@nextlyhq/adapter-sqlite 0.0.2-alpha.6 → 0.0.2-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +98 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.mjs +99 -29
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -35,11 +35,19 @@ var DEFAULT_CONFIG = {
|
|
|
35
35
|
function sanitizeSqliteValue(v) {
|
|
36
36
|
if (v === void 0) return null;
|
|
37
37
|
if (typeof v === "boolean") return v ? 1 : 0;
|
|
38
|
-
if (v instanceof Date) return v.
|
|
38
|
+
if (v instanceof Date) return Math.floor(v.getTime() / 1e3);
|
|
39
39
|
if (v !== null && typeof v === "object") return JSON.stringify(v);
|
|
40
40
|
return v;
|
|
41
41
|
}
|
|
42
42
|
var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
43
|
+
// getDrizzle memoization: drizzle v1's constructor builds a relational
|
|
44
|
+
// query builder per table in the relations config (~40 tables), and the
|
|
45
|
+
// service layer resolves an instance on every db access — construct once
|
|
46
|
+
// per relations object (identity-stable: the schema registry caches it
|
|
47
|
+
// and hands out a NEW object on invalidation, which naturally misses
|
|
48
|
+
// this cache and produces a fresh instance).
|
|
49
|
+
drizzleByRelations = /* @__PURE__ */ new WeakMap();
|
|
50
|
+
drizzleBare;
|
|
43
51
|
/**
|
|
44
52
|
* The database dialect - always 'sqlite' for this adapter.
|
|
45
53
|
*/
|
|
@@ -158,6 +166,8 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
158
166
|
// better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.
|
|
159
167
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
160
168
|
async disconnect() {
|
|
169
|
+
this.drizzleBare = void 0;
|
|
170
|
+
this.drizzleByRelations = /* @__PURE__ */ new WeakMap();
|
|
161
171
|
if (!this.db) {
|
|
162
172
|
return;
|
|
163
173
|
}
|
|
@@ -282,6 +292,7 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
282
292
|
throw error;
|
|
283
293
|
}
|
|
284
294
|
} catch (error) {
|
|
295
|
+
if (types.isApplicationError(error)) throw error;
|
|
285
296
|
throw this.classifyError(error);
|
|
286
297
|
}
|
|
287
298
|
}
|
|
@@ -360,7 +371,8 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
360
371
|
try {
|
|
361
372
|
const stmt = db.prepare(sql);
|
|
362
373
|
const rows = stmt.all(...params);
|
|
363
|
-
|
|
374
|
+
const tableObj = this.getTableObject(table);
|
|
375
|
+
return rows.map((r) => this.mapRowFromRawSql(tableObj, r));
|
|
364
376
|
} catch (error) {
|
|
365
377
|
throw this.handleQueryError(error, "insertMany", table);
|
|
366
378
|
}
|
|
@@ -390,13 +402,21 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
390
402
|
* @returns Drizzle ORM instance wrapping the better-sqlite3 connection
|
|
391
403
|
* @throws {Error} If called in browser or not connected
|
|
392
404
|
*/
|
|
393
|
-
|
|
394
|
-
getDrizzle(schema) {
|
|
405
|
+
getDrizzle(relations) {
|
|
395
406
|
if (typeof window !== "undefined") {
|
|
396
407
|
throw new Error("getDrizzle() is server-only");
|
|
397
408
|
}
|
|
398
409
|
const db = this.ensureDb();
|
|
399
|
-
|
|
410
|
+
if (!relations) {
|
|
411
|
+
this.drizzleBare ??= betterSqlite3.drizzle({ client: db });
|
|
412
|
+
return this.drizzleBare;
|
|
413
|
+
}
|
|
414
|
+
let cached = this.drizzleByRelations.get(relations);
|
|
415
|
+
if (!cached) {
|
|
416
|
+
cached = betterSqlite3.drizzle({ client: db, relations });
|
|
417
|
+
this.drizzleByRelations.set(relations, cached);
|
|
418
|
+
}
|
|
419
|
+
return cached;
|
|
400
420
|
}
|
|
401
421
|
/**
|
|
402
422
|
* Convert $1, $2 placeholders to ? for better-sqlite3.
|
|
@@ -411,7 +431,29 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
411
431
|
* Creates a TransactionContext for the given database connection.
|
|
412
432
|
*/
|
|
413
433
|
createTransactionContext(db) {
|
|
434
|
+
const buildTxExecutor = () => betterSqlite3.drizzle({ client: db });
|
|
435
|
+
let txExecutor;
|
|
436
|
+
const txDb = () => txExecutor ??= buildTxExecutor();
|
|
414
437
|
return {
|
|
438
|
+
// SQLite has no row-level locking and needs none here: `withTransaction`
|
|
439
|
+
// opens SQLite transactions with BEGIN IMMEDIATE, which takes the write
|
|
440
|
+
// lock up front and serializes writers for the whole transaction.
|
|
441
|
+
lockRow: () => Promise.resolve(),
|
|
442
|
+
// `run`, not `all`: better-sqlite3 throws on a statement that returns no
|
|
443
|
+
// rows, which is every statement this method exists to carry. The Drizzle
|
|
444
|
+
// instance is the transaction-bound one, so the statement runs inside this
|
|
445
|
+
// transaction.
|
|
446
|
+
//
|
|
447
|
+
// better-sqlite3 is synchronous, so this resolves an already-settled
|
|
448
|
+
// promise rather than being declared `async` over a body that never
|
|
449
|
+
// awaits.
|
|
450
|
+
runStatement: (statement) => {
|
|
451
|
+
txDb().run(statement);
|
|
452
|
+
return Promise.resolve();
|
|
453
|
+
},
|
|
454
|
+
// `all`, not `run`: this is the reading half, and better-sqlite3 returns
|
|
455
|
+
// rows only from `all`. Synchronous, so the promise is already settled.
|
|
456
|
+
queryStatement: (statement) => Promise.resolve(txDb().all(statement)),
|
|
415
457
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
416
458
|
execute: async (sql, params = []) => {
|
|
417
459
|
const convertedSql = this.convertPlaceholders(sql);
|
|
@@ -432,29 +474,45 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
432
474
|
];
|
|
433
475
|
}
|
|
434
476
|
},
|
|
477
|
+
// Keys only, unlike the PostgreSQL and MySQL raw paths, which also encode
|
|
478
|
+
// their date values. `sanitizeSqliteValue` below binds a `Date` as unix
|
|
479
|
+
// seconds, and an instant carries no zone -- so what SQLite stores does
|
|
480
|
+
// not depend on the server's timezone and there is nothing to correct.
|
|
435
481
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
436
482
|
insert: async (table, data, options) => {
|
|
437
|
-
const
|
|
438
|
-
|
|
483
|
+
const mapped = this.mapKeysToSqlColumns(
|
|
484
|
+
this.getTableObject(table),
|
|
485
|
+
data
|
|
486
|
+
);
|
|
487
|
+
const columns = Object.keys(mapped);
|
|
488
|
+
const values = Object.values(mapped).map(sanitizeSqliteValue);
|
|
439
489
|
const placeholders = values.map(() => "?").join(", ");
|
|
440
490
|
let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map((c) => this.escapeIdentifier(c)).join(", ")}) VALUES (${placeholders})`;
|
|
441
|
-
|
|
442
|
-
|
|
491
|
+
const ret = options?.returning;
|
|
492
|
+
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
493
|
+
if (!returningEmpty) {
|
|
494
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(this.getTableObject(table), ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
443
495
|
sql += ` RETURNING ${returning}`;
|
|
444
|
-
} else {
|
|
445
|
-
sql += " RETURNING *";
|
|
446
496
|
}
|
|
447
497
|
const stmt = db.prepare(sql);
|
|
498
|
+
if (returningEmpty) {
|
|
499
|
+
stmt.run(...values);
|
|
500
|
+
return void 0;
|
|
501
|
+
}
|
|
448
502
|
const rows = stmt.all(...values);
|
|
449
|
-
return rows[0];
|
|
503
|
+
return this.mapRowFromRawSql(this.getTableObject(table), rows[0]);
|
|
450
504
|
},
|
|
451
505
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
452
506
|
insertMany: async (table, data, options) => {
|
|
453
507
|
if (data.length === 0) return [];
|
|
454
|
-
const
|
|
508
|
+
const tableObj = this.getTableObject(table);
|
|
509
|
+
const mappedRecords = data.map(
|
|
510
|
+
(r) => this.mapKeysToSqlColumns(tableObj, r)
|
|
511
|
+
);
|
|
512
|
+
const columns = Object.keys(mappedRecords[0]);
|
|
455
513
|
const allValues = [];
|
|
456
514
|
const valuesClauses = [];
|
|
457
|
-
for (const record of
|
|
515
|
+
for (const record of mappedRecords) {
|
|
458
516
|
const placeholders = [];
|
|
459
517
|
for (const col of columns) {
|
|
460
518
|
allValues.push(sanitizeSqliteValue(record[col]));
|
|
@@ -463,31 +521,38 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
463
521
|
valuesClauses.push(`(${placeholders.join(", ")})`);
|
|
464
522
|
}
|
|
465
523
|
let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map((c) => this.escapeIdentifier(c)).join(", ")}) VALUES ${valuesClauses.join(", ")}`;
|
|
466
|
-
|
|
467
|
-
|
|
524
|
+
const ret = options?.returning;
|
|
525
|
+
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
526
|
+
if (!returningEmpty) {
|
|
527
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(this.getTableObject(table), ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
468
528
|
sql += ` RETURNING ${returning}`;
|
|
469
|
-
} else {
|
|
470
|
-
sql += " RETURNING *";
|
|
471
529
|
}
|
|
472
530
|
const stmt = db.prepare(sql);
|
|
473
|
-
|
|
531
|
+
if (returningEmpty) {
|
|
532
|
+
stmt.run(...allValues);
|
|
533
|
+
return [];
|
|
534
|
+
}
|
|
535
|
+
return stmt.all(...allValues).map(
|
|
536
|
+
(r) => this.mapRowFromRawSql(tableObj, r)
|
|
537
|
+
);
|
|
474
538
|
},
|
|
475
|
-
// TransactionContext CRUD methods delegate to the adapter's CRUD
|
|
476
|
-
//
|
|
539
|
+
// TransactionContext CRUD methods delegate to the adapter's Drizzle CRUD
|
|
540
|
+
// but pass the transaction-bound executor so they run inside this
|
|
541
|
+
// transaction rather than on the pool.
|
|
477
542
|
select: async (table, options) => {
|
|
478
|
-
return this.select(table, options);
|
|
543
|
+
return this.select(table, options, txDb());
|
|
479
544
|
},
|
|
480
545
|
selectOne: async (table, options) => {
|
|
481
|
-
return this.selectOne(table, options);
|
|
546
|
+
return this.selectOne(table, options, txDb());
|
|
482
547
|
},
|
|
483
548
|
update: async (table, data, where, options) => {
|
|
484
|
-
return this.update(table, data, where, options);
|
|
549
|
+
return this.update(table, data, where, options, txDb());
|
|
485
550
|
},
|
|
486
|
-
delete: async (table, where,
|
|
487
|
-
return this.delete(table, where);
|
|
551
|
+
delete: async (table, where, options) => {
|
|
552
|
+
return this.delete(table, where, options, txDb());
|
|
488
553
|
},
|
|
489
554
|
upsert: async (table, data, options) => {
|
|
490
|
-
return this.upsert(table, data, options);
|
|
555
|
+
return this.upsert(table, data, options, txDb());
|
|
491
556
|
},
|
|
492
557
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
493
558
|
savepoint: async (name) => {
|
|
@@ -500,7 +565,12 @@ var SqliteAdapter = class extends adapterDrizzle.DrizzleAdapter {
|
|
|
500
565
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
501
566
|
releaseSavepoint: async (name) => {
|
|
502
567
|
db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);
|
|
503
|
-
}
|
|
568
|
+
},
|
|
569
|
+
// Expose the transaction-bound Drizzle instance so callers can run
|
|
570
|
+
// Drizzle sql templates inside this transaction (junction-table writes
|
|
571
|
+
// need this to be atomic with the entry write). Reuses the memoized
|
|
572
|
+
// txDb() built for the delegated CRUD methods.
|
|
573
|
+
getDrizzle: () => txDb()
|
|
504
574
|
};
|
|
505
575
|
}
|
|
506
576
|
/**
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["DrizzleAdapter","checkDialectVersion","createDatabaseError","drizzle","isDatabaseError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @nextlyhq/adapter-sqlite\n *\n * SQLite database adapter for Nextly.\n * Extends DrizzleAdapter from @nextlyhq/adapter-drizzle to provide SQLite-specific functionality.\n *\n * @remarks\n * This adapter uses the better-sqlite3 package for database connectivity and provides:\n * - Synchronous API wrapped for async interface compatibility\n * - Full transaction support with savepoints (via better-sqlite3's native transaction handling)\n * - CRUD operations with RETURNING clause support (SQLite 3.35+)\n * - WAL mode for better concurrent read performance\n * - In-memory and file-based database support\n *\n * @example\n * ```typescript\n * import { createSqliteAdapter } from '@nextlyhq/adapter-sqlite';\n *\n * const adapter = createSqliteAdapter({\n * url: 'file:./data/app.db',\n * });\n *\n * await adapter.connect();\n *\n * // Query data\n * const users = await adapter.select('users', {\n * where: { and: [{ column: 'status', op: '=', value: 'active' }] },\n * limit: 10,\n * });\n *\n * await adapter.disconnect();\n * ```\n *\n * @packageDocumentation\n */\n\nimport { DrizzleAdapter } from \"@nextlyhq/adapter-drizzle\";\n// F17: connect-time DB version check shared across all adapters.\nimport {\n createDatabaseError,\n isDatabaseError,\n type SqliteAdapterConfig,\n type DatabaseCapabilities,\n type PoolStats,\n type TransactionContext,\n type TransactionOptions,\n type SqlParam,\n type WhereClause,\n type WhereCondition,\n type WhereOperator,\n type SelectOptions,\n type InsertOptions,\n type UpdateOptions,\n type DeleteOptions,\n type UpsertOptions,\n type OrderBySpec,\n type JoinSpec,\n type DatabaseError,\n type DatabaseErrorKind,\n type BaseAdapterConfig,\n type AdapterLogger,\n} from \"@nextlyhq/adapter-drizzle/types\";\nimport { checkDialectVersion } from \"@nextlyhq/adapter-drizzle/version-check\";\nimport type Database from \"better-sqlite3\";\nimport {\n drizzle,\n type BetterSQLite3Database,\n} from \"drizzle-orm/better-sqlite3\";\n\n// Re-export types for convenience\nexport type {\n SqliteAdapterConfig,\n DatabaseCapabilities,\n PoolStats,\n TransactionContext,\n TransactionOptions,\n SqlParam,\n WhereClause,\n WhereCondition,\n WhereOperator,\n SelectOptions,\n InsertOptions,\n UpdateOptions,\n DeleteOptions,\n UpsertOptions,\n OrderBySpec,\n JoinSpec,\n DatabaseError,\n DatabaseErrorKind,\n BaseAdapterConfig,\n AdapterLogger,\n};\n\n/**\n * Package version\n */\nexport const VERSION = \"0.1.0\";\n\n/**\n * SQLite error codes mapping to DatabaseErrorKind.\n *\n * @see https://sqlite.org/rescode.html\n */\nconst SQLITE_ERROR_CODES: Record<string, DatabaseErrorKind> = {\n // Constraint violations\n SQLITE_CONSTRAINT: \"constraint\",\n SQLITE_CONSTRAINT_UNIQUE: \"unique_violation\",\n SQLITE_CONSTRAINT_PRIMARYKEY: \"unique_violation\",\n SQLITE_CONSTRAINT_FOREIGNKEY: \"foreign_key_violation\",\n SQLITE_CONSTRAINT_NOTNULL: \"not_null_violation\",\n SQLITE_CONSTRAINT_CHECK: \"check_violation\",\n\n // Busy/locked errors\n SQLITE_BUSY: \"timeout\",\n SQLITE_LOCKED: \"timeout\",\n\n // Connection errors\n SQLITE_CANTOPEN: \"connection\",\n SQLITE_NOTADB: \"connection\",\n SQLITE_CORRUPT: \"connection\",\n\n // Query errors\n SQLITE_ERROR: \"query\",\n SQLITE_MISUSE: \"query\",\n SQLITE_RANGE: \"query\",\n};\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG = {\n busyTimeout: 5000,\n wal: true,\n foreignKeys: true,\n};\n\n/**\n * Converts a JavaScript value to a type that better-sqlite3 can bind.\n * better-sqlite3 only accepts: number, string, bigint, Buffer, null.\n */\nfunction sanitizeSqliteValue(v: unknown): unknown {\n if (v === undefined) return null;\n if (typeof v === \"boolean\") return v ? 1 : 0;\n if (v instanceof Date) return v.toISOString();\n if (v !== null && typeof v === \"object\") return JSON.stringify(v);\n return v;\n}\n\n/**\n * SQLite database adapter for Nextly.\n *\n * Extends the base DrizzleAdapter to provide SQLite-specific functionality\n * using the better-sqlite3 package.\n *\n * @remarks\n * SQLite has some differences from PostgreSQL:\n * - Synchronous API (wrapped for async compatibility)\n * - No connection pooling (single file/connection)\n * - RETURNING clause supported (SQLite 3.35+)\n * - Savepoints supported via nested transactions\n * - No native ILIKE (uses LOWER() LIKE workaround)\n * - JSON support (not JSONB)\n * - No array types\n *\n * @example\n * ```typescript\n * const adapter = new SqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport class SqliteAdapter extends DrizzleAdapter {\n /**\n * The database dialect - always 'sqlite' for this adapter.\n */\n readonly dialect = \"sqlite\" as const;\n\n /**\n * Adapter configuration.\n */\n protected readonly config: SqliteAdapterConfig;\n\n /**\n * better-sqlite3 Database instance.\n */\n private db: Database.Database | null = null;\n\n /**\n * Connection state flag.\n */\n private connected = false;\n\n /**\n * Serialization queue for concurrent `transaction()` calls.\n *\n * better-sqlite3 is synchronous, single-connection, and rejects nested\n * `BEGIN` with \"cannot start a transaction within a transaction\".\n * When two `await adapter.transaction(...)` calls overlap (e.g. a bulk\n * mutation calling `Promise.allSettled` with N per-row updates), the\n * second one tries to BEGIN while the first is still open and the\n * driver throws.\n *\n * Postgres/MySQL avoid this by allocating a fresh client/connection\n * per transaction from a pool — there is no equivalent for\n * better-sqlite3, so we serialize at the JS layer instead. Every\n * `transaction()` invocation chains onto this promise; only one\n * BEGIN→COMMIT/ROLLBACK section runs at any moment, preserving\n * write-isolation semantics that callers expect from a transactional\n * adapter.\n *\n * Performance impact is the natural floor: SQLite already serializes\n * writers at the file-lock level, so the queue removes failed-call\n * surface area without changing the achievable concurrency.\n */\n private transactionQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Creates a new SQLite adapter instance.\n *\n * @param config - Adapter configuration\n */\n constructor(config: SqliteAdapterConfig) {\n super();\n this.config = config;\n }\n\n /**\n * Connect to the SQLite database.\n *\n * @remarks\n * This method initializes the database connection. For SQLite, this\n * opens the database file or creates an in-memory database.\n * Also configures WAL mode and foreign keys based on config.\n *\n * @throws {DatabaseError} If connection fails\n */\n async connect(): Promise<void> {\n if (this.connected && this.db) {\n return;\n }\n\n try {\n // Dynamic import of better-sqlite3 to avoid bundling issues\n const BetterSqlite3 = await import(\"better-sqlite3\");\n const Database = BetterSqlite3.default;\n\n // Determine database path\n let dbPath: string;\n if (this.config.memory) {\n dbPath = \":memory:\";\n } else if (this.config.url) {\n // Strip file: prefix if present\n dbPath = this.config.url.replace(/^file:/, \"\");\n } else {\n dbPath = \":memory:\";\n }\n\n // Ensure the parent directory exists for file-backed databases.\n // better-sqlite3 fails with a confusing \"Cannot open database\n // because the directory does not exist\" error if it doesn't, and\n // a fresh clone with `DATABASE_URL=file:./data/app.db` reliably\n // hits this on first run. Create the dir lazily so DATABASE_URL\n // can point anywhere without a separate setup step.\n if (dbPath !== \":memory:\" && !this.config.readonly) {\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n const dir = path.dirname(path.resolve(dbPath));\n await fs.promises.mkdir(dir, { recursive: true });\n }\n\n // Create database instance\n this.db = new Database(dbPath, {\n readonly: this.config.readonly ?? false,\n timeout: this.config.busyTimeout ?? DEFAULT_CONFIG.busyTimeout,\n });\n\n // Configure WAL mode for better concurrency (unless in-memory or readonly)\n if (\n (this.config.wal ?? DEFAULT_CONFIG.wal) &&\n dbPath !== \":memory:\" &&\n !this.config.readonly\n ) {\n this.db.pragma(\"journal_mode = WAL\");\n }\n\n // Enable foreign keys\n if (this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys) {\n this.db.pragma(\"foreign_keys = ON\");\n }\n\n // F17: check SQLite version. Hard-fails on SQLite <3.38. SQLite has\n // no recognized cloud variants we warn on, so onWarning is omitted.\n // Note: better-sqlite3's bundled SQLite is set by the package\n // version; users on this package's pinned better-sqlite3 (3.45+)\n // will always pass.\n await checkDialectVersion(this.db, \"sqlite\");\n\n this.connected = true;\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection established\", {\n url: dbPath === \":memory:\" ? \"in-memory\" : dbPath,\n wal: this.config.wal ?? DEFAULT_CONFIG.wal,\n foreignKeys: this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys,\n });\n }\n } catch (error) {\n // Clean up on failure\n if (this.db) {\n try {\n this.db.close();\n } catch {\n // Ignore close errors during error handling\n }\n this.db = null;\n }\n throw this.classifyError(error);\n }\n }\n\n /**\n * Disconnect from the SQLite database.\n *\n * @remarks\n * This method closes the database connection and releases resources.\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async disconnect(): Promise<void> {\n if (!this.db) {\n return;\n }\n\n try {\n this.db.close();\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection closed\");\n }\n } finally {\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected to the database.\n */\n isConnected(): boolean {\n return this.connected && this.db !== null;\n }\n\n /**\n * Get connection pool statistics.\n *\n * @remarks\n * SQLite doesn't use connection pooling, so this returns null.\n * The database is single-file with a single connection.\n */\n getPoolStats(): PoolStats | null {\n // SQLite doesn't have connection pooling\n return null;\n }\n\n /**\n * Execute a raw SQL query.\n *\n * @param sql - SQL query string with $1, $2 placeholders (converted to ? for SQLite)\n * @param params - Query parameters\n * @returns Query results\n *\n * @throws {DatabaseError} If query execution fails\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async executeQuery<T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Convert $1, $2 placeholders to ? for better-sqlite3\n const convertedSql = this.convertPlaceholders(sql);\n\n // Determine if this is a SELECT query or a modifying query\n const trimmedSql = convertedSql.trim().toUpperCase();\n\n // Check for PRAGMA query statements (e.g., \"PRAGMA foreign_keys\").\n // Setting PRAGMAs (e.g., \"PRAGMA foreign_keys = OFF\") don't return data.\n const isPragmaQuery =\n trimmedSql.startsWith(\"PRAGMA\") && !trimmedSql.includes(\"=\");\n\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") ||\n isPragmaQuery ||\n trimmedSql.startsWith(\"WITH\");\n const hasReturning = trimmedSql.includes(\"RETURNING\");\n\n let result: T[];\n\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect || hasReturning) {\n // Use .all() for SELECT queries or queries with RETURNING\n const stmt = db.prepare(convertedSql);\n result = stmt.all(...sanitizedParams) as T[];\n } else {\n // Use .run() for INSERT/UPDATE/DELETE/PRAGMA settings without RETURNING\n const stmt = db.prepare(convertedSql);\n const runResult = stmt.run(...sanitizedParams);\n // Return info about the operation\n result = [\n {\n changes: runResult.changes,\n lastInsertRowid: runResult.lastInsertRowid,\n } as unknown as T,\n ];\n }\n\n // Log query if logger configured\n if (this.config.logger?.query) {\n const durationMs = Date.now() - startTime;\n this.config.logger.query(convertedSql, params, durationMs);\n }\n\n return result;\n } catch (error) {\n throw this.classifyError(error, sql);\n }\n }\n\n /**\n * Execute work within a transaction.\n *\n * @param work - Function containing transactional operations\n * @param options - Transaction options (isolation level not fully supported in SQLite)\n * @returns Result of the work function\n *\n * @remarks\n * Uses better-sqlite3's native transaction handling which:\n * - Automatically commits on success\n * - Automatically rolls back on error\n * - Converts nested transactions to savepoints\n *\n * Note: SQLite uses DEFERRED, IMMEDIATE, or EXCLUSIVE transaction modes\n * rather than isolation levels. This adapter uses IMMEDIATE by default.\n */\n async transaction<T>(\n work: (tx: TransactionContext) => Promise<T>,\n _options?: TransactionOptions\n ): Promise<T> {\n // Why: serialize concurrent transaction() invocations to dodge\n // better-sqlite3's \"cannot start a transaction within a transaction\"\n // error when two awaits overlap on the same connection. See the\n // `transactionQueue` field comment for the full rationale. The queue\n // chains every call onto a tail promise so only one BEGIN → COMMIT\n // section runs at a time; the next call's BEGIN waits for the\n // previous COMMIT/ROLLBACK to finish.\n //\n // Failure isolation: the queue's tail promise must not reject (a\n // rejection would poison every subsequent transaction with the same\n // rejected value). We attach a no-op `.catch` so the chain stays\n // resolved while the actual error propagates back to the original\n // caller through the inner promise.\n const run = async (): Promise<T> => this.runTransaction(work);\n const next = this.transactionQueue.then(run, run);\n this.transactionQueue = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Inner transaction body. Kept private so callers always go through\n * the serialized `transaction()` queue above and the BEGIN/COMMIT\n * pair is never invoked outside of it.\n */\n private async runTransaction<T>(\n work: (tx: TransactionContext) => Promise<T>\n ): Promise<T> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Create transaction context\n const ctx = this.createTransactionContext(db);\n\n // Since better-sqlite3's db.transaction() doesn't support async functions,\n // we manually manage the transaction with BEGIN/COMMIT/ROLLBACK\n db.exec(\"BEGIN IMMEDIATE\");\n\n try {\n const result = await work(ctx);\n db.exec(\"COMMIT\");\n\n // Log success\n if (this.config.logger?.debug) {\n const durationMs = Date.now() - startTime;\n this.config.logger.debug(\"Transaction committed\", {\n durationMs,\n });\n }\n\n return result;\n } catch (error) {\n // Rollback on error\n try {\n db.exec(\"ROLLBACK\");\n } catch {\n // Ignore rollback errors - transaction may already be aborted\n }\n throw error;\n }\n } catch (error) {\n throw this.classifyError(error);\n }\n }\n\n /**\n * Get SQLite database capabilities.\n *\n * @remarks\n * SQLite capabilities:\n * - JSON support (not JSONB)\n * - No arrays\n * - No native ILIKE\n * - RETURNING clause (3.35+)\n * - Savepoints supported\n * - ON CONFLICT supported\n */\n getCapabilities(): DatabaseCapabilities {\n return {\n dialect: \"sqlite\",\n supportsJsonb: false, // SQLite uses JSON, not JSONB\n supportsJson: true,\n supportsArrays: false, // SQLite doesn't support array types\n supportsGeneratedColumns: true, // SQLite 3.31+\n supportsFts: true, // SQLite FTS5\n supportsIlike: false, // No native ILIKE, use LOWER() LIKE\n supportsReturning: true, // SQLite 3.35+\n supportsSavepoints: true, // SQLite supports savepoints\n supportsOnConflict: true, // ON CONFLICT clause\n maxParamsPerQuery: 999, // SQLite SQLITE_MAX_VARIABLE_NUMBER default\n maxIdentifierLength: 128, // SQLite doesn't have a strict limit\n };\n }\n\n /**\n * Override insertMany for bulk insert optimization.\n *\n * @remarks\n * Uses a single multi-row INSERT statement for better performance.\n */\n override async insertMany<T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> {\n if (data.length === 0) {\n return [];\n }\n\n const db = this.ensureDb();\n\n // For single record, use parent implementation\n if (data.length === 1) {\n const result = await this.insert<T>(table, data[0], options);\n return [result];\n }\n\n // Build multi-row INSERT\n const columns = Object.keys(data[0]);\n const params: SqlParam[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n params.push(sanitizeSqliteValue(record[col]) as SqlParam);\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n const columnList = columns\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columnList}) VALUES ${valuesClauses.join(\", \")}`;\n\n // Add RETURNING clause\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning.map(col => this.escapeIdentifier(col)).join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n try {\n const stmt = db.prepare(sql);\n const rows = stmt.all(...(params as unknown[])) as T[];\n return rows;\n } catch (error) {\n throw this.handleQueryError(error, \"insertMany\", table);\n }\n }\n\n // ============================================================\n // Protected Helper Methods\n // ============================================================\n\n /**\n * Ensures database is connected and returns it.\n *\n * @throws {DatabaseError} If not connected\n */\n private ensureDb(): Database.Database {\n if (!this.db) {\n throw createDatabaseError({\n kind: \"connection\",\n message: \"SqliteAdapter is not connected. Call connect() first.\",\n });\n }\n return this.db;\n }\n\n /**\n * Return the typed Drizzle instance for SQLite.\n * Guarded for server-only usage and requires an active connection.\n *\n * @param schema - Optional schema for relational queries (db.query.*)\n * @returns Drizzle ORM instance wrapping the better-sqlite3 connection\n * @throws {Error} If called in browser or not connected\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getDrizzle<T = BetterSQLite3Database<any>>(\n schema?: Record<string, unknown>\n ): T {\n if (typeof window !== \"undefined\") {\n throw new Error(\"getDrizzle() is server-only\");\n }\n const db = this.ensureDb();\n return (schema ? drizzle(db, { schema }) : drizzle(db)) as T;\n }\n\n /**\n * Convert $1, $2 placeholders to ? for better-sqlite3.\n *\n * @param sql - SQL with PostgreSQL-style placeholders\n * @returns SQL with ? placeholders\n */\n private convertPlaceholders(sql: string): string {\n // Replace $1, $2, etc. with ?\n return sql.replace(/\\$\\d+/g, \"?\");\n }\n\n /**\n * Creates a TransactionContext for the given database connection.\n */\n private createTransactionContext(db: Database.Database): TransactionContext {\n // better-sqlite3 is synchronous; the methods below are async to satisfy\n // the TransactionContext contract shared with truly-async dialect adapters.\n return {\n // eslint-disable-next-line @typescript-eslint/require-await\n execute: async <T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> => {\n const convertedSql = this.convertPlaceholders(sql);\n const trimmedSql = convertedSql.trim().toUpperCase();\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") || trimmedSql.includes(\"RETURNING\");\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect) {\n const stmt = db.prepare(convertedSql);\n return stmt.all(...sanitizedParams) as T[];\n } else {\n const stmt = db.prepare(convertedSql);\n const result = stmt.run(...sanitizedParams);\n return [\n {\n changes: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n } as unknown as T,\n ];\n }\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options?: InsertOptions\n ): Promise<T> => {\n const columns = Object.keys(data);\n const values = Object.values(data).map(sanitizeSqliteValue);\n const placeholders = values.map(() => \"?\").join(\", \");\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES (${placeholders})`;\n\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n const stmt = db.prepare(sql);\n const rows = stmt.all(...values) as T[];\n return rows[0];\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insertMany: async <T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> => {\n if (data.length === 0) return [];\n\n const columns = Object.keys(data[0]);\n const allValues: unknown[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n allValues.push(sanitizeSqliteValue(record[col]));\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES ${valuesClauses.join(\", \")}`;\n\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n const stmt = db.prepare(sql);\n return stmt.all(...allValues) as T[];\n },\n\n // TransactionContext CRUD methods delegate to the adapter's CRUD\n // which uses Drizzle query API via the TableResolver.\n select: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T[]> => {\n return this.select<T>(table, options);\n },\n\n selectOne: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T | null> => {\n return this.selectOne<T>(table, options);\n },\n\n update: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n where: WhereClause,\n options?: UpdateOptions\n ): Promise<T[]> => {\n return this.update<T>(table, data, where, options);\n },\n\n delete: async (\n table: string,\n where: WhereClause,\n _options?: DeleteOptions\n ): Promise<number> => {\n return this.delete(table, where);\n },\n\n upsert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options: UpsertOptions\n ): Promise<T> => {\n return this.upsert<T>(table, data, options);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n savepoint: async (name: string): Promise<void> => {\n db.exec(`SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n rollbackToSavepoint: async (name: string): Promise<void> => {\n db.exec(`ROLLBACK TO SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n releaseSavepoint: async (name: string): Promise<void> => {\n db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n };\n }\n\n /**\n * Classifies a SQLite error into a DatabaseError.\n *\n * @param error - Original error from better-sqlite3\n * @param sql - SQL statement that caused the error (optional)\n * @returns DatabaseError with proper classification\n */\n private classifyError(error: unknown, sql?: string): DatabaseError {\n // Why short-circuit on existing DatabaseError: F17's\n // UnsupportedDialectVersionError is already a typed DatabaseError with\n // kind: \"unsupported_version\" plus detectedVersion/requiredVersion\n // fields. Re-wrapping it here would erase those fields.\n if (isDatabaseError(error)) return error;\n\n const sqliteError = error as {\n code?: string;\n message?: string;\n name?: string;\n };\n\n // Determine error kind from SQLite error code\n let kind: DatabaseErrorKind = \"unknown\";\n\n if (sqliteError.code) {\n kind = SQLITE_ERROR_CODES[sqliteError.code] || \"unknown\";\n } else if (sqliteError.message) {\n // Try to extract error type from message\n const msg = sqliteError.message.toUpperCase();\n if (msg.includes(\"UNIQUE CONSTRAINT\")) {\n kind = \"unique_violation\";\n } else if (msg.includes(\"FOREIGN KEY CONSTRAINT\")) {\n kind = \"foreign_key_violation\";\n } else if (msg.includes(\"NOT NULL CONSTRAINT\")) {\n kind = \"not_null_violation\";\n } else if (msg.includes(\"CHECK CONSTRAINT\")) {\n kind = \"check_violation\";\n } else if (msg.includes(\"BUSY\") || msg.includes(\"LOCKED\")) {\n kind = \"timeout\";\n } else if (\n msg.includes(\"SQLITE_CANTOPEN\") ||\n msg.includes(\"UNABLE TO OPEN\")\n ) {\n kind = \"connection\";\n }\n }\n\n // Build error message\n let message = sqliteError.message ?? String(error);\n if (sql && kind === \"query\") {\n message = `Query failed: ${message}`;\n }\n\n return createDatabaseError({\n kind,\n message,\n code: sqliteError.code,\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Override handleQueryError to use SQLite-specific classification.\n */\n protected override handleQueryError(\n error: unknown,\n operation: string,\n table: string\n ): DatabaseError {\n const dbError = this.classifyError(error);\n\n // Add operation context if not already present\n if (!dbError.message.includes(operation)) {\n dbError.message = `${operation} operation failed on table '${table}': ${dbError.message}`;\n }\n\n if (!dbError.table) {\n dbError.table = table;\n }\n\n return dbError;\n }\n}\n\n/**\n * Create a SQLite database adapter.\n *\n * @param config - SQLite adapter configuration\n * @returns A new SqliteAdapter instance\n *\n * @example\n * ```typescript\n * // Simple usage with file path\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * // In-memory database\n * const memAdapter = createSqliteAdapter({\n * memory: true,\n * });\n *\n * // Full configuration\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * wal: true,\n * foreignKeys: true,\n * busyTimeout: 5000,\n * logger: {\n * query: (sql, params, duration) => console.log(`Query: ${sql}`),\n * },\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport function createSqliteAdapter(\n config: SqliteAdapterConfig\n): SqliteAdapter {\n return new SqliteAdapter(config);\n}\n\n/**\n * Type guard to check if a value is a SqliteAdapter.\n *\n * @param value - Value to check\n * @returns True if value is a SqliteAdapter instance\n *\n * @example\n * ```typescript\n * if (isSqliteAdapter(adapter)) {\n * // TypeScript knows adapter is SqliteAdapter\n * console.log('Using SQLite');\n * }\n * ```\n */\nexport function isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return value instanceof SqliteAdapter;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["DrizzleAdapter","checkDialectVersion","isApplicationError","createDatabaseError","drizzle","isDatabaseError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @nextlyhq/adapter-sqlite\n *\n * SQLite database adapter for Nextly.\n * Extends DrizzleAdapter from @nextlyhq/adapter-drizzle to provide SQLite-specific functionality.\n *\n * @remarks\n * This adapter uses the better-sqlite3 package for database connectivity and provides:\n * - Synchronous API wrapped for async interface compatibility\n * - Full transaction support with savepoints (via better-sqlite3's native transaction handling)\n * - CRUD operations with RETURNING clause support (SQLite 3.35+)\n * - WAL mode for better concurrent read performance\n * - In-memory and file-based database support\n *\n * @example\n * ```typescript\n * import { createSqliteAdapter } from '@nextlyhq/adapter-sqlite';\n *\n * const adapter = createSqliteAdapter({\n * url: 'file:./data/app.db',\n * });\n *\n * await adapter.connect();\n *\n * // Query data\n * const users = await adapter.select('users', {\n * where: { and: [{ column: 'status', op: '=', value: 'active' }] },\n * limit: 10,\n * });\n *\n * await adapter.disconnect();\n * ```\n *\n * @packageDocumentation\n */\n\nimport { DrizzleAdapter } from \"@nextlyhq/adapter-drizzle\";\n// F17: connect-time DB version check shared across all adapters.\nimport {\n createDatabaseError,\n isDatabaseError,\n type SqliteAdapterConfig,\n type DatabaseCapabilities,\n type PoolStats,\n type TransactionContext,\n type TransactionOptions,\n type SqlParam,\n type WhereClause,\n type WhereCondition,\n type WhereOperator,\n type SelectOptions,\n type InsertOptions,\n type UpdateOptions,\n type DeleteOptions,\n type UpsertOptions,\n type OrderBySpec,\n type JoinSpec,\n type DatabaseError,\n type DatabaseErrorKind,\n type BaseAdapterConfig,\n type AdapterLogger,\n isApplicationError,\n} from \"@nextlyhq/adapter-drizzle/types\";\nimport { checkDialectVersion } from \"@nextlyhq/adapter-drizzle/version-check\";\nimport type Database from \"better-sqlite3\";\nimport type { AnyRelations, SQL } from \"drizzle-orm\";\nimport {\n drizzle,\n type BetterSQLite3Database,\n} from \"drizzle-orm/better-sqlite3\";\n\n// Re-export types for convenience\nexport type {\n SqliteAdapterConfig,\n DatabaseCapabilities,\n PoolStats,\n TransactionContext,\n TransactionOptions,\n SqlParam,\n WhereClause,\n WhereCondition,\n WhereOperator,\n SelectOptions,\n InsertOptions,\n UpdateOptions,\n DeleteOptions,\n UpsertOptions,\n OrderBySpec,\n JoinSpec,\n DatabaseError,\n DatabaseErrorKind,\n BaseAdapterConfig,\n AdapterLogger,\n};\n\n/**\n * Package version\n */\nexport const VERSION = \"0.1.0\";\n\n/**\n * SQLite error codes mapping to DatabaseErrorKind.\n *\n * @see https://sqlite.org/rescode.html\n */\nconst SQLITE_ERROR_CODES: Record<string, DatabaseErrorKind> = {\n // Constraint violations\n SQLITE_CONSTRAINT: \"constraint\",\n SQLITE_CONSTRAINT_UNIQUE: \"unique_violation\",\n SQLITE_CONSTRAINT_PRIMARYKEY: \"unique_violation\",\n SQLITE_CONSTRAINT_FOREIGNKEY: \"foreign_key_violation\",\n SQLITE_CONSTRAINT_NOTNULL: \"not_null_violation\",\n SQLITE_CONSTRAINT_CHECK: \"check_violation\",\n\n // Busy/locked errors\n SQLITE_BUSY: \"timeout\",\n SQLITE_LOCKED: \"timeout\",\n\n // Connection errors\n SQLITE_CANTOPEN: \"connection\",\n SQLITE_NOTADB: \"connection\",\n SQLITE_CORRUPT: \"connection\",\n\n // Query errors\n SQLITE_ERROR: \"query\",\n SQLITE_MISUSE: \"query\",\n SQLITE_RANGE: \"query\",\n};\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG = {\n busyTimeout: 5000,\n wal: true,\n foreignKeys: true,\n};\n\n/**\n * Converts a JavaScript value to a type that better-sqlite3 can bind.\n * better-sqlite3 only accepts: number, string, bigint, Buffer, null.\n *\n * These conversions have to match what the schema declares, because the rows\n * they write are read back through it. Every column here that takes a `Date`\n * is `integer({ mode: \"timestamp\" })` — the system columns and user date\n * fields in `runtime-schema-generator.ts`, and the core tables, whose date\n * columns are all INTEGER. So a date is bound as unix seconds, which is what\n * that mode reads.\n */\nfunction sanitizeSqliteValue(v: unknown): unknown {\n if (v === undefined) return null;\n if (typeof v === \"boolean\") return v ? 1 : 0;\n // Seconds, not an ISO string. SQLite stores whatever it is given regardless\n // of the declared type, so a string lands in the column without complaint\n // and only fails on the way back out, where the timestamp decoder reads it\n // as a number and yields an Invalid Date.\n if (v instanceof Date) return Math.floor(v.getTime() / 1000);\n if (v !== null && typeof v === \"object\") return JSON.stringify(v);\n return v;\n}\n\n/**\n * SQLite database adapter for Nextly.\n *\n * Extends the base DrizzleAdapter to provide SQLite-specific functionality\n * using the better-sqlite3 package.\n *\n * @remarks\n * SQLite has some differences from PostgreSQL:\n * - Synchronous API (wrapped for async compatibility)\n * - No connection pooling (single file/connection)\n * - RETURNING clause supported (SQLite 3.35+)\n * - Savepoints supported via nested transactions\n * - No native ILIKE (uses LOWER() LIKE workaround)\n * - JSON support (not JSONB)\n * - No array types\n *\n * @example\n * ```typescript\n * const adapter = new SqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport class SqliteAdapter extends DrizzleAdapter {\n // getDrizzle memoization: drizzle v1's constructor builds a relational\n // query builder per table in the relations config (~40 tables), and the\n // service layer resolves an instance on every db access — construct once\n // per relations object (identity-stable: the schema registry caches it\n // and hands out a NEW object on invalidation, which naturally misses\n // this cache and produces a fresh instance).\n private drizzleByRelations = new WeakMap<AnyRelations, unknown>();\n private drizzleBare: unknown;\n\n /**\n * The database dialect - always 'sqlite' for this adapter.\n */\n readonly dialect = \"sqlite\" as const;\n\n /**\n * Adapter configuration.\n */\n protected readonly config: SqliteAdapterConfig;\n\n /**\n * better-sqlite3 Database instance.\n */\n private db: Database.Database | null = null;\n\n /**\n * Connection state flag.\n */\n private connected = false;\n\n /**\n * Serialization queue for concurrent `transaction()` calls.\n *\n * better-sqlite3 is synchronous, single-connection, and rejects nested\n * `BEGIN` with \"cannot start a transaction within a transaction\".\n * When two `await adapter.transaction(...)` calls overlap (e.g. a bulk\n * mutation calling `Promise.allSettled` with N per-row updates), the\n * second one tries to BEGIN while the first is still open and the\n * driver throws.\n *\n * Postgres/MySQL avoid this by allocating a fresh client/connection\n * per transaction from a pool — there is no equivalent for\n * better-sqlite3, so we serialize at the JS layer instead. Every\n * `transaction()` invocation chains onto this promise; only one\n * BEGIN→COMMIT/ROLLBACK section runs at any moment, preserving\n * write-isolation semantics that callers expect from a transactional\n * adapter.\n *\n * Performance impact is the natural floor: SQLite already serializes\n * writers at the file-lock level, so the queue removes failed-call\n * surface area without changing the achievable concurrency.\n */\n private transactionQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Creates a new SQLite adapter instance.\n *\n * @param config - Adapter configuration\n */\n constructor(config: SqliteAdapterConfig) {\n super();\n this.config = config;\n }\n\n /**\n * Connect to the SQLite database.\n *\n * @remarks\n * This method initializes the database connection. For SQLite, this\n * opens the database file or creates an in-memory database.\n * Also configures WAL mode and foreign keys based on config.\n *\n * @throws {DatabaseError} If connection fails\n */\n async connect(): Promise<void> {\n if (this.connected && this.db) {\n return;\n }\n\n try {\n // Dynamic import of better-sqlite3 to avoid bundling issues\n const BetterSqlite3 = await import(\"better-sqlite3\");\n const Database = BetterSqlite3.default;\n\n // Determine database path\n let dbPath: string;\n if (this.config.memory) {\n dbPath = \":memory:\";\n } else if (this.config.url) {\n // Strip file: prefix if present\n dbPath = this.config.url.replace(/^file:/, \"\");\n } else {\n dbPath = \":memory:\";\n }\n\n // Ensure the parent directory exists for file-backed databases.\n // better-sqlite3 fails with a confusing \"Cannot open database\n // because the directory does not exist\" error if it doesn't, and\n // a fresh clone with `DATABASE_URL=file:./data/app.db` reliably\n // hits this on first run. Create the dir lazily so DATABASE_URL\n // can point anywhere without a separate setup step.\n if (dbPath !== \":memory:\" && !this.config.readonly) {\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n const dir = path.dirname(path.resolve(dbPath));\n await fs.promises.mkdir(dir, { recursive: true });\n }\n\n // Create database instance\n this.db = new Database(dbPath, {\n readonly: this.config.readonly ?? false,\n timeout: this.config.busyTimeout ?? DEFAULT_CONFIG.busyTimeout,\n });\n\n // Configure WAL mode for better concurrency (unless in-memory or readonly)\n if (\n (this.config.wal ?? DEFAULT_CONFIG.wal) &&\n dbPath !== \":memory:\" &&\n !this.config.readonly\n ) {\n this.db.pragma(\"journal_mode = WAL\");\n }\n\n // Enable foreign keys\n if (this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys) {\n this.db.pragma(\"foreign_keys = ON\");\n }\n\n // F17: check SQLite version. Hard-fails on SQLite <3.38. SQLite has\n // no recognized cloud variants we warn on, so onWarning is omitted.\n // Note: better-sqlite3's bundled SQLite is set by the package\n // version; users on this package's pinned better-sqlite3 (3.45+)\n // will always pass.\n await checkDialectVersion(this.db, \"sqlite\");\n\n this.connected = true;\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection established\", {\n url: dbPath === \":memory:\" ? \"in-memory\" : dbPath,\n wal: this.config.wal ?? DEFAULT_CONFIG.wal,\n foreignKeys: this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys,\n });\n }\n } catch (error) {\n // Clean up on failure\n if (this.db) {\n try {\n this.db.close();\n } catch {\n // Ignore close errors during error handling\n }\n this.db = null;\n }\n throw this.classifyError(error);\n }\n }\n\n /**\n * Disconnect from the SQLite database.\n *\n * @remarks\n * This method closes the database connection and releases resources.\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async disconnect(): Promise<void> {\n // Drop memoized drizzle instances — they wrap the connection being\n // closed and must not survive a reconnect.\n this.drizzleBare = undefined;\n this.drizzleByRelations = new WeakMap();\n if (!this.db) {\n return;\n }\n\n try {\n this.db.close();\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection closed\");\n }\n } finally {\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected to the database.\n */\n isConnected(): boolean {\n return this.connected && this.db !== null;\n }\n\n /**\n * Get connection pool statistics.\n *\n * @remarks\n * SQLite doesn't use connection pooling, so this returns null.\n * The database is single-file with a single connection.\n */\n getPoolStats(): PoolStats | null {\n // SQLite doesn't have connection pooling\n return null;\n }\n\n /**\n * Execute a raw SQL query.\n *\n * @param sql - SQL query string with $1, $2 placeholders (converted to ? for SQLite)\n * @param params - Query parameters\n * @returns Query results\n *\n * @throws {DatabaseError} If query execution fails\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async executeQuery<T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Convert $1, $2 placeholders to ? for better-sqlite3\n const convertedSql = this.convertPlaceholders(sql);\n\n // Determine if this is a SELECT query or a modifying query\n const trimmedSql = convertedSql.trim().toUpperCase();\n\n // Check for PRAGMA query statements (e.g., \"PRAGMA foreign_keys\").\n // Setting PRAGMAs (e.g., \"PRAGMA foreign_keys = OFF\") don't return data.\n const isPragmaQuery =\n trimmedSql.startsWith(\"PRAGMA\") && !trimmedSql.includes(\"=\");\n\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") ||\n isPragmaQuery ||\n trimmedSql.startsWith(\"WITH\");\n const hasReturning = trimmedSql.includes(\"RETURNING\");\n\n let result: T[];\n\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect || hasReturning) {\n // Use .all() for SELECT queries or queries with RETURNING\n const stmt = db.prepare(convertedSql);\n result = stmt.all(...sanitizedParams) as T[];\n } else {\n // Use .run() for INSERT/UPDATE/DELETE/PRAGMA settings without RETURNING\n const stmt = db.prepare(convertedSql);\n const runResult = stmt.run(...sanitizedParams);\n // Return info about the operation\n result = [\n {\n changes: runResult.changes,\n lastInsertRowid: runResult.lastInsertRowid,\n } as unknown as T,\n ];\n }\n\n // Log query if logger configured\n if (this.config.logger?.query) {\n const durationMs = Date.now() - startTime;\n this.config.logger.query(convertedSql, params, durationMs);\n }\n\n return result;\n } catch (error) {\n throw this.classifyError(error, sql);\n }\n }\n\n /**\n * Execute work within a transaction.\n *\n * @param work - Function containing transactional operations\n * @param options - Transaction options (isolation level not fully supported in SQLite)\n * @returns Result of the work function\n *\n * @remarks\n * Uses better-sqlite3's native transaction handling which:\n * - Automatically commits on success\n * - Automatically rolls back on error\n * - Converts nested transactions to savepoints\n *\n * Note: SQLite uses DEFERRED, IMMEDIATE, or EXCLUSIVE transaction modes\n * rather than isolation levels. This adapter uses IMMEDIATE by default.\n */\n async transaction<T>(\n work: (tx: TransactionContext) => Promise<T>,\n _options?: TransactionOptions\n ): Promise<T> {\n // Why: serialize concurrent transaction() invocations to dodge\n // better-sqlite3's \"cannot start a transaction within a transaction\"\n // error when two awaits overlap on the same connection. See the\n // `transactionQueue` field comment for the full rationale. The queue\n // chains every call onto a tail promise so only one BEGIN → COMMIT\n // section runs at a time; the next call's BEGIN waits for the\n // previous COMMIT/ROLLBACK to finish.\n //\n // Failure isolation: the queue's tail promise must not reject (a\n // rejection would poison every subsequent transaction with the same\n // rejected value). We attach a no-op `.catch` so the chain stays\n // resolved while the actual error propagates back to the original\n // caller through the inner promise.\n const run = async (): Promise<T> => this.runTransaction(work);\n const next = this.transactionQueue.then(run, run);\n this.transactionQueue = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Inner transaction body. Kept private so callers always go through\n * the serialized `transaction()` queue above and the BEGIN/COMMIT\n * pair is never invoked outside of it.\n */\n private async runTransaction<T>(\n work: (tx: TransactionContext) => Promise<T>\n ): Promise<T> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Create transaction context\n const ctx = this.createTransactionContext(db);\n\n // Since better-sqlite3's db.transaction() doesn't support async functions,\n // we manually manage the transaction with BEGIN/COMMIT/ROLLBACK\n db.exec(\"BEGIN IMMEDIATE\");\n\n try {\n const result = await work(ctx);\n db.exec(\"COMMIT\");\n\n // Log success\n if (this.config.logger?.debug) {\n const durationMs = Date.now() - startTime;\n this.config.logger.debug(\"Transaction committed\", {\n durationMs,\n });\n }\n\n return result;\n } catch (error) {\n // Rollback on error\n try {\n db.exec(\"ROLLBACK\");\n } catch {\n // Ignore rollback errors - transaction may already be aborted\n }\n throw error;\n }\n } catch (error) {\n // Work inside a transaction may throw to roll the write back — a refused\n // value, a denied permission — and that is the application's verdict, not\n // the driver's failure. Classifying it would replace its code and payload\n // with a generic database error, so a caller that asked for a refusal is\n // handed an unexplained failure and the per-field detail never arrives.\n if (isApplicationError(error)) throw error;\n throw this.classifyError(error);\n }\n }\n\n /**\n * Get SQLite database capabilities.\n *\n * @remarks\n * SQLite capabilities:\n * - JSON support (not JSONB)\n * - No arrays\n * - No native ILIKE\n * - RETURNING clause (3.35+)\n * - Savepoints supported\n * - ON CONFLICT supported\n */\n getCapabilities(): DatabaseCapabilities {\n return {\n dialect: \"sqlite\",\n supportsJsonb: false, // SQLite uses JSON, not JSONB\n supportsJson: true,\n supportsArrays: false, // SQLite doesn't support array types\n supportsGeneratedColumns: true, // SQLite 3.31+\n supportsFts: true, // SQLite FTS5\n supportsIlike: false, // No native ILIKE, use LOWER() LIKE\n supportsReturning: true, // SQLite 3.35+\n supportsSavepoints: true, // SQLite supports savepoints\n supportsOnConflict: true, // ON CONFLICT clause\n maxParamsPerQuery: 999, // SQLite SQLITE_MAX_VARIABLE_NUMBER default\n maxIdentifierLength: 128, // SQLite doesn't have a strict limit\n };\n }\n\n /**\n * Override insertMany for bulk insert optimization.\n *\n * @remarks\n * Uses a single multi-row INSERT statement for better performance.\n */\n override async insertMany<T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> {\n if (data.length === 0) {\n return [];\n }\n\n const db = this.ensureDb();\n\n // For single record, use parent implementation\n if (data.length === 1) {\n const result = await this.insert<T>(table, data[0], options);\n return [result];\n }\n\n // Build multi-row INSERT\n const columns = Object.keys(data[0]);\n const params: SqlParam[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n params.push(sanitizeSqliteValue(record[col]) as SqlParam);\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n const columnList = columns\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columnList}) VALUES ${valuesClauses.join(\", \")}`;\n\n // Add RETURNING clause\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning.map(col => this.escapeIdentifier(col)).join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n try {\n const stmt = db.prepare(sql);\n const rows = stmt.all(...(params as unknown[])) as T[];\n // SQLite stores a timestamp as an integer and hands it back as one. The\n // Drizzle read paths decode it through the column definition, so without\n // this a bulk insert answers with numbers where a read answers `Date`.\n const tableObj = this.getTableObject(table);\n return rows.map(r => this.mapRowFromRawSql(tableObj, r));\n } catch (error) {\n throw this.handleQueryError(error, \"insertMany\", table);\n }\n }\n\n // ============================================================\n // Protected Helper Methods\n // ============================================================\n\n /**\n * Ensures database is connected and returns it.\n *\n * @throws {DatabaseError} If not connected\n */\n private ensureDb(): Database.Database {\n if (!this.db) {\n throw createDatabaseError({\n kind: \"connection\",\n message: \"SqliteAdapter is not connected. Call connect() first.\",\n });\n }\n return this.db;\n }\n\n /**\n * Return the typed Drizzle instance for SQLite.\n * Guarded for server-only usage and requires an active connection.\n *\n * @param schema - Optional schema for relational queries (db.query.*)\n * @returns Drizzle ORM instance wrapping the better-sqlite3 connection\n * @throws {Error} If called in browser or not connected\n */\n getDrizzle<T = BetterSQLite3Database<AnyRelations>>(\n relations?: AnyRelations\n ): T {\n if (typeof window !== \"undefined\") {\n throw new Error(\"getDrizzle() is server-only\");\n }\n const db = this.ensureDb();\n // drizzle v1 removed the positional (client, config) form — positional\n // calls silently open a NEW :memory: database. Object form only.\n if (!relations) {\n this.drizzleBare ??= drizzle({ client: db });\n return this.drizzleBare as T;\n }\n let cached = this.drizzleByRelations.get(relations);\n if (!cached) {\n cached = drizzle({ client: db, relations });\n this.drizzleByRelations.set(relations, cached);\n }\n return cached as T;\n }\n\n /**\n * Convert $1, $2 placeholders to ? for better-sqlite3.\n *\n * @param sql - SQL with PostgreSQL-style placeholders\n * @returns SQL with ? placeholders\n */\n private convertPlaceholders(sql: string): string {\n // Replace $1, $2, etc. with ?\n return sql.replace(/\\$\\d+/g, \"?\");\n }\n\n /**\n * Creates a TransactionContext for the given database connection.\n */\n private createTransactionContext(db: Database.Database): TransactionContext {\n // better-sqlite3 is synchronous; the methods below are async to satisfy\n // the TransactionContext contract shared with truly-async dialect adapters.\n // Bind a Drizzle instance to the transaction's connection so the delegated\n // CRUD methods run inside it. better-sqlite3 is single-connection, so this\n // is the same connection getDrizzle() would use, but binding explicitly\n // keeps the three adapters consistent and correct if that ever changes.\n // Built lazily and memoized: transactions that use only raw execute/insert\n // never construct it.\n const buildTxExecutor = () => drizzle({ client: db });\n let txExecutor: ReturnType<typeof buildTxExecutor> | undefined;\n const txDb = () => (txExecutor ??= buildTxExecutor());\n return {\n // SQLite has no row-level locking and needs none here: `withTransaction`\n // opens SQLite transactions with BEGIN IMMEDIATE, which takes the write\n // lock up front and serializes writers for the whole transaction.\n lockRow: (): Promise<void> => Promise.resolve(),\n\n // `run`, not `all`: better-sqlite3 throws on a statement that returns no\n // rows, which is every statement this method exists to carry. The Drizzle\n // instance is the transaction-bound one, so the statement runs inside this\n // transaction.\n //\n // better-sqlite3 is synchronous, so this resolves an already-settled\n // promise rather than being declared `async` over a body that never\n // awaits.\n runStatement: (statement: SQL): Promise<void> => {\n txDb().run(statement);\n return Promise.resolve();\n },\n\n // `all`, not `run`: this is the reading half, and better-sqlite3 returns\n // rows only from `all`. Synchronous, so the promise is already settled.\n queryStatement: <T = Record<string, unknown>>(\n statement: SQL\n ): Promise<T[]> => Promise.resolve(txDb().all(statement)),\n\n // eslint-disable-next-line @typescript-eslint/require-await\n execute: async <T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> => {\n const convertedSql = this.convertPlaceholders(sql);\n const trimmedSql = convertedSql.trim().toUpperCase();\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") || trimmedSql.includes(\"RETURNING\");\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect) {\n const stmt = db.prepare(convertedSql);\n return stmt.all(...sanitizedParams) as T[];\n } else {\n const stmt = db.prepare(convertedSql);\n const result = stmt.run(...sanitizedParams);\n return [\n {\n changes: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n } as unknown as T,\n ];\n }\n },\n\n // Keys only, unlike the PostgreSQL and MySQL raw paths, which also encode\n // their date values. `sanitizeSqliteValue` below binds a `Date` as unix\n // seconds, and an instant carries no zone -- so what SQLite stores does\n // not depend on the server's timezone and there is nothing to correct.\n // eslint-disable-next-line @typescript-eslint/require-await\n insert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options?: InsertOptions\n ): Promise<T> => {\n const mapped = this.mapKeysToSqlColumns(\n this.getTableObject(table),\n data\n );\n const columns = Object.keys(mapped);\n const values = Object.values(mapped).map(sanitizeSqliteValue);\n const placeholders = values.map(() => \"?\").join(\", \");\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES (${placeholders})`;\n\n const ret = options?.returning;\n const returningEmpty = Array.isArray(ret) && ret.length === 0;\n if (!returningEmpty) {\n const returning =\n !ret || ret === \"*\"\n ? \"*\"\n : this.mapColumnNamesToSql(this.getTableObject(table), ret)\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n }\n\n const stmt = db.prepare(sql);\n if (returningEmpty) {\n // No RETURNING clause: better-sqlite3's .all() rejects a statement\n // that returns no columns, so run it and return nothing.\n stmt.run(...values);\n return undefined as T;\n }\n const rows = stmt.all(...values) as T[];\n // Return JS property-named keys AND Drizzle-decoded date values, so a\n // write inside a transaction answers with the same representation a\n // read of the same row gives.\n return this.mapRowFromRawSql(this.getTableObject(table), rows[0]);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insertMany: async <T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> => {\n if (data.length === 0) return [];\n\n const tableObj = this.getTableObject(table);\n const mappedRecords = data.map(r =>\n this.mapKeysToSqlColumns(tableObj, r)\n );\n const columns = Object.keys(mappedRecords[0]);\n const allValues: unknown[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of mappedRecords) {\n const placeholders: string[] = [];\n for (const col of columns) {\n allValues.push(sanitizeSqliteValue(record[col]));\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES ${valuesClauses.join(\", \")}`;\n\n const ret = options?.returning;\n const returningEmpty = Array.isArray(ret) && ret.length === 0;\n if (!returningEmpty) {\n const returning =\n !ret || ret === \"*\"\n ? \"*\"\n : this.mapColumnNamesToSql(this.getTableObject(table), ret)\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n }\n\n const stmt = db.prepare(sql);\n if (returningEmpty) {\n stmt.run(...allValues);\n return [];\n }\n return (stmt.all(...allValues) as T[]).map(r =>\n this.mapRowFromRawSql(tableObj, r)\n );\n },\n\n // TransactionContext CRUD methods delegate to the adapter's Drizzle CRUD\n // but pass the transaction-bound executor so they run inside this\n // transaction rather than on the pool.\n select: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T[]> => {\n return this.select<T>(table, options, txDb());\n },\n\n selectOne: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T | null> => {\n return this.selectOne<T>(table, options, txDb());\n },\n\n update: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n where: WhereClause,\n options?: UpdateOptions\n ): Promise<T[]> => {\n return this.update<T>(table, data, where, options, txDb());\n },\n\n delete: async (\n table: string,\n where: WhereClause,\n options?: DeleteOptions\n ): Promise<number> => {\n return this.delete(table, where, options, txDb());\n },\n\n upsert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options: UpsertOptions\n ): Promise<T> => {\n return this.upsert<T>(table, data, options, txDb());\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n savepoint: async (name: string): Promise<void> => {\n db.exec(`SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n rollbackToSavepoint: async (name: string): Promise<void> => {\n db.exec(`ROLLBACK TO SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n releaseSavepoint: async (name: string): Promise<void> => {\n db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // Expose the transaction-bound Drizzle instance so callers can run\n // Drizzle sql templates inside this transaction (junction-table writes\n // need this to be atomic with the entry write). Reuses the memoized\n // txDb() built for the delegated CRUD methods.\n getDrizzle: <T = unknown>(): T => txDb() as T,\n };\n }\n\n /**\n * Classifies a SQLite error into a DatabaseError.\n *\n * @param error - Original error from better-sqlite3\n * @param sql - SQL statement that caused the error (optional)\n * @returns DatabaseError with proper classification\n */\n private classifyError(error: unknown, sql?: string): DatabaseError {\n // Why short-circuit on existing DatabaseError: F17's\n // UnsupportedDialectVersionError is already a typed DatabaseError with\n // kind: \"unsupported_version\" plus detectedVersion/requiredVersion\n // fields. Re-wrapping it here would erase those fields.\n if (isDatabaseError(error)) return error;\n\n const sqliteError = error as {\n code?: string;\n message?: string;\n name?: string;\n };\n\n // Determine error kind from SQLite error code\n let kind: DatabaseErrorKind = \"unknown\";\n\n if (sqliteError.code) {\n kind = SQLITE_ERROR_CODES[sqliteError.code] || \"unknown\";\n } else if (sqliteError.message) {\n // Try to extract error type from message\n const msg = sqliteError.message.toUpperCase();\n if (msg.includes(\"UNIQUE CONSTRAINT\")) {\n kind = \"unique_violation\";\n } else if (msg.includes(\"FOREIGN KEY CONSTRAINT\")) {\n kind = \"foreign_key_violation\";\n } else if (msg.includes(\"NOT NULL CONSTRAINT\")) {\n kind = \"not_null_violation\";\n } else if (msg.includes(\"CHECK CONSTRAINT\")) {\n kind = \"check_violation\";\n } else if (msg.includes(\"BUSY\") || msg.includes(\"LOCKED\")) {\n kind = \"timeout\";\n } else if (\n msg.includes(\"SQLITE_CANTOPEN\") ||\n msg.includes(\"UNABLE TO OPEN\")\n ) {\n kind = \"connection\";\n }\n }\n\n // Build error message\n let message = sqliteError.message ?? String(error);\n if (sql && kind === \"query\") {\n message = `Query failed: ${message}`;\n }\n\n return createDatabaseError({\n kind,\n message,\n code: sqliteError.code,\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Override handleQueryError to use SQLite-specific classification.\n */\n protected override handleQueryError(\n error: unknown,\n operation: string,\n table: string\n ): DatabaseError {\n const dbError = this.classifyError(error);\n\n // Add operation context if not already present\n if (!dbError.message.includes(operation)) {\n dbError.message = `${operation} operation failed on table '${table}': ${dbError.message}`;\n }\n\n if (!dbError.table) {\n dbError.table = table;\n }\n\n return dbError;\n }\n}\n\n/**\n * Create a SQLite database adapter.\n *\n * @param config - SQLite adapter configuration\n * @returns A new SqliteAdapter instance\n *\n * @example\n * ```typescript\n * // Simple usage with file path\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * // In-memory database\n * const memAdapter = createSqliteAdapter({\n * memory: true,\n * });\n *\n * // Full configuration\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * wal: true,\n * foreignKeys: true,\n * busyTimeout: 5000,\n * logger: {\n * query: (sql, params, duration) => console.log(`Query: ${sql}`),\n * },\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport function createSqliteAdapter(\n config: SqliteAdapterConfig\n): SqliteAdapter {\n return new SqliteAdapter(config);\n}\n\n/**\n * Type guard to check if a value is a SqliteAdapter.\n *\n * @param value - Value to check\n * @returns True if value is a SqliteAdapter instance\n *\n * @example\n * ```typescript\n * if (isSqliteAdapter(adapter)) {\n * // TypeScript knows adapter is SqliteAdapter\n * console.log('Using SQLite');\n * }\n * ```\n */\nexport function isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return value instanceof SqliteAdapter;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DrizzleAdapter } from '@nextlyhq/adapter-drizzle';
|
|
2
2
|
import { SqliteAdapterConfig, PoolStats, SqlParam, TransactionContext, TransactionOptions, DatabaseCapabilities, InsertOptions, DatabaseError } from '@nextlyhq/adapter-drizzle/types';
|
|
3
3
|
export { AdapterLogger, BaseAdapterConfig, DatabaseCapabilities, DatabaseError, DatabaseErrorKind, DeleteOptions, InsertOptions, JoinSpec, OrderBySpec, PoolStats, SelectOptions, SqlParam, SqliteAdapterConfig, TransactionContext, TransactionOptions, UpdateOptions, UpsertOptions, WhereClause, WhereCondition, WhereOperator } from '@nextlyhq/adapter-drizzle/types';
|
|
4
|
+
import { AnyRelations } from 'drizzle-orm';
|
|
4
5
|
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -69,6 +70,8 @@ declare const VERSION = "0.1.0";
|
|
|
69
70
|
* ```
|
|
70
71
|
*/
|
|
71
72
|
declare class SqliteAdapter extends DrizzleAdapter {
|
|
73
|
+
private drizzleByRelations;
|
|
74
|
+
private drizzleBare;
|
|
72
75
|
/**
|
|
73
76
|
* The database dialect - always 'sqlite' for this adapter.
|
|
74
77
|
*/
|
|
@@ -211,7 +214,7 @@ declare class SqliteAdapter extends DrizzleAdapter {
|
|
|
211
214
|
* @returns Drizzle ORM instance wrapping the better-sqlite3 connection
|
|
212
215
|
* @throws {Error} If called in browser or not connected
|
|
213
216
|
*/
|
|
214
|
-
getDrizzle<T = BetterSQLite3Database<
|
|
217
|
+
getDrizzle<T = BetterSQLite3Database<AnyRelations>>(relations?: AnyRelations): T;
|
|
215
218
|
/**
|
|
216
219
|
* Convert $1, $2 placeholders to ? for better-sqlite3.
|
|
217
220
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DrizzleAdapter } from '@nextlyhq/adapter-drizzle';
|
|
2
2
|
import { SqliteAdapterConfig, PoolStats, SqlParam, TransactionContext, TransactionOptions, DatabaseCapabilities, InsertOptions, DatabaseError } from '@nextlyhq/adapter-drizzle/types';
|
|
3
3
|
export { AdapterLogger, BaseAdapterConfig, DatabaseCapabilities, DatabaseError, DatabaseErrorKind, DeleteOptions, InsertOptions, JoinSpec, OrderBySpec, PoolStats, SelectOptions, SqlParam, SqliteAdapterConfig, TransactionContext, TransactionOptions, UpdateOptions, UpsertOptions, WhereClause, WhereCondition, WhereOperator } from '@nextlyhq/adapter-drizzle/types';
|
|
4
|
+
import { AnyRelations } from 'drizzle-orm';
|
|
4
5
|
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -69,6 +70,8 @@ declare const VERSION = "0.1.0";
|
|
|
69
70
|
* ```
|
|
70
71
|
*/
|
|
71
72
|
declare class SqliteAdapter extends DrizzleAdapter {
|
|
73
|
+
private drizzleByRelations;
|
|
74
|
+
private drizzleBare;
|
|
72
75
|
/**
|
|
73
76
|
* The database dialect - always 'sqlite' for this adapter.
|
|
74
77
|
*/
|
|
@@ -211,7 +214,7 @@ declare class SqliteAdapter extends DrizzleAdapter {
|
|
|
211
214
|
* @returns Drizzle ORM instance wrapping the better-sqlite3 connection
|
|
212
215
|
* @throws {Error} If called in browser or not connected
|
|
213
216
|
*/
|
|
214
|
-
getDrizzle<T = BetterSQLite3Database<
|
|
217
|
+
getDrizzle<T = BetterSQLite3Database<AnyRelations>>(relations?: AnyRelations): T;
|
|
215
218
|
/**
|
|
216
219
|
* Convert $1, $2 placeholders to ? for better-sqlite3.
|
|
217
220
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DrizzleAdapter } from '@nextlyhq/adapter-drizzle';
|
|
2
|
-
import { createDatabaseError, isDatabaseError } from '@nextlyhq/adapter-drizzle/types';
|
|
2
|
+
import { isApplicationError, createDatabaseError, isDatabaseError } from '@nextlyhq/adapter-drizzle/types';
|
|
3
3
|
import { checkDialectVersion } from '@nextlyhq/adapter-drizzle/version-check';
|
|
4
4
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
5
5
|
|
|
@@ -33,11 +33,19 @@ var DEFAULT_CONFIG = {
|
|
|
33
33
|
function sanitizeSqliteValue(v) {
|
|
34
34
|
if (v === void 0) return null;
|
|
35
35
|
if (typeof v === "boolean") return v ? 1 : 0;
|
|
36
|
-
if (v instanceof Date) return v.
|
|
36
|
+
if (v instanceof Date) return Math.floor(v.getTime() / 1e3);
|
|
37
37
|
if (v !== null && typeof v === "object") return JSON.stringify(v);
|
|
38
38
|
return v;
|
|
39
39
|
}
|
|
40
40
|
var SqliteAdapter = class extends DrizzleAdapter {
|
|
41
|
+
// getDrizzle memoization: drizzle v1's constructor builds a relational
|
|
42
|
+
// query builder per table in the relations config (~40 tables), and the
|
|
43
|
+
// service layer resolves an instance on every db access — construct once
|
|
44
|
+
// per relations object (identity-stable: the schema registry caches it
|
|
45
|
+
// and hands out a NEW object on invalidation, which naturally misses
|
|
46
|
+
// this cache and produces a fresh instance).
|
|
47
|
+
drizzleByRelations = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
drizzleBare;
|
|
41
49
|
/**
|
|
42
50
|
* The database dialect - always 'sqlite' for this adapter.
|
|
43
51
|
*/
|
|
@@ -156,6 +164,8 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
156
164
|
// better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.
|
|
157
165
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
158
166
|
async disconnect() {
|
|
167
|
+
this.drizzleBare = void 0;
|
|
168
|
+
this.drizzleByRelations = /* @__PURE__ */ new WeakMap();
|
|
159
169
|
if (!this.db) {
|
|
160
170
|
return;
|
|
161
171
|
}
|
|
@@ -280,6 +290,7 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
280
290
|
throw error;
|
|
281
291
|
}
|
|
282
292
|
} catch (error) {
|
|
293
|
+
if (isApplicationError(error)) throw error;
|
|
283
294
|
throw this.classifyError(error);
|
|
284
295
|
}
|
|
285
296
|
}
|
|
@@ -358,7 +369,8 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
358
369
|
try {
|
|
359
370
|
const stmt = db.prepare(sql);
|
|
360
371
|
const rows = stmt.all(...params);
|
|
361
|
-
|
|
372
|
+
const tableObj = this.getTableObject(table);
|
|
373
|
+
return rows.map((r) => this.mapRowFromRawSql(tableObj, r));
|
|
362
374
|
} catch (error) {
|
|
363
375
|
throw this.handleQueryError(error, "insertMany", table);
|
|
364
376
|
}
|
|
@@ -388,13 +400,21 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
388
400
|
* @returns Drizzle ORM instance wrapping the better-sqlite3 connection
|
|
389
401
|
* @throws {Error} If called in browser or not connected
|
|
390
402
|
*/
|
|
391
|
-
|
|
392
|
-
getDrizzle(schema) {
|
|
403
|
+
getDrizzle(relations) {
|
|
393
404
|
if (typeof window !== "undefined") {
|
|
394
405
|
throw new Error("getDrizzle() is server-only");
|
|
395
406
|
}
|
|
396
407
|
const db = this.ensureDb();
|
|
397
|
-
|
|
408
|
+
if (!relations) {
|
|
409
|
+
this.drizzleBare ??= drizzle({ client: db });
|
|
410
|
+
return this.drizzleBare;
|
|
411
|
+
}
|
|
412
|
+
let cached = this.drizzleByRelations.get(relations);
|
|
413
|
+
if (!cached) {
|
|
414
|
+
cached = drizzle({ client: db, relations });
|
|
415
|
+
this.drizzleByRelations.set(relations, cached);
|
|
416
|
+
}
|
|
417
|
+
return cached;
|
|
398
418
|
}
|
|
399
419
|
/**
|
|
400
420
|
* Convert $1, $2 placeholders to ? for better-sqlite3.
|
|
@@ -409,7 +429,29 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
409
429
|
* Creates a TransactionContext for the given database connection.
|
|
410
430
|
*/
|
|
411
431
|
createTransactionContext(db) {
|
|
432
|
+
const buildTxExecutor = () => drizzle({ client: db });
|
|
433
|
+
let txExecutor;
|
|
434
|
+
const txDb = () => txExecutor ??= buildTxExecutor();
|
|
412
435
|
return {
|
|
436
|
+
// SQLite has no row-level locking and needs none here: `withTransaction`
|
|
437
|
+
// opens SQLite transactions with BEGIN IMMEDIATE, which takes the write
|
|
438
|
+
// lock up front and serializes writers for the whole transaction.
|
|
439
|
+
lockRow: () => Promise.resolve(),
|
|
440
|
+
// `run`, not `all`: better-sqlite3 throws on a statement that returns no
|
|
441
|
+
// rows, which is every statement this method exists to carry. The Drizzle
|
|
442
|
+
// instance is the transaction-bound one, so the statement runs inside this
|
|
443
|
+
// transaction.
|
|
444
|
+
//
|
|
445
|
+
// better-sqlite3 is synchronous, so this resolves an already-settled
|
|
446
|
+
// promise rather than being declared `async` over a body that never
|
|
447
|
+
// awaits.
|
|
448
|
+
runStatement: (statement) => {
|
|
449
|
+
txDb().run(statement);
|
|
450
|
+
return Promise.resolve();
|
|
451
|
+
},
|
|
452
|
+
// `all`, not `run`: this is the reading half, and better-sqlite3 returns
|
|
453
|
+
// rows only from `all`. Synchronous, so the promise is already settled.
|
|
454
|
+
queryStatement: (statement) => Promise.resolve(txDb().all(statement)),
|
|
413
455
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
414
456
|
execute: async (sql, params = []) => {
|
|
415
457
|
const convertedSql = this.convertPlaceholders(sql);
|
|
@@ -430,29 +472,45 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
430
472
|
];
|
|
431
473
|
}
|
|
432
474
|
},
|
|
475
|
+
// Keys only, unlike the PostgreSQL and MySQL raw paths, which also encode
|
|
476
|
+
// their date values. `sanitizeSqliteValue` below binds a `Date` as unix
|
|
477
|
+
// seconds, and an instant carries no zone -- so what SQLite stores does
|
|
478
|
+
// not depend on the server's timezone and there is nothing to correct.
|
|
433
479
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
434
480
|
insert: async (table, data, options) => {
|
|
435
|
-
const
|
|
436
|
-
|
|
481
|
+
const mapped = this.mapKeysToSqlColumns(
|
|
482
|
+
this.getTableObject(table),
|
|
483
|
+
data
|
|
484
|
+
);
|
|
485
|
+
const columns = Object.keys(mapped);
|
|
486
|
+
const values = Object.values(mapped).map(sanitizeSqliteValue);
|
|
437
487
|
const placeholders = values.map(() => "?").join(", ");
|
|
438
488
|
let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map((c) => this.escapeIdentifier(c)).join(", ")}) VALUES (${placeholders})`;
|
|
439
|
-
|
|
440
|
-
|
|
489
|
+
const ret = options?.returning;
|
|
490
|
+
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
491
|
+
if (!returningEmpty) {
|
|
492
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(this.getTableObject(table), ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
441
493
|
sql += ` RETURNING ${returning}`;
|
|
442
|
-
} else {
|
|
443
|
-
sql += " RETURNING *";
|
|
444
494
|
}
|
|
445
495
|
const stmt = db.prepare(sql);
|
|
496
|
+
if (returningEmpty) {
|
|
497
|
+
stmt.run(...values);
|
|
498
|
+
return void 0;
|
|
499
|
+
}
|
|
446
500
|
const rows = stmt.all(...values);
|
|
447
|
-
return rows[0];
|
|
501
|
+
return this.mapRowFromRawSql(this.getTableObject(table), rows[0]);
|
|
448
502
|
},
|
|
449
503
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
450
504
|
insertMany: async (table, data, options) => {
|
|
451
505
|
if (data.length === 0) return [];
|
|
452
|
-
const
|
|
506
|
+
const tableObj = this.getTableObject(table);
|
|
507
|
+
const mappedRecords = data.map(
|
|
508
|
+
(r) => this.mapKeysToSqlColumns(tableObj, r)
|
|
509
|
+
);
|
|
510
|
+
const columns = Object.keys(mappedRecords[0]);
|
|
453
511
|
const allValues = [];
|
|
454
512
|
const valuesClauses = [];
|
|
455
|
-
for (const record of
|
|
513
|
+
for (const record of mappedRecords) {
|
|
456
514
|
const placeholders = [];
|
|
457
515
|
for (const col of columns) {
|
|
458
516
|
allValues.push(sanitizeSqliteValue(record[col]));
|
|
@@ -461,31 +519,38 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
461
519
|
valuesClauses.push(`(${placeholders.join(", ")})`);
|
|
462
520
|
}
|
|
463
521
|
let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map((c) => this.escapeIdentifier(c)).join(", ")}) VALUES ${valuesClauses.join(", ")}`;
|
|
464
|
-
|
|
465
|
-
|
|
522
|
+
const ret = options?.returning;
|
|
523
|
+
const returningEmpty = Array.isArray(ret) && ret.length === 0;
|
|
524
|
+
if (!returningEmpty) {
|
|
525
|
+
const returning = !ret || ret === "*" ? "*" : this.mapColumnNamesToSql(this.getTableObject(table), ret).map((col) => this.escapeIdentifier(col)).join(", ");
|
|
466
526
|
sql += ` RETURNING ${returning}`;
|
|
467
|
-
} else {
|
|
468
|
-
sql += " RETURNING *";
|
|
469
527
|
}
|
|
470
528
|
const stmt = db.prepare(sql);
|
|
471
|
-
|
|
529
|
+
if (returningEmpty) {
|
|
530
|
+
stmt.run(...allValues);
|
|
531
|
+
return [];
|
|
532
|
+
}
|
|
533
|
+
return stmt.all(...allValues).map(
|
|
534
|
+
(r) => this.mapRowFromRawSql(tableObj, r)
|
|
535
|
+
);
|
|
472
536
|
},
|
|
473
|
-
// TransactionContext CRUD methods delegate to the adapter's CRUD
|
|
474
|
-
//
|
|
537
|
+
// TransactionContext CRUD methods delegate to the adapter's Drizzle CRUD
|
|
538
|
+
// but pass the transaction-bound executor so they run inside this
|
|
539
|
+
// transaction rather than on the pool.
|
|
475
540
|
select: async (table, options) => {
|
|
476
|
-
return this.select(table, options);
|
|
541
|
+
return this.select(table, options, txDb());
|
|
477
542
|
},
|
|
478
543
|
selectOne: async (table, options) => {
|
|
479
|
-
return this.selectOne(table, options);
|
|
544
|
+
return this.selectOne(table, options, txDb());
|
|
480
545
|
},
|
|
481
546
|
update: async (table, data, where, options) => {
|
|
482
|
-
return this.update(table, data, where, options);
|
|
547
|
+
return this.update(table, data, where, options, txDb());
|
|
483
548
|
},
|
|
484
|
-
delete: async (table, where,
|
|
485
|
-
return this.delete(table, where);
|
|
549
|
+
delete: async (table, where, options) => {
|
|
550
|
+
return this.delete(table, where, options, txDb());
|
|
486
551
|
},
|
|
487
552
|
upsert: async (table, data, options) => {
|
|
488
|
-
return this.upsert(table, data, options);
|
|
553
|
+
return this.upsert(table, data, options, txDb());
|
|
489
554
|
},
|
|
490
555
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
491
556
|
savepoint: async (name) => {
|
|
@@ -498,7 +563,12 @@ var SqliteAdapter = class extends DrizzleAdapter {
|
|
|
498
563
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
499
564
|
releaseSavepoint: async (name) => {
|
|
500
565
|
db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);
|
|
501
|
-
}
|
|
566
|
+
},
|
|
567
|
+
// Expose the transaction-bound Drizzle instance so callers can run
|
|
568
|
+
// Drizzle sql templates inside this transaction (junction-table writes
|
|
569
|
+
// need this to be atomic with the entry write). Reuses the memoized
|
|
570
|
+
// txDb() built for the delegated CRUD methods.
|
|
571
|
+
getDrizzle: () => txDb()
|
|
502
572
|
};
|
|
503
573
|
}
|
|
504
574
|
/**
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @nextlyhq/adapter-sqlite\n *\n * SQLite database adapter for Nextly.\n * Extends DrizzleAdapter from @nextlyhq/adapter-drizzle to provide SQLite-specific functionality.\n *\n * @remarks\n * This adapter uses the better-sqlite3 package for database connectivity and provides:\n * - Synchronous API wrapped for async interface compatibility\n * - Full transaction support with savepoints (via better-sqlite3's native transaction handling)\n * - CRUD operations with RETURNING clause support (SQLite 3.35+)\n * - WAL mode for better concurrent read performance\n * - In-memory and file-based database support\n *\n * @example\n * ```typescript\n * import { createSqliteAdapter } from '@nextlyhq/adapter-sqlite';\n *\n * const adapter = createSqliteAdapter({\n * url: 'file:./data/app.db',\n * });\n *\n * await adapter.connect();\n *\n * // Query data\n * const users = await adapter.select('users', {\n * where: { and: [{ column: 'status', op: '=', value: 'active' }] },\n * limit: 10,\n * });\n *\n * await adapter.disconnect();\n * ```\n *\n * @packageDocumentation\n */\n\nimport { DrizzleAdapter } from \"@nextlyhq/adapter-drizzle\";\n// F17: connect-time DB version check shared across all adapters.\nimport {\n createDatabaseError,\n isDatabaseError,\n type SqliteAdapterConfig,\n type DatabaseCapabilities,\n type PoolStats,\n type TransactionContext,\n type TransactionOptions,\n type SqlParam,\n type WhereClause,\n type WhereCondition,\n type WhereOperator,\n type SelectOptions,\n type InsertOptions,\n type UpdateOptions,\n type DeleteOptions,\n type UpsertOptions,\n type OrderBySpec,\n type JoinSpec,\n type DatabaseError,\n type DatabaseErrorKind,\n type BaseAdapterConfig,\n type AdapterLogger,\n} from \"@nextlyhq/adapter-drizzle/types\";\nimport { checkDialectVersion } from \"@nextlyhq/adapter-drizzle/version-check\";\nimport type Database from \"better-sqlite3\";\nimport {\n drizzle,\n type BetterSQLite3Database,\n} from \"drizzle-orm/better-sqlite3\";\n\n// Re-export types for convenience\nexport type {\n SqliteAdapterConfig,\n DatabaseCapabilities,\n PoolStats,\n TransactionContext,\n TransactionOptions,\n SqlParam,\n WhereClause,\n WhereCondition,\n WhereOperator,\n SelectOptions,\n InsertOptions,\n UpdateOptions,\n DeleteOptions,\n UpsertOptions,\n OrderBySpec,\n JoinSpec,\n DatabaseError,\n DatabaseErrorKind,\n BaseAdapterConfig,\n AdapterLogger,\n};\n\n/**\n * Package version\n */\nexport const VERSION = \"0.1.0\";\n\n/**\n * SQLite error codes mapping to DatabaseErrorKind.\n *\n * @see https://sqlite.org/rescode.html\n */\nconst SQLITE_ERROR_CODES: Record<string, DatabaseErrorKind> = {\n // Constraint violations\n SQLITE_CONSTRAINT: \"constraint\",\n SQLITE_CONSTRAINT_UNIQUE: \"unique_violation\",\n SQLITE_CONSTRAINT_PRIMARYKEY: \"unique_violation\",\n SQLITE_CONSTRAINT_FOREIGNKEY: \"foreign_key_violation\",\n SQLITE_CONSTRAINT_NOTNULL: \"not_null_violation\",\n SQLITE_CONSTRAINT_CHECK: \"check_violation\",\n\n // Busy/locked errors\n SQLITE_BUSY: \"timeout\",\n SQLITE_LOCKED: \"timeout\",\n\n // Connection errors\n SQLITE_CANTOPEN: \"connection\",\n SQLITE_NOTADB: \"connection\",\n SQLITE_CORRUPT: \"connection\",\n\n // Query errors\n SQLITE_ERROR: \"query\",\n SQLITE_MISUSE: \"query\",\n SQLITE_RANGE: \"query\",\n};\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG = {\n busyTimeout: 5000,\n wal: true,\n foreignKeys: true,\n};\n\n/**\n * Converts a JavaScript value to a type that better-sqlite3 can bind.\n * better-sqlite3 only accepts: number, string, bigint, Buffer, null.\n */\nfunction sanitizeSqliteValue(v: unknown): unknown {\n if (v === undefined) return null;\n if (typeof v === \"boolean\") return v ? 1 : 0;\n if (v instanceof Date) return v.toISOString();\n if (v !== null && typeof v === \"object\") return JSON.stringify(v);\n return v;\n}\n\n/**\n * SQLite database adapter for Nextly.\n *\n * Extends the base DrizzleAdapter to provide SQLite-specific functionality\n * using the better-sqlite3 package.\n *\n * @remarks\n * SQLite has some differences from PostgreSQL:\n * - Synchronous API (wrapped for async compatibility)\n * - No connection pooling (single file/connection)\n * - RETURNING clause supported (SQLite 3.35+)\n * - Savepoints supported via nested transactions\n * - No native ILIKE (uses LOWER() LIKE workaround)\n * - JSON support (not JSONB)\n * - No array types\n *\n * @example\n * ```typescript\n * const adapter = new SqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport class SqliteAdapter extends DrizzleAdapter {\n /**\n * The database dialect - always 'sqlite' for this adapter.\n */\n readonly dialect = \"sqlite\" as const;\n\n /**\n * Adapter configuration.\n */\n protected readonly config: SqliteAdapterConfig;\n\n /**\n * better-sqlite3 Database instance.\n */\n private db: Database.Database | null = null;\n\n /**\n * Connection state flag.\n */\n private connected = false;\n\n /**\n * Serialization queue for concurrent `transaction()` calls.\n *\n * better-sqlite3 is synchronous, single-connection, and rejects nested\n * `BEGIN` with \"cannot start a transaction within a transaction\".\n * When two `await adapter.transaction(...)` calls overlap (e.g. a bulk\n * mutation calling `Promise.allSettled` with N per-row updates), the\n * second one tries to BEGIN while the first is still open and the\n * driver throws.\n *\n * Postgres/MySQL avoid this by allocating a fresh client/connection\n * per transaction from a pool — there is no equivalent for\n * better-sqlite3, so we serialize at the JS layer instead. Every\n * `transaction()` invocation chains onto this promise; only one\n * BEGIN→COMMIT/ROLLBACK section runs at any moment, preserving\n * write-isolation semantics that callers expect from a transactional\n * adapter.\n *\n * Performance impact is the natural floor: SQLite already serializes\n * writers at the file-lock level, so the queue removes failed-call\n * surface area without changing the achievable concurrency.\n */\n private transactionQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Creates a new SQLite adapter instance.\n *\n * @param config - Adapter configuration\n */\n constructor(config: SqliteAdapterConfig) {\n super();\n this.config = config;\n }\n\n /**\n * Connect to the SQLite database.\n *\n * @remarks\n * This method initializes the database connection. For SQLite, this\n * opens the database file or creates an in-memory database.\n * Also configures WAL mode and foreign keys based on config.\n *\n * @throws {DatabaseError} If connection fails\n */\n async connect(): Promise<void> {\n if (this.connected && this.db) {\n return;\n }\n\n try {\n // Dynamic import of better-sqlite3 to avoid bundling issues\n const BetterSqlite3 = await import(\"better-sqlite3\");\n const Database = BetterSqlite3.default;\n\n // Determine database path\n let dbPath: string;\n if (this.config.memory) {\n dbPath = \":memory:\";\n } else if (this.config.url) {\n // Strip file: prefix if present\n dbPath = this.config.url.replace(/^file:/, \"\");\n } else {\n dbPath = \":memory:\";\n }\n\n // Ensure the parent directory exists for file-backed databases.\n // better-sqlite3 fails with a confusing \"Cannot open database\n // because the directory does not exist\" error if it doesn't, and\n // a fresh clone with `DATABASE_URL=file:./data/app.db` reliably\n // hits this on first run. Create the dir lazily so DATABASE_URL\n // can point anywhere without a separate setup step.\n if (dbPath !== \":memory:\" && !this.config.readonly) {\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n const dir = path.dirname(path.resolve(dbPath));\n await fs.promises.mkdir(dir, { recursive: true });\n }\n\n // Create database instance\n this.db = new Database(dbPath, {\n readonly: this.config.readonly ?? false,\n timeout: this.config.busyTimeout ?? DEFAULT_CONFIG.busyTimeout,\n });\n\n // Configure WAL mode for better concurrency (unless in-memory or readonly)\n if (\n (this.config.wal ?? DEFAULT_CONFIG.wal) &&\n dbPath !== \":memory:\" &&\n !this.config.readonly\n ) {\n this.db.pragma(\"journal_mode = WAL\");\n }\n\n // Enable foreign keys\n if (this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys) {\n this.db.pragma(\"foreign_keys = ON\");\n }\n\n // F17: check SQLite version. Hard-fails on SQLite <3.38. SQLite has\n // no recognized cloud variants we warn on, so onWarning is omitted.\n // Note: better-sqlite3's bundled SQLite is set by the package\n // version; users on this package's pinned better-sqlite3 (3.45+)\n // will always pass.\n await checkDialectVersion(this.db, \"sqlite\");\n\n this.connected = true;\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection established\", {\n url: dbPath === \":memory:\" ? \"in-memory\" : dbPath,\n wal: this.config.wal ?? DEFAULT_CONFIG.wal,\n foreignKeys: this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys,\n });\n }\n } catch (error) {\n // Clean up on failure\n if (this.db) {\n try {\n this.db.close();\n } catch {\n // Ignore close errors during error handling\n }\n this.db = null;\n }\n throw this.classifyError(error);\n }\n }\n\n /**\n * Disconnect from the SQLite database.\n *\n * @remarks\n * This method closes the database connection and releases resources.\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async disconnect(): Promise<void> {\n if (!this.db) {\n return;\n }\n\n try {\n this.db.close();\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection closed\");\n }\n } finally {\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected to the database.\n */\n isConnected(): boolean {\n return this.connected && this.db !== null;\n }\n\n /**\n * Get connection pool statistics.\n *\n * @remarks\n * SQLite doesn't use connection pooling, so this returns null.\n * The database is single-file with a single connection.\n */\n getPoolStats(): PoolStats | null {\n // SQLite doesn't have connection pooling\n return null;\n }\n\n /**\n * Execute a raw SQL query.\n *\n * @param sql - SQL query string with $1, $2 placeholders (converted to ? for SQLite)\n * @param params - Query parameters\n * @returns Query results\n *\n * @throws {DatabaseError} If query execution fails\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async executeQuery<T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Convert $1, $2 placeholders to ? for better-sqlite3\n const convertedSql = this.convertPlaceholders(sql);\n\n // Determine if this is a SELECT query or a modifying query\n const trimmedSql = convertedSql.trim().toUpperCase();\n\n // Check for PRAGMA query statements (e.g., \"PRAGMA foreign_keys\").\n // Setting PRAGMAs (e.g., \"PRAGMA foreign_keys = OFF\") don't return data.\n const isPragmaQuery =\n trimmedSql.startsWith(\"PRAGMA\") && !trimmedSql.includes(\"=\");\n\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") ||\n isPragmaQuery ||\n trimmedSql.startsWith(\"WITH\");\n const hasReturning = trimmedSql.includes(\"RETURNING\");\n\n let result: T[];\n\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect || hasReturning) {\n // Use .all() for SELECT queries or queries with RETURNING\n const stmt = db.prepare(convertedSql);\n result = stmt.all(...sanitizedParams) as T[];\n } else {\n // Use .run() for INSERT/UPDATE/DELETE/PRAGMA settings without RETURNING\n const stmt = db.prepare(convertedSql);\n const runResult = stmt.run(...sanitizedParams);\n // Return info about the operation\n result = [\n {\n changes: runResult.changes,\n lastInsertRowid: runResult.lastInsertRowid,\n } as unknown as T,\n ];\n }\n\n // Log query if logger configured\n if (this.config.logger?.query) {\n const durationMs = Date.now() - startTime;\n this.config.logger.query(convertedSql, params, durationMs);\n }\n\n return result;\n } catch (error) {\n throw this.classifyError(error, sql);\n }\n }\n\n /**\n * Execute work within a transaction.\n *\n * @param work - Function containing transactional operations\n * @param options - Transaction options (isolation level not fully supported in SQLite)\n * @returns Result of the work function\n *\n * @remarks\n * Uses better-sqlite3's native transaction handling which:\n * - Automatically commits on success\n * - Automatically rolls back on error\n * - Converts nested transactions to savepoints\n *\n * Note: SQLite uses DEFERRED, IMMEDIATE, or EXCLUSIVE transaction modes\n * rather than isolation levels. This adapter uses IMMEDIATE by default.\n */\n async transaction<T>(\n work: (tx: TransactionContext) => Promise<T>,\n _options?: TransactionOptions\n ): Promise<T> {\n // Why: serialize concurrent transaction() invocations to dodge\n // better-sqlite3's \"cannot start a transaction within a transaction\"\n // error when two awaits overlap on the same connection. See the\n // `transactionQueue` field comment for the full rationale. The queue\n // chains every call onto a tail promise so only one BEGIN → COMMIT\n // section runs at a time; the next call's BEGIN waits for the\n // previous COMMIT/ROLLBACK to finish.\n //\n // Failure isolation: the queue's tail promise must not reject (a\n // rejection would poison every subsequent transaction with the same\n // rejected value). We attach a no-op `.catch` so the chain stays\n // resolved while the actual error propagates back to the original\n // caller through the inner promise.\n const run = async (): Promise<T> => this.runTransaction(work);\n const next = this.transactionQueue.then(run, run);\n this.transactionQueue = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Inner transaction body. Kept private so callers always go through\n * the serialized `transaction()` queue above and the BEGIN/COMMIT\n * pair is never invoked outside of it.\n */\n private async runTransaction<T>(\n work: (tx: TransactionContext) => Promise<T>\n ): Promise<T> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Create transaction context\n const ctx = this.createTransactionContext(db);\n\n // Since better-sqlite3's db.transaction() doesn't support async functions,\n // we manually manage the transaction with BEGIN/COMMIT/ROLLBACK\n db.exec(\"BEGIN IMMEDIATE\");\n\n try {\n const result = await work(ctx);\n db.exec(\"COMMIT\");\n\n // Log success\n if (this.config.logger?.debug) {\n const durationMs = Date.now() - startTime;\n this.config.logger.debug(\"Transaction committed\", {\n durationMs,\n });\n }\n\n return result;\n } catch (error) {\n // Rollback on error\n try {\n db.exec(\"ROLLBACK\");\n } catch {\n // Ignore rollback errors - transaction may already be aborted\n }\n throw error;\n }\n } catch (error) {\n throw this.classifyError(error);\n }\n }\n\n /**\n * Get SQLite database capabilities.\n *\n * @remarks\n * SQLite capabilities:\n * - JSON support (not JSONB)\n * - No arrays\n * - No native ILIKE\n * - RETURNING clause (3.35+)\n * - Savepoints supported\n * - ON CONFLICT supported\n */\n getCapabilities(): DatabaseCapabilities {\n return {\n dialect: \"sqlite\",\n supportsJsonb: false, // SQLite uses JSON, not JSONB\n supportsJson: true,\n supportsArrays: false, // SQLite doesn't support array types\n supportsGeneratedColumns: true, // SQLite 3.31+\n supportsFts: true, // SQLite FTS5\n supportsIlike: false, // No native ILIKE, use LOWER() LIKE\n supportsReturning: true, // SQLite 3.35+\n supportsSavepoints: true, // SQLite supports savepoints\n supportsOnConflict: true, // ON CONFLICT clause\n maxParamsPerQuery: 999, // SQLite SQLITE_MAX_VARIABLE_NUMBER default\n maxIdentifierLength: 128, // SQLite doesn't have a strict limit\n };\n }\n\n /**\n * Override insertMany for bulk insert optimization.\n *\n * @remarks\n * Uses a single multi-row INSERT statement for better performance.\n */\n override async insertMany<T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> {\n if (data.length === 0) {\n return [];\n }\n\n const db = this.ensureDb();\n\n // For single record, use parent implementation\n if (data.length === 1) {\n const result = await this.insert<T>(table, data[0], options);\n return [result];\n }\n\n // Build multi-row INSERT\n const columns = Object.keys(data[0]);\n const params: SqlParam[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n params.push(sanitizeSqliteValue(record[col]) as SqlParam);\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n const columnList = columns\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columnList}) VALUES ${valuesClauses.join(\", \")}`;\n\n // Add RETURNING clause\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning.map(col => this.escapeIdentifier(col)).join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n try {\n const stmt = db.prepare(sql);\n const rows = stmt.all(...(params as unknown[])) as T[];\n return rows;\n } catch (error) {\n throw this.handleQueryError(error, \"insertMany\", table);\n }\n }\n\n // ============================================================\n // Protected Helper Methods\n // ============================================================\n\n /**\n * Ensures database is connected and returns it.\n *\n * @throws {DatabaseError} If not connected\n */\n private ensureDb(): Database.Database {\n if (!this.db) {\n throw createDatabaseError({\n kind: \"connection\",\n message: \"SqliteAdapter is not connected. Call connect() first.\",\n });\n }\n return this.db;\n }\n\n /**\n * Return the typed Drizzle instance for SQLite.\n * Guarded for server-only usage and requires an active connection.\n *\n * @param schema - Optional schema for relational queries (db.query.*)\n * @returns Drizzle ORM instance wrapping the better-sqlite3 connection\n * @throws {Error} If called in browser or not connected\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getDrizzle<T = BetterSQLite3Database<any>>(\n schema?: Record<string, unknown>\n ): T {\n if (typeof window !== \"undefined\") {\n throw new Error(\"getDrizzle() is server-only\");\n }\n const db = this.ensureDb();\n return (schema ? drizzle(db, { schema }) : drizzle(db)) as T;\n }\n\n /**\n * Convert $1, $2 placeholders to ? for better-sqlite3.\n *\n * @param sql - SQL with PostgreSQL-style placeholders\n * @returns SQL with ? placeholders\n */\n private convertPlaceholders(sql: string): string {\n // Replace $1, $2, etc. with ?\n return sql.replace(/\\$\\d+/g, \"?\");\n }\n\n /**\n * Creates a TransactionContext for the given database connection.\n */\n private createTransactionContext(db: Database.Database): TransactionContext {\n // better-sqlite3 is synchronous; the methods below are async to satisfy\n // the TransactionContext contract shared with truly-async dialect adapters.\n return {\n // eslint-disable-next-line @typescript-eslint/require-await\n execute: async <T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> => {\n const convertedSql = this.convertPlaceholders(sql);\n const trimmedSql = convertedSql.trim().toUpperCase();\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") || trimmedSql.includes(\"RETURNING\");\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect) {\n const stmt = db.prepare(convertedSql);\n return stmt.all(...sanitizedParams) as T[];\n } else {\n const stmt = db.prepare(convertedSql);\n const result = stmt.run(...sanitizedParams);\n return [\n {\n changes: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n } as unknown as T,\n ];\n }\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options?: InsertOptions\n ): Promise<T> => {\n const columns = Object.keys(data);\n const values = Object.values(data).map(sanitizeSqliteValue);\n const placeholders = values.map(() => \"?\").join(\", \");\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES (${placeholders})`;\n\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n const stmt = db.prepare(sql);\n const rows = stmt.all(...values) as T[];\n return rows[0];\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insertMany: async <T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> => {\n if (data.length === 0) return [];\n\n const columns = Object.keys(data[0]);\n const allValues: unknown[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n allValues.push(sanitizeSqliteValue(record[col]));\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES ${valuesClauses.join(\", \")}`;\n\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n const stmt = db.prepare(sql);\n return stmt.all(...allValues) as T[];\n },\n\n // TransactionContext CRUD methods delegate to the adapter's CRUD\n // which uses Drizzle query API via the TableResolver.\n select: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T[]> => {\n return this.select<T>(table, options);\n },\n\n selectOne: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T | null> => {\n return this.selectOne<T>(table, options);\n },\n\n update: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n where: WhereClause,\n options?: UpdateOptions\n ): Promise<T[]> => {\n return this.update<T>(table, data, where, options);\n },\n\n delete: async (\n table: string,\n where: WhereClause,\n _options?: DeleteOptions\n ): Promise<number> => {\n return this.delete(table, where);\n },\n\n upsert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options: UpsertOptions\n ): Promise<T> => {\n return this.upsert<T>(table, data, options);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n savepoint: async (name: string): Promise<void> => {\n db.exec(`SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n rollbackToSavepoint: async (name: string): Promise<void> => {\n db.exec(`ROLLBACK TO SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n releaseSavepoint: async (name: string): Promise<void> => {\n db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n };\n }\n\n /**\n * Classifies a SQLite error into a DatabaseError.\n *\n * @param error - Original error from better-sqlite3\n * @param sql - SQL statement that caused the error (optional)\n * @returns DatabaseError with proper classification\n */\n private classifyError(error: unknown, sql?: string): DatabaseError {\n // Why short-circuit on existing DatabaseError: F17's\n // UnsupportedDialectVersionError is already a typed DatabaseError with\n // kind: \"unsupported_version\" plus detectedVersion/requiredVersion\n // fields. Re-wrapping it here would erase those fields.\n if (isDatabaseError(error)) return error;\n\n const sqliteError = error as {\n code?: string;\n message?: string;\n name?: string;\n };\n\n // Determine error kind from SQLite error code\n let kind: DatabaseErrorKind = \"unknown\";\n\n if (sqliteError.code) {\n kind = SQLITE_ERROR_CODES[sqliteError.code] || \"unknown\";\n } else if (sqliteError.message) {\n // Try to extract error type from message\n const msg = sqliteError.message.toUpperCase();\n if (msg.includes(\"UNIQUE CONSTRAINT\")) {\n kind = \"unique_violation\";\n } else if (msg.includes(\"FOREIGN KEY CONSTRAINT\")) {\n kind = \"foreign_key_violation\";\n } else if (msg.includes(\"NOT NULL CONSTRAINT\")) {\n kind = \"not_null_violation\";\n } else if (msg.includes(\"CHECK CONSTRAINT\")) {\n kind = \"check_violation\";\n } else if (msg.includes(\"BUSY\") || msg.includes(\"LOCKED\")) {\n kind = \"timeout\";\n } else if (\n msg.includes(\"SQLITE_CANTOPEN\") ||\n msg.includes(\"UNABLE TO OPEN\")\n ) {\n kind = \"connection\";\n }\n }\n\n // Build error message\n let message = sqliteError.message ?? String(error);\n if (sql && kind === \"query\") {\n message = `Query failed: ${message}`;\n }\n\n return createDatabaseError({\n kind,\n message,\n code: sqliteError.code,\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Override handleQueryError to use SQLite-specific classification.\n */\n protected override handleQueryError(\n error: unknown,\n operation: string,\n table: string\n ): DatabaseError {\n const dbError = this.classifyError(error);\n\n // Add operation context if not already present\n if (!dbError.message.includes(operation)) {\n dbError.message = `${operation} operation failed on table '${table}': ${dbError.message}`;\n }\n\n if (!dbError.table) {\n dbError.table = table;\n }\n\n return dbError;\n }\n}\n\n/**\n * Create a SQLite database adapter.\n *\n * @param config - SQLite adapter configuration\n * @returns A new SqliteAdapter instance\n *\n * @example\n * ```typescript\n * // Simple usage with file path\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * // In-memory database\n * const memAdapter = createSqliteAdapter({\n * memory: true,\n * });\n *\n * // Full configuration\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * wal: true,\n * foreignKeys: true,\n * busyTimeout: 5000,\n * logger: {\n * query: (sql, params, duration) => console.log(`Query: ${sql}`),\n * },\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport function createSqliteAdapter(\n config: SqliteAdapterConfig\n): SqliteAdapter {\n return new SqliteAdapter(config);\n}\n\n/**\n * Type guard to check if a value is a SqliteAdapter.\n *\n * @param value - Value to check\n * @returns True if value is a SqliteAdapter instance\n *\n * @example\n * ```typescript\n * if (isSqliteAdapter(adapter)) {\n * // TypeScript knows adapter is SqliteAdapter\n * console.log('Using SQLite');\n * }\n * ```\n */\nexport function isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return value instanceof SqliteAdapter;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @nextlyhq/adapter-sqlite\n *\n * SQLite database adapter for Nextly.\n * Extends DrizzleAdapter from @nextlyhq/adapter-drizzle to provide SQLite-specific functionality.\n *\n * @remarks\n * This adapter uses the better-sqlite3 package for database connectivity and provides:\n * - Synchronous API wrapped for async interface compatibility\n * - Full transaction support with savepoints (via better-sqlite3's native transaction handling)\n * - CRUD operations with RETURNING clause support (SQLite 3.35+)\n * - WAL mode for better concurrent read performance\n * - In-memory and file-based database support\n *\n * @example\n * ```typescript\n * import { createSqliteAdapter } from '@nextlyhq/adapter-sqlite';\n *\n * const adapter = createSqliteAdapter({\n * url: 'file:./data/app.db',\n * });\n *\n * await adapter.connect();\n *\n * // Query data\n * const users = await adapter.select('users', {\n * where: { and: [{ column: 'status', op: '=', value: 'active' }] },\n * limit: 10,\n * });\n *\n * await adapter.disconnect();\n * ```\n *\n * @packageDocumentation\n */\n\nimport { DrizzleAdapter } from \"@nextlyhq/adapter-drizzle\";\n// F17: connect-time DB version check shared across all adapters.\nimport {\n createDatabaseError,\n isDatabaseError,\n type SqliteAdapterConfig,\n type DatabaseCapabilities,\n type PoolStats,\n type TransactionContext,\n type TransactionOptions,\n type SqlParam,\n type WhereClause,\n type WhereCondition,\n type WhereOperator,\n type SelectOptions,\n type InsertOptions,\n type UpdateOptions,\n type DeleteOptions,\n type UpsertOptions,\n type OrderBySpec,\n type JoinSpec,\n type DatabaseError,\n type DatabaseErrorKind,\n type BaseAdapterConfig,\n type AdapterLogger,\n isApplicationError,\n} from \"@nextlyhq/adapter-drizzle/types\";\nimport { checkDialectVersion } from \"@nextlyhq/adapter-drizzle/version-check\";\nimport type Database from \"better-sqlite3\";\nimport type { AnyRelations, SQL } from \"drizzle-orm\";\nimport {\n drizzle,\n type BetterSQLite3Database,\n} from \"drizzle-orm/better-sqlite3\";\n\n// Re-export types for convenience\nexport type {\n SqliteAdapterConfig,\n DatabaseCapabilities,\n PoolStats,\n TransactionContext,\n TransactionOptions,\n SqlParam,\n WhereClause,\n WhereCondition,\n WhereOperator,\n SelectOptions,\n InsertOptions,\n UpdateOptions,\n DeleteOptions,\n UpsertOptions,\n OrderBySpec,\n JoinSpec,\n DatabaseError,\n DatabaseErrorKind,\n BaseAdapterConfig,\n AdapterLogger,\n};\n\n/**\n * Package version\n */\nexport const VERSION = \"0.1.0\";\n\n/**\n * SQLite error codes mapping to DatabaseErrorKind.\n *\n * @see https://sqlite.org/rescode.html\n */\nconst SQLITE_ERROR_CODES: Record<string, DatabaseErrorKind> = {\n // Constraint violations\n SQLITE_CONSTRAINT: \"constraint\",\n SQLITE_CONSTRAINT_UNIQUE: \"unique_violation\",\n SQLITE_CONSTRAINT_PRIMARYKEY: \"unique_violation\",\n SQLITE_CONSTRAINT_FOREIGNKEY: \"foreign_key_violation\",\n SQLITE_CONSTRAINT_NOTNULL: \"not_null_violation\",\n SQLITE_CONSTRAINT_CHECK: \"check_violation\",\n\n // Busy/locked errors\n SQLITE_BUSY: \"timeout\",\n SQLITE_LOCKED: \"timeout\",\n\n // Connection errors\n SQLITE_CANTOPEN: \"connection\",\n SQLITE_NOTADB: \"connection\",\n SQLITE_CORRUPT: \"connection\",\n\n // Query errors\n SQLITE_ERROR: \"query\",\n SQLITE_MISUSE: \"query\",\n SQLITE_RANGE: \"query\",\n};\n\n/**\n * Default configuration values.\n */\nconst DEFAULT_CONFIG = {\n busyTimeout: 5000,\n wal: true,\n foreignKeys: true,\n};\n\n/**\n * Converts a JavaScript value to a type that better-sqlite3 can bind.\n * better-sqlite3 only accepts: number, string, bigint, Buffer, null.\n *\n * These conversions have to match what the schema declares, because the rows\n * they write are read back through it. Every column here that takes a `Date`\n * is `integer({ mode: \"timestamp\" })` — the system columns and user date\n * fields in `runtime-schema-generator.ts`, and the core tables, whose date\n * columns are all INTEGER. So a date is bound as unix seconds, which is what\n * that mode reads.\n */\nfunction sanitizeSqliteValue(v: unknown): unknown {\n if (v === undefined) return null;\n if (typeof v === \"boolean\") return v ? 1 : 0;\n // Seconds, not an ISO string. SQLite stores whatever it is given regardless\n // of the declared type, so a string lands in the column without complaint\n // and only fails on the way back out, where the timestamp decoder reads it\n // as a number and yields an Invalid Date.\n if (v instanceof Date) return Math.floor(v.getTime() / 1000);\n if (v !== null && typeof v === \"object\") return JSON.stringify(v);\n return v;\n}\n\n/**\n * SQLite database adapter for Nextly.\n *\n * Extends the base DrizzleAdapter to provide SQLite-specific functionality\n * using the better-sqlite3 package.\n *\n * @remarks\n * SQLite has some differences from PostgreSQL:\n * - Synchronous API (wrapped for async compatibility)\n * - No connection pooling (single file/connection)\n * - RETURNING clause supported (SQLite 3.35+)\n * - Savepoints supported via nested transactions\n * - No native ILIKE (uses LOWER() LIKE workaround)\n * - JSON support (not JSONB)\n * - No array types\n *\n * @example\n * ```typescript\n * const adapter = new SqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport class SqliteAdapter extends DrizzleAdapter {\n // getDrizzle memoization: drizzle v1's constructor builds a relational\n // query builder per table in the relations config (~40 tables), and the\n // service layer resolves an instance on every db access — construct once\n // per relations object (identity-stable: the schema registry caches it\n // and hands out a NEW object on invalidation, which naturally misses\n // this cache and produces a fresh instance).\n private drizzleByRelations = new WeakMap<AnyRelations, unknown>();\n private drizzleBare: unknown;\n\n /**\n * The database dialect - always 'sqlite' for this adapter.\n */\n readonly dialect = \"sqlite\" as const;\n\n /**\n * Adapter configuration.\n */\n protected readonly config: SqliteAdapterConfig;\n\n /**\n * better-sqlite3 Database instance.\n */\n private db: Database.Database | null = null;\n\n /**\n * Connection state flag.\n */\n private connected = false;\n\n /**\n * Serialization queue for concurrent `transaction()` calls.\n *\n * better-sqlite3 is synchronous, single-connection, and rejects nested\n * `BEGIN` with \"cannot start a transaction within a transaction\".\n * When two `await adapter.transaction(...)` calls overlap (e.g. a bulk\n * mutation calling `Promise.allSettled` with N per-row updates), the\n * second one tries to BEGIN while the first is still open and the\n * driver throws.\n *\n * Postgres/MySQL avoid this by allocating a fresh client/connection\n * per transaction from a pool — there is no equivalent for\n * better-sqlite3, so we serialize at the JS layer instead. Every\n * `transaction()` invocation chains onto this promise; only one\n * BEGIN→COMMIT/ROLLBACK section runs at any moment, preserving\n * write-isolation semantics that callers expect from a transactional\n * adapter.\n *\n * Performance impact is the natural floor: SQLite already serializes\n * writers at the file-lock level, so the queue removes failed-call\n * surface area without changing the achievable concurrency.\n */\n private transactionQueue: Promise<unknown> = Promise.resolve();\n\n /**\n * Creates a new SQLite adapter instance.\n *\n * @param config - Adapter configuration\n */\n constructor(config: SqliteAdapterConfig) {\n super();\n this.config = config;\n }\n\n /**\n * Connect to the SQLite database.\n *\n * @remarks\n * This method initializes the database connection. For SQLite, this\n * opens the database file or creates an in-memory database.\n * Also configures WAL mode and foreign keys based on config.\n *\n * @throws {DatabaseError} If connection fails\n */\n async connect(): Promise<void> {\n if (this.connected && this.db) {\n return;\n }\n\n try {\n // Dynamic import of better-sqlite3 to avoid bundling issues\n const BetterSqlite3 = await import(\"better-sqlite3\");\n const Database = BetterSqlite3.default;\n\n // Determine database path\n let dbPath: string;\n if (this.config.memory) {\n dbPath = \":memory:\";\n } else if (this.config.url) {\n // Strip file: prefix if present\n dbPath = this.config.url.replace(/^file:/, \"\");\n } else {\n dbPath = \":memory:\";\n }\n\n // Ensure the parent directory exists for file-backed databases.\n // better-sqlite3 fails with a confusing \"Cannot open database\n // because the directory does not exist\" error if it doesn't, and\n // a fresh clone with `DATABASE_URL=file:./data/app.db` reliably\n // hits this on first run. Create the dir lazily so DATABASE_URL\n // can point anywhere without a separate setup step.\n if (dbPath !== \":memory:\" && !this.config.readonly) {\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n const dir = path.dirname(path.resolve(dbPath));\n await fs.promises.mkdir(dir, { recursive: true });\n }\n\n // Create database instance\n this.db = new Database(dbPath, {\n readonly: this.config.readonly ?? false,\n timeout: this.config.busyTimeout ?? DEFAULT_CONFIG.busyTimeout,\n });\n\n // Configure WAL mode for better concurrency (unless in-memory or readonly)\n if (\n (this.config.wal ?? DEFAULT_CONFIG.wal) &&\n dbPath !== \":memory:\" &&\n !this.config.readonly\n ) {\n this.db.pragma(\"journal_mode = WAL\");\n }\n\n // Enable foreign keys\n if (this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys) {\n this.db.pragma(\"foreign_keys = ON\");\n }\n\n // F17: check SQLite version. Hard-fails on SQLite <3.38. SQLite has\n // no recognized cloud variants we warn on, so onWarning is omitted.\n // Note: better-sqlite3's bundled SQLite is set by the package\n // version; users on this package's pinned better-sqlite3 (3.45+)\n // will always pass.\n await checkDialectVersion(this.db, \"sqlite\");\n\n this.connected = true;\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection established\", {\n url: dbPath === \":memory:\" ? \"in-memory\" : dbPath,\n wal: this.config.wal ?? DEFAULT_CONFIG.wal,\n foreignKeys: this.config.foreignKeys ?? DEFAULT_CONFIG.foreignKeys,\n });\n }\n } catch (error) {\n // Clean up on failure\n if (this.db) {\n try {\n this.db.close();\n } catch {\n // Ignore close errors during error handling\n }\n this.db = null;\n }\n throw this.classifyError(error);\n }\n }\n\n /**\n * Disconnect from the SQLite database.\n *\n * @remarks\n * This method closes the database connection and releases resources.\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async disconnect(): Promise<void> {\n // Drop memoized drizzle instances — they wrap the connection being\n // closed and must not survive a reconnect.\n this.drizzleBare = undefined;\n this.drizzleByRelations = new WeakMap();\n if (!this.db) {\n return;\n }\n\n try {\n this.db.close();\n\n if (this.config.logger?.info) {\n this.config.logger.info(\"SQLite connection closed\");\n }\n } finally {\n this.db = null;\n this.connected = false;\n }\n }\n\n /**\n * Check if connected to the database.\n */\n isConnected(): boolean {\n return this.connected && this.db !== null;\n }\n\n /**\n * Get connection pool statistics.\n *\n * @remarks\n * SQLite doesn't use connection pooling, so this returns null.\n * The database is single-file with a single connection.\n */\n getPoolStats(): PoolStats | null {\n // SQLite doesn't have connection pooling\n return null;\n }\n\n /**\n * Execute a raw SQL query.\n *\n * @param sql - SQL query string with $1, $2 placeholders (converted to ? for SQLite)\n * @param params - Query parameters\n * @returns Query results\n *\n * @throws {DatabaseError} If query execution fails\n */\n // better-sqlite3 is synchronous; method is async to satisfy the DatabaseAdapter contract.\n // eslint-disable-next-line @typescript-eslint/require-await\n async executeQuery<T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Convert $1, $2 placeholders to ? for better-sqlite3\n const convertedSql = this.convertPlaceholders(sql);\n\n // Determine if this is a SELECT query or a modifying query\n const trimmedSql = convertedSql.trim().toUpperCase();\n\n // Check for PRAGMA query statements (e.g., \"PRAGMA foreign_keys\").\n // Setting PRAGMAs (e.g., \"PRAGMA foreign_keys = OFF\") don't return data.\n const isPragmaQuery =\n trimmedSql.startsWith(\"PRAGMA\") && !trimmedSql.includes(\"=\");\n\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") ||\n isPragmaQuery ||\n trimmedSql.startsWith(\"WITH\");\n const hasReturning = trimmedSql.includes(\"RETURNING\");\n\n let result: T[];\n\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect || hasReturning) {\n // Use .all() for SELECT queries or queries with RETURNING\n const stmt = db.prepare(convertedSql);\n result = stmt.all(...sanitizedParams) as T[];\n } else {\n // Use .run() for INSERT/UPDATE/DELETE/PRAGMA settings without RETURNING\n const stmt = db.prepare(convertedSql);\n const runResult = stmt.run(...sanitizedParams);\n // Return info about the operation\n result = [\n {\n changes: runResult.changes,\n lastInsertRowid: runResult.lastInsertRowid,\n } as unknown as T,\n ];\n }\n\n // Log query if logger configured\n if (this.config.logger?.query) {\n const durationMs = Date.now() - startTime;\n this.config.logger.query(convertedSql, params, durationMs);\n }\n\n return result;\n } catch (error) {\n throw this.classifyError(error, sql);\n }\n }\n\n /**\n * Execute work within a transaction.\n *\n * @param work - Function containing transactional operations\n * @param options - Transaction options (isolation level not fully supported in SQLite)\n * @returns Result of the work function\n *\n * @remarks\n * Uses better-sqlite3's native transaction handling which:\n * - Automatically commits on success\n * - Automatically rolls back on error\n * - Converts nested transactions to savepoints\n *\n * Note: SQLite uses DEFERRED, IMMEDIATE, or EXCLUSIVE transaction modes\n * rather than isolation levels. This adapter uses IMMEDIATE by default.\n */\n async transaction<T>(\n work: (tx: TransactionContext) => Promise<T>,\n _options?: TransactionOptions\n ): Promise<T> {\n // Why: serialize concurrent transaction() invocations to dodge\n // better-sqlite3's \"cannot start a transaction within a transaction\"\n // error when two awaits overlap on the same connection. See the\n // `transactionQueue` field comment for the full rationale. The queue\n // chains every call onto a tail promise so only one BEGIN → COMMIT\n // section runs at a time; the next call's BEGIN waits for the\n // previous COMMIT/ROLLBACK to finish.\n //\n // Failure isolation: the queue's tail promise must not reject (a\n // rejection would poison every subsequent transaction with the same\n // rejected value). We attach a no-op `.catch` so the chain stays\n // resolved while the actual error propagates back to the original\n // caller through the inner promise.\n const run = async (): Promise<T> => this.runTransaction(work);\n const next = this.transactionQueue.then(run, run);\n this.transactionQueue = next.catch(() => undefined);\n return next;\n }\n\n /**\n * Inner transaction body. Kept private so callers always go through\n * the serialized `transaction()` queue above and the BEGIN/COMMIT\n * pair is never invoked outside of it.\n */\n private async runTransaction<T>(\n work: (tx: TransactionContext) => Promise<T>\n ): Promise<T> {\n const db = this.ensureDb();\n const startTime = Date.now();\n\n try {\n // Create transaction context\n const ctx = this.createTransactionContext(db);\n\n // Since better-sqlite3's db.transaction() doesn't support async functions,\n // we manually manage the transaction with BEGIN/COMMIT/ROLLBACK\n db.exec(\"BEGIN IMMEDIATE\");\n\n try {\n const result = await work(ctx);\n db.exec(\"COMMIT\");\n\n // Log success\n if (this.config.logger?.debug) {\n const durationMs = Date.now() - startTime;\n this.config.logger.debug(\"Transaction committed\", {\n durationMs,\n });\n }\n\n return result;\n } catch (error) {\n // Rollback on error\n try {\n db.exec(\"ROLLBACK\");\n } catch {\n // Ignore rollback errors - transaction may already be aborted\n }\n throw error;\n }\n } catch (error) {\n // Work inside a transaction may throw to roll the write back — a refused\n // value, a denied permission — and that is the application's verdict, not\n // the driver's failure. Classifying it would replace its code and payload\n // with a generic database error, so a caller that asked for a refusal is\n // handed an unexplained failure and the per-field detail never arrives.\n if (isApplicationError(error)) throw error;\n throw this.classifyError(error);\n }\n }\n\n /**\n * Get SQLite database capabilities.\n *\n * @remarks\n * SQLite capabilities:\n * - JSON support (not JSONB)\n * - No arrays\n * - No native ILIKE\n * - RETURNING clause (3.35+)\n * - Savepoints supported\n * - ON CONFLICT supported\n */\n getCapabilities(): DatabaseCapabilities {\n return {\n dialect: \"sqlite\",\n supportsJsonb: false, // SQLite uses JSON, not JSONB\n supportsJson: true,\n supportsArrays: false, // SQLite doesn't support array types\n supportsGeneratedColumns: true, // SQLite 3.31+\n supportsFts: true, // SQLite FTS5\n supportsIlike: false, // No native ILIKE, use LOWER() LIKE\n supportsReturning: true, // SQLite 3.35+\n supportsSavepoints: true, // SQLite supports savepoints\n supportsOnConflict: true, // ON CONFLICT clause\n maxParamsPerQuery: 999, // SQLite SQLITE_MAX_VARIABLE_NUMBER default\n maxIdentifierLength: 128, // SQLite doesn't have a strict limit\n };\n }\n\n /**\n * Override insertMany for bulk insert optimization.\n *\n * @remarks\n * Uses a single multi-row INSERT statement for better performance.\n */\n override async insertMany<T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> {\n if (data.length === 0) {\n return [];\n }\n\n const db = this.ensureDb();\n\n // For single record, use parent implementation\n if (data.length === 1) {\n const result = await this.insert<T>(table, data[0], options);\n return [result];\n }\n\n // Build multi-row INSERT\n const columns = Object.keys(data[0]);\n const params: SqlParam[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of data) {\n const placeholders: string[] = [];\n for (const col of columns) {\n params.push(sanitizeSqliteValue(record[col]) as SqlParam);\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n const columnList = columns\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columnList}) VALUES ${valuesClauses.join(\", \")}`;\n\n // Add RETURNING clause\n if (options?.returning) {\n const returning =\n options.returning === \"*\"\n ? \"*\"\n : options.returning.map(col => this.escapeIdentifier(col)).join(\", \");\n sql += ` RETURNING ${returning}`;\n } else {\n sql += \" RETURNING *\";\n }\n\n try {\n const stmt = db.prepare(sql);\n const rows = stmt.all(...(params as unknown[])) as T[];\n // SQLite stores a timestamp as an integer and hands it back as one. The\n // Drizzle read paths decode it through the column definition, so without\n // this a bulk insert answers with numbers where a read answers `Date`.\n const tableObj = this.getTableObject(table);\n return rows.map(r => this.mapRowFromRawSql(tableObj, r));\n } catch (error) {\n throw this.handleQueryError(error, \"insertMany\", table);\n }\n }\n\n // ============================================================\n // Protected Helper Methods\n // ============================================================\n\n /**\n * Ensures database is connected and returns it.\n *\n * @throws {DatabaseError} If not connected\n */\n private ensureDb(): Database.Database {\n if (!this.db) {\n throw createDatabaseError({\n kind: \"connection\",\n message: \"SqliteAdapter is not connected. Call connect() first.\",\n });\n }\n return this.db;\n }\n\n /**\n * Return the typed Drizzle instance for SQLite.\n * Guarded for server-only usage and requires an active connection.\n *\n * @param schema - Optional schema for relational queries (db.query.*)\n * @returns Drizzle ORM instance wrapping the better-sqlite3 connection\n * @throws {Error} If called in browser or not connected\n */\n getDrizzle<T = BetterSQLite3Database<AnyRelations>>(\n relations?: AnyRelations\n ): T {\n if (typeof window !== \"undefined\") {\n throw new Error(\"getDrizzle() is server-only\");\n }\n const db = this.ensureDb();\n // drizzle v1 removed the positional (client, config) form — positional\n // calls silently open a NEW :memory: database. Object form only.\n if (!relations) {\n this.drizzleBare ??= drizzle({ client: db });\n return this.drizzleBare as T;\n }\n let cached = this.drizzleByRelations.get(relations);\n if (!cached) {\n cached = drizzle({ client: db, relations });\n this.drizzleByRelations.set(relations, cached);\n }\n return cached as T;\n }\n\n /**\n * Convert $1, $2 placeholders to ? for better-sqlite3.\n *\n * @param sql - SQL with PostgreSQL-style placeholders\n * @returns SQL with ? placeholders\n */\n private convertPlaceholders(sql: string): string {\n // Replace $1, $2, etc. with ?\n return sql.replace(/\\$\\d+/g, \"?\");\n }\n\n /**\n * Creates a TransactionContext for the given database connection.\n */\n private createTransactionContext(db: Database.Database): TransactionContext {\n // better-sqlite3 is synchronous; the methods below are async to satisfy\n // the TransactionContext contract shared with truly-async dialect adapters.\n // Bind a Drizzle instance to the transaction's connection so the delegated\n // CRUD methods run inside it. better-sqlite3 is single-connection, so this\n // is the same connection getDrizzle() would use, but binding explicitly\n // keeps the three adapters consistent and correct if that ever changes.\n // Built lazily and memoized: transactions that use only raw execute/insert\n // never construct it.\n const buildTxExecutor = () => drizzle({ client: db });\n let txExecutor: ReturnType<typeof buildTxExecutor> | undefined;\n const txDb = () => (txExecutor ??= buildTxExecutor());\n return {\n // SQLite has no row-level locking and needs none here: `withTransaction`\n // opens SQLite transactions with BEGIN IMMEDIATE, which takes the write\n // lock up front and serializes writers for the whole transaction.\n lockRow: (): Promise<void> => Promise.resolve(),\n\n // `run`, not `all`: better-sqlite3 throws on a statement that returns no\n // rows, which is every statement this method exists to carry. The Drizzle\n // instance is the transaction-bound one, so the statement runs inside this\n // transaction.\n //\n // better-sqlite3 is synchronous, so this resolves an already-settled\n // promise rather than being declared `async` over a body that never\n // awaits.\n runStatement: (statement: SQL): Promise<void> => {\n txDb().run(statement);\n return Promise.resolve();\n },\n\n // `all`, not `run`: this is the reading half, and better-sqlite3 returns\n // rows only from `all`. Synchronous, so the promise is already settled.\n queryStatement: <T = Record<string, unknown>>(\n statement: SQL\n ): Promise<T[]> => Promise.resolve(txDb().all(statement)),\n\n // eslint-disable-next-line @typescript-eslint/require-await\n execute: async <T = unknown>(\n sql: string,\n params: SqlParam[] = []\n ): Promise<T[]> => {\n const convertedSql = this.convertPlaceholders(sql);\n const trimmedSql = convertedSql.trim().toUpperCase();\n const isSelect =\n trimmedSql.startsWith(\"SELECT\") || trimmedSql.includes(\"RETURNING\");\n const sanitizedParams = params.map(sanitizeSqliteValue);\n\n if (isSelect) {\n const stmt = db.prepare(convertedSql);\n return stmt.all(...sanitizedParams) as T[];\n } else {\n const stmt = db.prepare(convertedSql);\n const result = stmt.run(...sanitizedParams);\n return [\n {\n changes: result.changes,\n lastInsertRowid: result.lastInsertRowid,\n } as unknown as T,\n ];\n }\n },\n\n // Keys only, unlike the PostgreSQL and MySQL raw paths, which also encode\n // their date values. `sanitizeSqliteValue` below binds a `Date` as unix\n // seconds, and an instant carries no zone -- so what SQLite stores does\n // not depend on the server's timezone and there is nothing to correct.\n // eslint-disable-next-line @typescript-eslint/require-await\n insert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options?: InsertOptions\n ): Promise<T> => {\n const mapped = this.mapKeysToSqlColumns(\n this.getTableObject(table),\n data\n );\n const columns = Object.keys(mapped);\n const values = Object.values(mapped).map(sanitizeSqliteValue);\n const placeholders = values.map(() => \"?\").join(\", \");\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES (${placeholders})`;\n\n const ret = options?.returning;\n const returningEmpty = Array.isArray(ret) && ret.length === 0;\n if (!returningEmpty) {\n const returning =\n !ret || ret === \"*\"\n ? \"*\"\n : this.mapColumnNamesToSql(this.getTableObject(table), ret)\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n }\n\n const stmt = db.prepare(sql);\n if (returningEmpty) {\n // No RETURNING clause: better-sqlite3's .all() rejects a statement\n // that returns no columns, so run it and return nothing.\n stmt.run(...values);\n return undefined as T;\n }\n const rows = stmt.all(...values) as T[];\n // Return JS property-named keys AND Drizzle-decoded date values, so a\n // write inside a transaction answers with the same representation a\n // read of the same row gives.\n return this.mapRowFromRawSql(this.getTableObject(table), rows[0]);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n insertMany: async <T = unknown>(\n table: string,\n data: Record<string, unknown>[],\n options?: InsertOptions\n ): Promise<T[]> => {\n if (data.length === 0) return [];\n\n const tableObj = this.getTableObject(table);\n const mappedRecords = data.map(r =>\n this.mapKeysToSqlColumns(tableObj, r)\n );\n const columns = Object.keys(mappedRecords[0]);\n const allValues: unknown[] = [];\n const valuesClauses: string[] = [];\n\n for (const record of mappedRecords) {\n const placeholders: string[] = [];\n for (const col of columns) {\n allValues.push(sanitizeSqliteValue(record[col]));\n placeholders.push(\"?\");\n }\n valuesClauses.push(`(${placeholders.join(\", \")})`);\n }\n\n let sql = `INSERT INTO ${this.escapeIdentifier(table)} (${columns.map(c => this.escapeIdentifier(c)).join(\", \")}) VALUES ${valuesClauses.join(\", \")}`;\n\n const ret = options?.returning;\n const returningEmpty = Array.isArray(ret) && ret.length === 0;\n if (!returningEmpty) {\n const returning =\n !ret || ret === \"*\"\n ? \"*\"\n : this.mapColumnNamesToSql(this.getTableObject(table), ret)\n .map(col => this.escapeIdentifier(col))\n .join(\", \");\n sql += ` RETURNING ${returning}`;\n }\n\n const stmt = db.prepare(sql);\n if (returningEmpty) {\n stmt.run(...allValues);\n return [];\n }\n return (stmt.all(...allValues) as T[]).map(r =>\n this.mapRowFromRawSql(tableObj, r)\n );\n },\n\n // TransactionContext CRUD methods delegate to the adapter's Drizzle CRUD\n // but pass the transaction-bound executor so they run inside this\n // transaction rather than on the pool.\n select: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T[]> => {\n return this.select<T>(table, options, txDb());\n },\n\n selectOne: async <T = unknown>(\n table: string,\n options?: SelectOptions\n ): Promise<T | null> => {\n return this.selectOne<T>(table, options, txDb());\n },\n\n update: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n where: WhereClause,\n options?: UpdateOptions\n ): Promise<T[]> => {\n return this.update<T>(table, data, where, options, txDb());\n },\n\n delete: async (\n table: string,\n where: WhereClause,\n options?: DeleteOptions\n ): Promise<number> => {\n return this.delete(table, where, options, txDb());\n },\n\n upsert: async <T = unknown>(\n table: string,\n data: Record<string, unknown>,\n options: UpsertOptions\n ): Promise<T> => {\n return this.upsert<T>(table, data, options, txDb());\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n savepoint: async (name: string): Promise<void> => {\n db.exec(`SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n rollbackToSavepoint: async (name: string): Promise<void> => {\n db.exec(`ROLLBACK TO SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // eslint-disable-next-line @typescript-eslint/require-await\n releaseSavepoint: async (name: string): Promise<void> => {\n db.exec(`RELEASE SAVEPOINT ${this.escapeIdentifier(name)}`);\n },\n\n // Expose the transaction-bound Drizzle instance so callers can run\n // Drizzle sql templates inside this transaction (junction-table writes\n // need this to be atomic with the entry write). Reuses the memoized\n // txDb() built for the delegated CRUD methods.\n getDrizzle: <T = unknown>(): T => txDb() as T,\n };\n }\n\n /**\n * Classifies a SQLite error into a DatabaseError.\n *\n * @param error - Original error from better-sqlite3\n * @param sql - SQL statement that caused the error (optional)\n * @returns DatabaseError with proper classification\n */\n private classifyError(error: unknown, sql?: string): DatabaseError {\n // Why short-circuit on existing DatabaseError: F17's\n // UnsupportedDialectVersionError is already a typed DatabaseError with\n // kind: \"unsupported_version\" plus detectedVersion/requiredVersion\n // fields. Re-wrapping it here would erase those fields.\n if (isDatabaseError(error)) return error;\n\n const sqliteError = error as {\n code?: string;\n message?: string;\n name?: string;\n };\n\n // Determine error kind from SQLite error code\n let kind: DatabaseErrorKind = \"unknown\";\n\n if (sqliteError.code) {\n kind = SQLITE_ERROR_CODES[sqliteError.code] || \"unknown\";\n } else if (sqliteError.message) {\n // Try to extract error type from message\n const msg = sqliteError.message.toUpperCase();\n if (msg.includes(\"UNIQUE CONSTRAINT\")) {\n kind = \"unique_violation\";\n } else if (msg.includes(\"FOREIGN KEY CONSTRAINT\")) {\n kind = \"foreign_key_violation\";\n } else if (msg.includes(\"NOT NULL CONSTRAINT\")) {\n kind = \"not_null_violation\";\n } else if (msg.includes(\"CHECK CONSTRAINT\")) {\n kind = \"check_violation\";\n } else if (msg.includes(\"BUSY\") || msg.includes(\"LOCKED\")) {\n kind = \"timeout\";\n } else if (\n msg.includes(\"SQLITE_CANTOPEN\") ||\n msg.includes(\"UNABLE TO OPEN\")\n ) {\n kind = \"connection\";\n }\n }\n\n // Build error message\n let message = sqliteError.message ?? String(error);\n if (sql && kind === \"query\") {\n message = `Query failed: ${message}`;\n }\n\n return createDatabaseError({\n kind,\n message,\n code: sqliteError.code,\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n /**\n * Override handleQueryError to use SQLite-specific classification.\n */\n protected override handleQueryError(\n error: unknown,\n operation: string,\n table: string\n ): DatabaseError {\n const dbError = this.classifyError(error);\n\n // Add operation context if not already present\n if (!dbError.message.includes(operation)) {\n dbError.message = `${operation} operation failed on table '${table}': ${dbError.message}`;\n }\n\n if (!dbError.table) {\n dbError.table = table;\n }\n\n return dbError;\n }\n}\n\n/**\n * Create a SQLite database adapter.\n *\n * @param config - SQLite adapter configuration\n * @returns A new SqliteAdapter instance\n *\n * @example\n * ```typescript\n * // Simple usage with file path\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * });\n *\n * // In-memory database\n * const memAdapter = createSqliteAdapter({\n * memory: true,\n * });\n *\n * // Full configuration\n * const adapter = createSqliteAdapter({\n * url: 'file:./data.db',\n * wal: true,\n * foreignKeys: true,\n * busyTimeout: 5000,\n * logger: {\n * query: (sql, params, duration) => console.log(`Query: ${sql}`),\n * },\n * });\n *\n * await adapter.connect();\n * ```\n */\nexport function createSqliteAdapter(\n config: SqliteAdapterConfig\n): SqliteAdapter {\n return new SqliteAdapter(config);\n}\n\n/**\n * Type guard to check if a value is a SqliteAdapter.\n *\n * @param value - Value to check\n * @returns True if value is a SqliteAdapter instance\n *\n * @example\n * ```typescript\n * if (isSqliteAdapter(adapter)) {\n * // TypeScript knows adapter is SqliteAdapter\n * console.log('Using SQLite');\n * }\n * ```\n */\nexport function isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return value instanceof SqliteAdapter;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextlyhq/adapter-sqlite",
|
|
3
|
-
"version": "0.0.2-alpha.
|
|
3
|
+
"version": "0.0.2-alpha.60",
|
|
4
4
|
"description": "SQLite database adapter for Nextly - extends @nextlyhq/adapter-drizzle",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,25 +18,25 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"engines": {
|
|
21
|
-
"node": "
|
|
21
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"better-sqlite3": "^12.5.0",
|
|
25
|
-
"drizzle-orm": "
|
|
26
|
-
"@nextlyhq/adapter-drizzle": "0.0.2-alpha.
|
|
25
|
+
"drizzle-orm": "1.0.0-rc.4",
|
|
26
|
+
"@nextlyhq/adapter-drizzle": "0.0.2-alpha.60"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/better-sqlite3": "^7.6.
|
|
30
|
-
"@vitest/coverage-v8": "^4.0
|
|
31
|
-
"@vitest/ui": "^4.0
|
|
29
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
30
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
31
|
+
"@vitest/ui": "^4.1.0",
|
|
32
32
|
"better-sqlite3": "^12.5.0",
|
|
33
|
-
"eslint": "^9.
|
|
33
|
+
"eslint": "^9.39.1",
|
|
34
34
|
"tsup": "^8.5.0",
|
|
35
35
|
"typescript": "^5.9.3",
|
|
36
36
|
"vite-tsconfig-paths": "^5.1.4",
|
|
37
|
-
"vitest": "^4.0
|
|
38
|
-
"@nextlyhq/eslint-config": "0.0.2-alpha.
|
|
39
|
-
"@nextlyhq/tsconfig": "0.0.2-alpha.
|
|
37
|
+
"vitest": "^4.1.0",
|
|
38
|
+
"@nextlyhq/eslint-config": "0.0.2-alpha.60",
|
|
39
|
+
"@nextlyhq/tsconfig": "0.0.2-alpha.60"
|
|
40
40
|
},
|
|
41
41
|
"keywords": [
|
|
42
42
|
"nextly",
|