// inlined https://github.com/griffiths-waite/kysely-oracledb with minor adjustments
/* v8 ignore start: internal Kysely driver integration, tested through the main Oracle driver */
import {
  CompiledQuery,
  createQueryId,
  DefaultQueryCompiler,
  DialectAdapterBase,
  IdentifierNode,
  RawNode,
} from 'kysely';
function parseSavepointCommand(command, savepointName) {
  return RawNode.createWithChildren([
    RawNode.createWithSql(`${command} `),
    IdentifierNode.create(savepointName), // ensures savepointName gets sanitized
  ]);
}
class OracleQueryCompiler extends DefaultQueryCompiler {
  getLeftIdentifierWrapper() {
    return '';
  }
  getRightIdentifierWrapper() {
    return '';
  }
  visitAlias(node) {
    this.visitNode(node.node);
    this.append(' ');
    this.visitNode(node.alias);
  }
}
class OracleAdapter extends DialectAdapterBase {
  #supportsReturning = false;
  #supportsTransactionalDdl = false;
  get supportsReturning() {
    return this.#supportsReturning;
  }
  get supportsTransactionalDdl() {
    return this.#supportsTransactionalDdl;
  }
  async acquireMigrationLock(_) {
    throw new Error('Not implemented');
  }
  async releaseMigrationLock(_) {
    throw new Error('Not implemented');
  }
}
const OUT_FORMAT_OBJECT = 4002;
let i = 0;
class OracleConnection {
  id = i++;
  #executeOptions;
  #connection;
  constructor(connection, executeOptions) {
    this.#executeOptions = executeOptions ?? {};
    this.#connection = connection;
  }
  async executeQuery(compiledQuery) {
    const { sql, bindParams } = this.formatQuery(compiledQuery);
    const result = await this.#connection.execute(sql, bindParams, {
      autoCommit: compiledQuery.autoCommit,
      outFormat: OUT_FORMAT_OBJECT,
      ...this.#executeOptions,
    });
    return {
      rows: result?.rows || [],
      numAffectedRows: result.rowsAffected ? BigInt(result.rowsAffected) : undefined,
      // @ts-ignore internal extension for Oracle returning clause
      outBinds: result.outBinds,
    };
  }
  formatQuery(query) {
    return {
      sql: query.sql.replace(/\$(\d+)/g, (_match, p1) => `:${parseInt(p1, 10) - 1}`), // Format bind params in Oracle syntax :0, :1, etc.
      bindParams: query.parameters,
    };
  }
  async *streamQuery(compiledQuery, _chunkSize) {
    const { sql, bindParams } = this.formatQuery(compiledQuery);
    const result = await this.#connection.execute(sql, bindParams, {
      resultSet: true,
      autoCommit: compiledQuery.autoCommit,
      outFormat: OUT_FORMAT_OBJECT,
      ...this.#executeOptions,
    });
    const rs = result.resultSet;
    try {
      let row;
      while ((row = await rs.getRow())) {
        yield { rows: [row] };
      }
    } finally {
      await rs.close();
    }
  }
  get connection() {
    return this.#connection;
  }
}
class OracleDriver {
  #config;
  #connections = new Set();
  constructor(config) {
    this.#config = config;
  }
  async init() {
    //
  }
  async acquireConnection() {
    const connection = new OracleConnection(await this.#config.pool.getConnection(), this.#config.executeOptions);
    this.#connections.add(connection);
    return connection;
  }
  async savepoint(connection, savepointName, compileQuery) {
    await connection.executeQuery(compileQuery(parseSavepointCommand('savepoint', savepointName), createQueryId()));
  }
  async rollbackToSavepoint(connection, savepointName, compileQuery) {
    await connection.executeQuery(
      compileQuery(parseSavepointCommand('rollback to savepoint', savepointName), createQueryId()),
    );
  }
  async releaseSavepoint(connection, savepointName, compileQuery) {
    //
  }
  async beginTransaction(connection, settings) {
    if (settings.accessMode) {
      await connection.executeQuery(CompiledQuery.raw(`set transaction ${settings.accessMode}`));
      return;
    }
    if (settings.isolationLevel) {
      await connection.executeQuery(CompiledQuery.raw(`set transaction isolation level ${settings.isolationLevel}`));
    }
  }
  async commitTransaction(connection) {
    await connection.connection.commit();
  }
  async rollbackTransaction(connection) {
    await connection.connection.rollback();
  }
  async releaseConnection(connection) {
    try {
      await connection.connection.close();
    } catch (err) {
      //
    } finally {
      this.#connections.delete(connection);
    }
  }
  async destroy() {
    for (const connection of this.#connections) {
      await this.releaseConnection(connection);
    }
    await this.#config.pool?.close(0);
  }
}
export class OracleDialect {
  #config;
  constructor(config) {
    this.#config = config;
  }
  createDriver() {
    return new OracleDriver(this.#config);
  }
  createAdapter() {
    return new OracleAdapter();
  }
  createIntrospector(db) {
    throw new Error('Not implemented');
  }
  createQueryCompiler() {
    return new OracleQueryCompiler();
  }
}
/* v8 ignore stop */
