import { SqliteQueryCompiler, SqliteAdapter, SqliteIntrospector, CompiledQuery, SelectQueryNode } from 'kysely';
import { EventEmitter } from 'node:events';

// src/index.ts
var BunWorkerDriver = class {
  config;
  worker;
  connection;
  connectionMutex = new ConnectionMutex();
  mitt;
  constructor(config) {
    this.config = config;
  }
  async init() {
    this.worker = this.config?.worker ?? new Worker(
      new URL("./worker", import.meta.url),
      { type: "module" }
    );
    this.mitt = new EventEmitter();
    this.worker.onmessage = ({ data: [type, data, err] }) => {
      this.mitt?.emit(type, data, err);
    };
    this.worker.postMessage([
      0,
      // init
      this.config?.url,
      this.config?.cacheStatment
    ]);
    await new Promise((resolve, reject) => {
      this.mitt?.once(0, (_, err) => err ? reject(err) : resolve());
    });
    this.connection = new BunWorkerConnection(this.worker, this.mitt);
    await this.config?.onCreateConnection?.(this.connection);
  }
  async acquireConnection() {
    await this.connectionMutex.lock();
    return this.connection;
  }
  async beginTransaction(connection) {
    await connection.executeQuery(CompiledQuery.raw("begin"));
  }
  async commitTransaction(connection) {
    await connection.executeQuery(CompiledQuery.raw("commit"));
  }
  async rollbackTransaction(connection) {
    await connection.executeQuery(CompiledQuery.raw("rollback"));
  }
  async releaseConnection() {
    this.connectionMutex.unlock();
  }
  async destroy() {
    if (!this.worker) {
      return;
    }
    this.worker.postMessage([2]);
    return new Promise((resolve, reject) => {
      this.mitt?.once(2, (_, err) => {
        if (err) {
          reject(err);
        } else {
          this.worker?.terminate();
          this.mitt?.removeAllListeners();
          this.mitt = void 0;
          resolve();
        }
      });
    });
  }
};
var ConnectionMutex = class {
  promise;
  resolve;
  async lock() {
    while (this.promise) {
      await this.promise;
    }
    this.promise = new Promise((resolve) => {
      this.resolve = resolve;
    });
  }
  unlock() {
    const resolve = this.resolve;
    this.promise = void 0;
    this.resolve = void 0;
    resolve?.();
  }
};
var BunWorkerConnection = class {
  constructor(worker, mitt) {
    this.worker = worker;
    this.mitt = mitt;
  }
  streamQuery() {
    throw new Error("Bun:sqlite-worker driver doesn't support streaming");
  }
  async executeQuery(compiledQuery) {
    const { parameters, sql, query } = compiledQuery;
    const isSelect = SelectQueryNode.is(query);
    this.worker.postMessage([1, isSelect, sql, parameters]);
    return new Promise((resolve, reject) => {
      if (!this.mitt) {
        reject(new Error("kysely instance has been destroyed"));
      }
      this.mitt.once(1, (data, err) => !err && data ? resolve(data) : reject(err));
    });
  }
};

// src/index.ts
var BunWorkerDialect = class {
  config;
  /**
   * dialect for `bun:sqlite`, run sql in worker
   */
  constructor(config) {
    this.config = config;
  }
  createDriver() {
    return new BunWorkerDriver(this.config);
  }
  createQueryCompiler() {
    return new SqliteQueryCompiler();
  }
  createAdapter() {
    return new SqliteAdapter();
  }
  createIntrospector(db) {
    return new SqliteIntrospector(db);
  }
};

export { BunWorkerDialect };
