import {
  get as get2,
  make as make3
} from "./index-y24mzzdg.js";
import {
  SqlError
} from "./index-p3fb6n1p.js";
import {
  SafeIntegers,
  SqlClient,
  defaultTransforms,
  layer,
  make as make4,
  makeCompilerSqlite
} from "./index-wezxaapt.js";
import {
  Scope,
  Service,
  acquireUseRelease,
  add,
  addFinalizer1 as addFinalizer,
  as1 as as,
  die1 as die,
  die2,
  effectServices,
  fail3 as fail,
  flatMap1 as flatMap,
  gen1 as gen,
  get,
  getCurrent,
  getUnsafe,
  identity,
  make2 as make,
  make8 as make2,
  map6 as map,
  minutes,
  provide1 as provide,
  scope1 as scope,
  succeed4 as succeed,
  sync1 as sync,
  tap,
  try_,
  uninterruptibleMask1 as uninterruptibleMask,
  unwrap2 as unwrap,
  void_1 as void_,
  withFiber1 as withFiber
} from "./index-w9j14fjm.js";
import"./index-sdksp5px.js";

// src/persistence/NodeSqliteClient.ts
import { DatabaseSync } from "node:sqlite";
var ATTR_DB_SYSTEM_NAME = "db.system.name";
var TypeId = "~local/sqlite-node/SqliteClient";
var SqliteClient = Service("t3/persistence/NodeSqliteClient");
var checkNodeSqliteCompat = () => {
  const parts = process.versions.node.split(".").map(Number);
  const major = parts[0] ?? 0;
  const minor = parts[1] ?? 0;
  const supported = major === 22 && minor >= 16 || major === 23 && minor >= 11 || major >= 24;
  if (!supported) {
    return die(`Node.js ${process.versions.node} is missing required node:sqlite APIs ` + `(StatementSync.columns). Upgrade to Node.js >=22.16, >=23.11, or >=24.`);
  }
  return void_;
};
var makeWithDatabase = (options, openDatabase) => gen(function* () {
  yield* checkNodeSqliteCompat();
  const compiler = makeCompilerSqlite(options.transformQueryNames);
  const transformRows = options.transformResultNames ? defaultTransforms(options.transformResultNames).array : undefined;
  const makeConnection = gen(function* () {
    const scope2 = yield* scope;
    const db = openDatabase();
    yield* addFinalizer(scope2, sync(() => db.close()));
    const statementReaderCache = new WeakMap;
    const hasRows = (statement) => {
      const cached = statementReaderCache.get(statement);
      if (cached !== undefined) {
        return cached;
      }
      const value = statement.columns().length > 0;
      statementReaderCache.set(statement, value);
      return value;
    };
    const prepareCache = yield* make3({
      capacity: options.prepareCacheSize ?? 200,
      timeToLive: options.prepareCacheTTL ?? minutes(10),
      lookup: (sql) => try_({
        try: () => db.prepare(sql),
        catch: (cause) => new SqlError({ cause, message: "Failed to prepare statement" })
      })
    });
    const runStatement = (statement, params, raw) => withFiber((fiber) => {
      statement.setReadBigInts(Boolean(get(fiber.services, SafeIntegers)));
      try {
        if (hasRows(statement)) {
          return succeed(statement.all(...params));
        }
        const result = statement.run(...params);
        return succeed(raw ? result : []);
      } catch (cause) {
        return fail(new SqlError({ cause, message: "Failed to execute statement" }));
      }
    });
    const run = (sql, params, raw = false) => flatMap(get2(prepareCache, sql), (s) => runStatement(s, params, raw));
    const runValues = (sql, params) => acquireUseRelease(get2(prepareCache, sql), (statement) => try_({
      try: () => {
        if (hasRows(statement)) {
          statement.setReturnArrays(true);
          return statement.all(...params);
        }
        statement.run(...params);
        return [];
      },
      catch: (cause) => new SqlError({ cause, message: "Failed to execute statement" })
    }), (statement) => sync(() => {
      if (hasRows(statement)) {
        statement.setReturnArrays(false);
      }
    }));
    return identity({
      execute(sql, params, rowTransform) {
        return rowTransform ? map(run(sql, params), rowTransform) : run(sql, params);
      },
      executeRaw(sql, params) {
        return run(sql, params, true);
      },
      executeValues(sql, params) {
        return runValues(sql, params);
      },
      executeUnprepared(sql, params, rowTransform) {
        const effect = runStatement(db.prepare(sql), params ?? [], false);
        return rowTransform ? map(effect, rowTransform) : effect;
      },
      executeStream(_sql, _params) {
        return die2("executeStream not implemented");
      }
    });
  });
  const semaphore = yield* make2(1);
  const connection = yield* makeConnection;
  const acquirer = semaphore.withPermits(1)(succeed(connection));
  const transactionAcquirer = uninterruptibleMask((restore) => {
    const fiber = getCurrent();
    const scope2 = getUnsafe(fiber.services, Scope);
    return as(tap(restore(semaphore.take(1)), () => addFinalizer(scope2, semaphore.release(1))), connection);
  });
  return yield* make4({
    acquirer,
    compiler,
    transactionAcquirer,
    spanAttributes: [
      ...options.spanAttributes ? Object.entries(options.spanAttributes) : [],
      [ATTR_DB_SYSTEM_NAME, "sqlite"]
    ],
    transformRows
  });
});
var make5 = (options) => makeWithDatabase(options, () => new DatabaseSync(options.filename, {
  readOnly: options.readonly ?? false,
  allowExtension: options.allowExtension ?? false
}));
var makeMemory = (config = {}) => makeWithDatabase({
  ...config,
  filename: ":memory:",
  readonly: false
}, () => {
  const database = new DatabaseSync(":memory:", {
    allowExtension: config.allowExtension ?? false
  });
  return database;
});
var layerConfig = (config) => effectServices(unwrap(config).asEffect().pipe(flatMap(make5), map((client) => make(SqliteClient, client).pipe(add(SqlClient, client))))).pipe(provide(layer));
var layer2 = (config) => effectServices(map(make5(config), (client) => make(SqliteClient, client).pipe(add(SqlClient, client)))).pipe(provide(layer));
var layerMemory = (config = {}) => effectServices(map(makeMemory(config), (client) => make(SqliteClient, client).pipe(add(SqlClient, client)))).pipe(provide(layer));
export {
  layerMemory,
  layerConfig,
  layer2 as layer,
  TypeId,
  SqliteClient
};
