content: package com.annimon.ownlang.modules.jdbc;
  
  import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
  import com.annimon.ownlang.exceptions.OwnLangRuntimeException;
  import com.annimon.ownlang.lib.*;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import static com.annimon.ownlang.modules.jdbc.JdbcConverters.*;
  
  class ConnectionValue extends MapValue {
  
      private final Connection connection;
  
      public ConnectionValue(Connection connection) {
          super(20);
          this.connection = connection;
          init();
      }
  
      private void init() {
          set("createStatement", new FunctionValue(this::createStatement));
          set("prepareStatement", new FunctionValue(this::prepareStatement));
          set("close", new FunctionValue(this::close));
  
          set("clearWarnings", voidFunction(connection::clearWarnings));
          set("commit", voidFunction(connection::commit));
          set("rollback", voidFunction(connection::rollback));
  
          set("setHoldability", voidIntFunction(connection::setHoldability));
          set("setTransactionIsolation", voidIntFunction(connection::setTransactionIsolation));
  
          set("getAutoCommit", booleanFunction(connection::getAutoCommit));
          set("isClosed", booleanFunction(connection::isClosed));
          set("isReadOnly", booleanFunction(connection::isReadOnly));
  
          set("getHoldability", intFunction(connection::getHoldability));
          set("getNetworkTimeout", intFunction(connection::getNetworkTimeout));
          set("getTransactionIsolation", intFunction(connection::getTransactionIsolation));
          set("getUpdateCount", intFunction(connection::getHoldability));
  
          set("getCatalog", stringFunction(connection::getCatalog));
          set("getSchema", stringFunction(connection::getSchema));
      }
  
      private Value createStatement(Value[] args) {
          try {
              return switch (args.length) {
                  case 0 -> new StatementValue(connection.createStatement());
                  case 2 -> new StatementValue(connection.createStatement(args[0].asInt(), args[1].asInt()));
                  case 3 -> new StatementValue(connection.createStatement(args[0].asInt(), args[1].asInt(), args[2].asInt()));
                  default -> throw new ArgumentsMismatchException("Wrong number of arguments");
              };
          } catch (SQLException sqlex) {
              throw new OwnLangRuntimeException(sqlex);
          }
      }
  
      private Value prepareStatement(Value[] args) {
          Arguments.checkRange(1, 4, args.length);
          try {
              final String sql = args[0].asString();
              return switch (args.length) {
                  case 1 -> new StatementValue(connection.prepareStatement(sql));
                  case 2 -> {
                      final PreparedStatement ps = columnData(args[1],
                              (int autogeneratedKeys) -> connection.prepareStatement(sql, autogeneratedKeys),
                              (int[] columnIndices) -> connection.prepareStatement(sql, columnIndices),
                              (String[] columnNames) -> connection.prepareStatement(sql, columnNames));
                      yield new StatementValue(ps);
                  }
                  case 3 -> new StatementValue(connection.prepareStatement(sql, args[1].asInt(), args[2].asInt()));
                  case 4 -> new StatementValue(connection.prepareStatement(sql, args[1].asInt(), args[2].asInt(), args[3].asInt()));
                  default -> throw new ArgumentsMismatchException("Wrong number of arguments");
              };
          } catch (SQLException sqlex) {
              throw new OwnLangRuntimeException(sqlex);
          }
      }
  
      private Value close(Value[] args) {
          try {
              if (connection != null) {
                  connection.close();
              }
          } catch (SQLException sqlex) {
              // skip
          }
          return NumberValue.ZERO;
      }
  }
  