@happyvertical/sql 0.80.4 → 0.80.6
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/chunks/{duckdb-DykBBzd6.js → duckdb-D_Wu36JL.js} +43 -48
- package/dist/chunks/duckdb-D_Wu36JL.js.map +1 -0
- package/dist/chunks/{sqlite-YgU9LCVy.js → sqlite-B4ussRTS.js} +76 -54
- package/dist/chunks/sqlite-B4ussRTS.js.map +1 -0
- package/dist/chunks/{sqlite-native-BGtpx7Ro.js → sqlite-native-BgiF4301.js} +34 -6
- package/dist/chunks/{sqlite-native-BGtpx7Ro.js.map → sqlite-native-BgiF4301.js.map} +1 -1
- package/dist/duckdb.d.ts.map +1 -1
- package/dist/index.js +109 -51
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/shared/types.d.ts +59 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/sqlite.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/chunks/duckdb-DykBBzd6.js.map +0 -1
- package/dist/chunks/sqlite-YgU9LCVy.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as buildWhere, r as formatDbError, t as DatabaseSchemaManager } from "./schema-manager-a8RlxIE2.js";
|
|
2
2
|
import { t as convertUniqueIndexesToInlineConstraints } from "./duckdb-schema-utils-B-XBP8QF.js";
|
|
3
3
|
import { a as validateTableName, i as validateIndexName, n as generateCreateIndexStatement, r as validateColumnName, t as generateAddColumnStatement } from "./alter-utils-K7tiuj5L.js";
|
|
4
|
-
import { resolveSchemas } from "../index.js";
|
|
4
|
+
import { NestedTransactionError, resolveSchemas } from "../index.js";
|
|
5
5
|
import { DatabaseError } from "@happyvertical/utils";
|
|
6
6
|
import { readdir } from "node:fs/promises";
|
|
7
7
|
import { basename, extname, join } from "node:path";
|
|
@@ -935,60 +935,27 @@ async function getDatabase(options = {}) {
|
|
|
935
935
|
const transaction = async (callback) => {
|
|
936
936
|
try {
|
|
937
937
|
await connection.run("BEGIN TRANSACTION");
|
|
938
|
-
const result = await callback(
|
|
939
|
-
url,
|
|
940
|
-
client: connection,
|
|
941
|
-
insert,
|
|
942
|
-
get,
|
|
943
|
-
list,
|
|
944
|
-
update,
|
|
945
|
-
upsert,
|
|
946
|
-
getOrInsert,
|
|
947
|
-
delete: deleteRecords,
|
|
948
|
-
count,
|
|
949
|
-
table,
|
|
950
|
-
many,
|
|
951
|
-
single,
|
|
952
|
-
pluck,
|
|
953
|
-
execute,
|
|
954
|
-
query,
|
|
955
|
-
oo,
|
|
956
|
-
oO,
|
|
957
|
-
ox,
|
|
958
|
-
xx,
|
|
959
|
-
tableExists,
|
|
960
|
-
syncSchema,
|
|
961
|
-
transaction
|
|
962
|
-
});
|
|
938
|
+
const result = await callback(createTransactionScope());
|
|
963
939
|
await connection.run("COMMIT");
|
|
964
940
|
return result;
|
|
965
941
|
} catch (error) {
|
|
966
|
-
|
|
942
|
+
try {
|
|
943
|
+
await connection.run("ROLLBACK");
|
|
944
|
+
} catch {}
|
|
967
945
|
throw error;
|
|
968
946
|
}
|
|
969
947
|
};
|
|
970
948
|
/**
|
|
971
|
-
*
|
|
949
|
+
* Builds the transaction-scoped interface handed to a transaction callback.
|
|
972
950
|
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
951
|
+
* The only difference from the top-level interface is `transaction`, which
|
|
952
|
+
* refuses to nest. DuckDB has no SAVEPOINT, so there is no way to re-enter
|
|
953
|
+
* the transaction already in progress; re-exposing the top-level
|
|
954
|
+
* `transaction` (the previous behaviour) sent the nested call into a second
|
|
955
|
+
* BEGIN on the same connection, which throws and then rolls back the
|
|
956
|
+
* *enclosing* transaction, silently discarding its work.
|
|
977
957
|
*/
|
|
978
|
-
const
|
|
979
|
-
await connection.run("BEGIN TRANSACTION");
|
|
980
|
-
let active = true;
|
|
981
|
-
const commit = async () => {
|
|
982
|
-
if (!active) throw new DatabaseError("Transaction already ended", {});
|
|
983
|
-
await connection.run("COMMIT");
|
|
984
|
-
active = false;
|
|
985
|
-
};
|
|
986
|
-
const rollback = async () => {
|
|
987
|
-
if (!active) throw new DatabaseError("Transaction already ended", {});
|
|
988
|
-
await connection.run("ROLLBACK");
|
|
989
|
-
active = false;
|
|
990
|
-
};
|
|
991
|
-
const isActive = () => active;
|
|
958
|
+
const createTransactionScope = () => {
|
|
992
959
|
return {
|
|
993
960
|
url,
|
|
994
961
|
client: connection,
|
|
@@ -1012,7 +979,35 @@ async function getDatabase(options = {}) {
|
|
|
1012
979
|
xx,
|
|
1013
980
|
tableExists,
|
|
1014
981
|
syncSchema,
|
|
1015
|
-
transaction
|
|
982
|
+
transaction: async () => {
|
|
983
|
+
throw new NestedTransactionError("Nested transactions are not supported by this adapter because its engine has no SAVEPOINT. Pass the existing transaction to the callee instead of opening a new one.", { adapter: "duckdb" });
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
};
|
|
987
|
+
/**
|
|
988
|
+
* Begins a new transaction and returns a handle for manual control
|
|
989
|
+
*
|
|
990
|
+
* Unlike transaction(), this gives you explicit control over commit/rollback.
|
|
991
|
+
* Ideal for test isolation where you want to rollback after each test.
|
|
992
|
+
*
|
|
993
|
+
* @returns Promise resolving to a TransactionHandle
|
|
994
|
+
*/
|
|
995
|
+
const beginTransaction = async () => {
|
|
996
|
+
await connection.run("BEGIN TRANSACTION");
|
|
997
|
+
let active = true;
|
|
998
|
+
const commit = async () => {
|
|
999
|
+
if (!active) throw new DatabaseError("Transaction already ended", {});
|
|
1000
|
+
await connection.run("COMMIT");
|
|
1001
|
+
active = false;
|
|
1002
|
+
};
|
|
1003
|
+
const rollback = async () => {
|
|
1004
|
+
if (!active) throw new DatabaseError("Transaction already ended", {});
|
|
1005
|
+
await connection.run("ROLLBACK");
|
|
1006
|
+
active = false;
|
|
1007
|
+
};
|
|
1008
|
+
const isActive = () => active;
|
|
1009
|
+
return {
|
|
1010
|
+
...createTransactionScope(),
|
|
1016
1011
|
commit,
|
|
1017
1012
|
rollback,
|
|
1018
1013
|
isActive
|
|
@@ -1053,4 +1048,4 @@ async function getDatabase(options = {}) {
|
|
|
1053
1048
|
//#endregion
|
|
1054
1049
|
export { getDatabase };
|
|
1055
1050
|
|
|
1056
|
-
//# sourceMappingURL=duckdb-
|
|
1051
|
+
//# sourceMappingURL=duckdb-D_Wu36JL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duckdb-D_Wu36JL.js","names":[],"sources":["../../src/duckdb.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { basename, extname, join } from 'node:path';\nimport { DatabaseError } from '@happyvertical/utils';\nimport { DatabaseSchemaManager } from './schema-manager';\nimport {\n generateAddColumnStatement,\n generateCreateIndexStatement,\n validateColumnName,\n validateIndexName,\n validateTableName,\n} from './shared/alter-utils';\nimport { convertUniqueIndexesToInlineConstraints } from './shared/duckdb-schema-utils';\nimport type {\n ColumnDefinition,\n ColumnDefinitionWithName,\n DatabaseInterface,\n DuckDBOptions,\n IndexDefinition,\n QueryResult,\n SchemaInitializationOptions,\n TableInterface,\n TableSchemaInfo,\n TransactionHandle,\n UpsertOptions,\n} from './shared/types';\nimport { NestedTransactionError, resolveSchemas } from './shared/types';\nimport { buildWhere, formatDbError } from './shared/utils';\n\n/**\n * Creates tables from provided schema definitions\n *\n * DuckDB has a known limitation (issue #12684) where ON CONFLICT clauses\n * fail with UNIQUE INDEX but work with inline UNIQUE constraints.\n * This function converts UNIQUE indexes to inline constraints for compatibility.\n *\n * @param connection - DuckDB connection\n * @param schemas - Schema definitions to create\n */\nasync function createTablesFromSchemas(\n connection: any,\n schemas: Record<string, import('./shared/types').SchemaProvider>,\n): Promise<void> {\n for (const [tableName, schema] of Object.entries(schemas)) {\n try {\n // Check if table already exists\n const result = await connection.runAndReadAll(\n `SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}'`,\n );\n const rows = result.getRowObjects();\n\n if (rows.length > 0) {\n console.log(`[duckdb] Table ${tableName} already exists, skipping`);\n continue;\n }\n\n console.log(`[duckdb] Creating table ${tableName} from provided schema`);\n\n // Convert UNIQUE indexes to inline UNIQUE constraints for DuckDB compatibility\n // DuckDB's ON CONFLICT requires inline constraints, not separate indexes\n const transformed = convertUniqueIndexesToInlineConstraints(\n schema.ddl,\n schema.indexes,\n );\n\n // Create table from transformed DDL\n await connection.run(transformed.ddl);\n\n // Create remaining indexes (non-UNIQUE indexes only)\n // UNIQUE indexes have been converted to inline constraints\n if (transformed.indexes && transformed.indexes.length > 0) {\n for (const indexSQL of transformed.indexes) {\n try {\n await connection.run(indexSQL);\n } catch (error) {\n console.warn(\n `[duckdb] Failed to create index for ${tableName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n\n // Create triggers (if supported)\n if (schema.triggers && schema.triggers.length > 0) {\n for (const triggerSQL of schema.triggers) {\n try {\n await connection.run(triggerSQL);\n } catch (error) {\n console.warn(\n `[duckdb] Failed to create trigger for ${tableName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n } catch (error) {\n throw new DatabaseError(\n `Failed to create table ${tableName} from schema`,\n {\n tableName,\n schema,\n originalError: error instanceof Error ? error.message : String(error),\n },\n );\n }\n }\n}\n\n/**\n * Resolves a DuckDB URL, handling :memory: variants to prevent file leakage.\n *\n * DuckDB interprets any string as a file path unless it's exactly ':memory:'.\n * URLs like ':memory:12345' create files named ':memory:12345' in the working directory.\n *\n * This function:\n * - Returns ':memory:' unchanged (pure in-memory database)\n * - Converts ':memory:*' patterns to temp files in os.tmpdir()\n * - Returns other URLs unchanged (file paths, etc.)\n *\n * @param url - The database URL to resolve\n * @returns The resolved URL safe for DuckDB\n */\nfunction resolveDuckDBUrl(url: string): string {\n // Pure in-memory: use as-is\n if (url === ':memory:') {\n return url;\n }\n\n // Pattern: :memory: followed by anything (e.g., :memory:12345-0.5678)\n // These would create files in CWD - redirect to temp directory instead\n if (url.startsWith(':memory:')) {\n const suffix = url.slice(':memory:'.length);\n const tempPath = join(tmpdir(), `duckdb-memory-${suffix}.db`);\n return tempPath;\n }\n\n // Other URLs (file paths, etc.): use as-is\n return url;\n}\n\n/**\n * Creates a DuckDB connection instance\n *\n * @param options - DuckDB connection options\n * @returns Promise resolving to a DuckDB connection\n */\nasync function createDuckDBConnection(options: DuckDBOptions) {\n const {\n url = ':memory:',\n dataDir = './data',\n autoRegisterJSON = true,\n } = options;\n const schemas = resolveSchemas(options.schemas) ?? {};\n\n // Resolve URL to prevent file leakage from :memory:* patterns\n const resolvedUrl = resolveDuckDBUrl(url);\n\n try {\n // Dynamic import to avoid bundling\n const duckdbModule = '@duckdb/node-api';\n const { DuckDBInstance } = await import(/* @vite-ignore */ duckdbModule);\n\n // Create DuckDB instance with resolved URL\n const instance = await DuckDBInstance.create(resolvedUrl);\n const connection = await instance.connect();\n\n // Create tables from provided schemas first\n if (schemas && Object.keys(schemas).length > 0) {\n await createTablesFromSchemas(connection, schemas);\n }\n\n // Auto-register JSON files if enabled\n if (autoRegisterJSON && dataDir) {\n await registerJSONFiles(connection, dataDir);\n }\n\n return connection;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new DatabaseError(\n `Failed to create DuckDB connection: ${errorMessage}`,\n {\n url,\n originalError: errorMessage,\n },\n );\n }\n}\n\n/**\n * Scans the data directory and registers JSON files as queryable tables\n *\n * @param connection - DuckDB connection\n * @param dataDir - Directory containing JSON files\n */\nasync function registerJSONFiles(connection: any, dataDir: string) {\n try {\n const files = await readdir(dataDir);\n const jsonFiles = files.filter(\n (file) => extname(file).toLowerCase() === '.json',\n );\n\n for (const file of jsonFiles) {\n const filePath = join(dataDir, file);\n const tableName = basename(file, '.json');\n\n // Create view that reads from JSON file\n // DuckDB automatically infers schema with ISO date/timestamp parsing\n await connection.run(\n `CREATE OR REPLACE VIEW ${tableName} AS SELECT * FROM read_json('${filePath}', auto_detect=true, format='auto', timestampformat='iso', dateformat='iso')`,\n );\n }\n } catch (error) {\n // If directory doesn't exist, that's okay - user might not have JSON files yet\n if ((error as any).code !== 'ENOENT') {\n throw new DatabaseError(`Failed to register JSON files from ${dataDir}`, {\n dataDir,\n originalError: error instanceof Error ? error.message : String(error),\n });\n }\n }\n}\n\n/**\n * Converts DuckDB-specific type representations to JavaScript types\n *\n * Handles two cases:\n * 1. JavaScript BigInt values → converted to numbers\n * 2. DuckDB timestamp objects ({ micros: number }) → converted to Date objects\n *\n * DuckDB represents TIMESTAMP values as objects with a single property\n * called 'micros' containing microseconds since Unix epoch. This function\n * converts them to JavaScript Date objects for proper serialization.\n *\n * @param obj - Object that may contain BigInt or timestamp values\n * @returns Object with DuckDB types converted to JavaScript types\n */\nfunction convertBigInts(obj: any): any {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj === 'bigint') return Number(obj);\n\n // Handle DuckDB timestamp objects: { micros: number | bigint }\n // Convert to JavaScript Date for proper serialization\n // Fixes issue #314: DuckDB returns dates as { micros } objects\n if (\n typeof obj === 'object' &&\n !Array.isArray(obj) &&\n 'micros' in obj &&\n Object.keys(obj).length === 1 &&\n (typeof obj.micros === 'number' || typeof obj.micros === 'bigint')\n ) {\n // Convert microseconds to milliseconds for Date constructor\n // DuckDB stores timestamps as microseconds since Unix epoch\n // Handle both number and bigint types (DuckDB can return either)\n const micros =\n typeof obj.micros === 'bigint' ? Number(obj.micros) : obj.micros;\n const milliseconds = micros / 1000;\n return new Date(milliseconds);\n }\n\n if (Array.isArray(obj)) return obj.map(convertBigInts);\n if (typeof obj === 'object') {\n const result: any = {};\n for (const key in obj) {\n result[key] = convertBigInts(obj[key]);\n }\n return result;\n }\n return obj;\n}\n\n/**\n * Creates a DuckDB database adapter\n *\n * @param options - DuckDB connection options\n * @returns Database interface for DuckDB\n */\nexport async function getDatabase(\n options: DuckDBOptions = {},\n): Promise<DatabaseInterface> {\n const connection = await createDuckDBConnection(options);\n const writeStrategy = options.writeStrategy || 'none';\n const dataDir = options.dataDir || './data';\n // Use resolved URL to reflect actual database location\n const url = resolveDuckDBUrl(options.url || ':memory:');\n\n /**\n * Inserts one or more records into a table\n *\n * @param table - Table name\n * @param data - Single record or array of records to insert\n * @returns Promise resolving to operation result\n * @throws Error if the insert operation fails\n */\n const insert = async (\n table: string,\n data: Record<string, any> | Record<string, any>[],\n ): Promise<QueryResult> => {\n const records = Array.isArray(data) ? data : [data];\n\n if (records.length === 0) {\n return { operation: 'insert', affected: 0 };\n }\n\n const keys = Object.keys(records[0]);\n const values: any[] = [];\n let paramIdx = 1;\n\n // Build placeholders with proper type casting for DuckDB\n const placeholders = records\n .map((record) => {\n const rowPlaceholders = keys.map((key) => {\n const value = record[key];\n\n if (value === null || value === undefined) {\n return 'NULL';\n } else if (value === '' && typeof value === 'string') {\n // CAST empty strings to TEXT to prevent DuckDB ANY type inference\n values.push(value);\n return `CAST($${paramIdx++} AS TEXT)`;\n } else if (value instanceof Date) {\n // Convert Date objects to ISO strings for DuckDB\n values.push(value.toISOString());\n return `$${paramIdx++}`;\n } else if (Array.isArray(value)) {\n // CAST arrays to JSON to prevent DuckDB ANY type inference\n values.push(JSON.stringify(value));\n return `CAST($${paramIdx++} AS JSON)`;\n } else if (\n typeof value === 'object' &&\n value !== null &&\n Object.getPrototypeOf(value) === Object.prototype\n ) {\n // CAST plain objects to JSON to prevent DuckDB ANY type inference\n values.push(JSON.stringify(value));\n return `CAST($${paramIdx++} AS JSON)`;\n } else {\n // Direct parameter binding for other values\n values.push(value);\n return `$${paramIdx++}`;\n }\n });\n return `(${rowPlaceholders.join(', ')})`;\n })\n .join(', ');\n\n const sql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES ${placeholders}`;\n\n try {\n await connection.run(sql, values);\n const affected = records.length;\n\n // Handle write-back strategy\n if (writeStrategy === 'immediate') {\n await exportTableToJSON(connection, table, dataDir);\n }\n\n return { operation: 'insert', affected };\n } catch (e) {\n throw new DatabaseError('Failed to insert records into table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Retrieves a single record matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records\n * @returns Promise resolving to matching record or null if not found\n * @throws Error if the query fails\n */\n const get = async (\n table: string,\n where: Record<string, any>,\n ): Promise<Record<string, any> | null> => {\n const { sql: whereClause, values } = buildWhere(where, 1, 'duckdb');\n const sql = `SELECT * FROM ${table} ${whereClause} LIMIT 1`;\n\n try {\n const reader = await connection.runAndReadAll(sql, values);\n const rows = reader.getRowObjects();\n return rows.length > 0 ? convertBigInts(rows[0]) : null;\n } catch (e) {\n throw new DatabaseError('Failed to retrieve record from table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Retrieves multiple records matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records\n * @returns Promise resolving to array of matching records\n * @throws Error if the query fails\n */\n const list = async (\n table: string,\n where: Record<string, any>,\n ): Promise<Record<string, any>[]> => {\n const { sql: whereClause, values } = buildWhere(where, 1, 'duckdb');\n const sql = `SELECT * FROM ${table} ${whereClause}`;\n\n try {\n const reader = await connection.runAndReadAll(sql, values);\n return convertBigInts(reader.getRowObjects());\n } catch (e) {\n throw new DatabaseError('Failed to list records from table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Updates records matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records to update\n * @param data - New data to set\n * @returns Promise resolving to operation result\n * @throws Error if the update operation fails\n */\n const update = async (\n table: string,\n where: Record<string, any>,\n data: Record<string, any>,\n ): Promise<QueryResult> => {\n const keys = Object.keys(data);\n const setClause = keys.map((key, idx) => `${key} = $${idx + 1}`).join(', ');\n const { sql: whereClause, values: whereValues } = buildWhere(\n where,\n keys.length + 1,\n 'duckdb',\n );\n\n const sql = `UPDATE ${table} SET ${setClause} ${whereClause}`;\n const values = [...Object.values(data), ...whereValues];\n\n try {\n await connection.run(sql, values);\n\n // Handle write-back strategy\n if (writeStrategy === 'immediate') {\n await exportTableToJSON(connection, table, dataDir);\n }\n\n // DuckDB doesn't return rowsAffected in the same way, estimate from where clause\n return { operation: 'update', affected: 1 };\n } catch (e) {\n throw new DatabaseError('Failed to update records in table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n const buildDuckDBValueExpression = (\n value: any,\n values: any[],\n paramIdx: { value: number },\n ): string => {\n if (value === null || value === undefined) {\n return 'NULL';\n }\n if (value === '' && typeof value === 'string') {\n values.push(value);\n return `CAST($${paramIdx.value++} AS TEXT)`;\n }\n if (value instanceof Date) {\n values.push(value.toISOString());\n return `$${paramIdx.value++}`;\n }\n if (Array.isArray(value)) {\n values.push(JSON.stringify(value));\n return `CAST($${paramIdx.value++} AS JSON)`;\n }\n if (\n typeof value === 'object' &&\n value !== null &&\n Object.getPrototypeOf(value) === Object.prototype\n ) {\n values.push(JSON.stringify(value));\n return `CAST($${paramIdx.value++} AS JSON)`;\n }\n\n values.push(value);\n return `$${paramIdx.value++}`;\n };\n\n const executeNullAwareDuckDBUpsert = async (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n ): Promise<QueryResult> => {\n const conflictWhere = Object.fromEntries(\n conflictColumns.map((col) => [col, data[col]]),\n );\n const existing = await get(table, conflictWhere);\n\n if (!existing) {\n return insert(table, data);\n }\n\n const keys = Object.keys(data);\n const values: any[] = [];\n const paramIdx = { value: 1 };\n const assignments = keys.map((key) => {\n const valueExpr = buildDuckDBValueExpression(data[key], values, paramIdx);\n return `\"${key}\" = ${valueExpr}`;\n });\n const { sql: whereClause, values: whereValues } = buildWhere(\n conflictWhere,\n paramIdx.value,\n 'duckdb',\n );\n const sql = `UPDATE ${table} SET ${assignments.join(', ')} ${whereClause}`;\n\n try {\n await connection.run(sql, [...values, ...whereValues]);\n\n if (writeStrategy === 'immediate') {\n await exportTableToJSON(connection, table, dataDir);\n }\n\n return { operation: 'upsert', affected: 1 };\n } catch (e) {\n throw new DatabaseError('Failed to upsert record into table', {\n table,\n sql,\n values: [...values, ...whereValues],\n conflictColumns,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Inserts a record or updates it if it already exists (UPSERT)\n *\n * @param table - Table name\n * @param conflictColumns - Columns that define the uniqueness constraint\n * @param data - Data to insert or update\n * @returns Promise resolving to operation result\n * @throws Error if the upsert operation fails\n */\n const upsert = async (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n options?: UpsertOptions,\n ): Promise<QueryResult> => {\n // Validate that all conflict columns are present in the data\n const missingColumns = conflictColumns.filter((col) => !(col in data));\n\n if (missingColumns.length > 0) {\n throw new DatabaseError('Conflict columns missing from data', {\n table,\n conflictColumns,\n missingColumns,\n availableColumns: Object.keys(data),\n hint: 'All columns specified in ON CONFLICT must be present in the data being inserted. Undefined values should be replaced with null or an appropriate default.',\n });\n }\n\n if (\n !options?.nullsDistinct &&\n conflictColumns.some((col) => data[col] === null)\n ) {\n return executeNullAwareDuckDBUpsert(table, conflictColumns, data);\n }\n\n const keys = Object.keys(data);\n const dataValues = Object.values(data);\n\n // Build placeholders and values with proper type handling for DuckDB\n // DuckDB cannot infer types from empty strings or certain values, so we need explicit CAST\n const placeholders: string[] = [];\n const values: any[] = [];\n let paramIdx = 1;\n\n for (const value of dataValues) {\n if (value === null || value === undefined) {\n // DuckDB requires explicit NULL for null/undefined values\n placeholders.push('NULL');\n } else if (value === '' && typeof value === 'string') {\n // CAST empty strings to TEXT to prevent DuckDB ANY type inference\n placeholders.push(`CAST($${paramIdx} AS TEXT)`);\n values.push(value);\n paramIdx++;\n } else if (value instanceof Date) {\n // Convert Date objects to ISO strings for DuckDB\n placeholders.push(`$${paramIdx}`);\n values.push(value.toISOString());\n paramIdx++;\n } else if (Array.isArray(value)) {\n // CAST arrays to JSON to prevent DuckDB ANY type inference\n // DuckDB cannot infer array element types from empty arrays or mixed types\n placeholders.push(`CAST($${paramIdx} AS JSON)`);\n values.push(JSON.stringify(value));\n paramIdx++;\n } else if (\n typeof value === 'object' &&\n value !== null &&\n Object.getPrototypeOf(value) === Object.prototype\n ) {\n // CAST plain objects to JSON to prevent DuckDB ANY type inference\n // Only applies to plain objects (not class instances)\n placeholders.push(`CAST($${paramIdx} AS JSON)`);\n values.push(JSON.stringify(value));\n paramIdx++;\n } else {\n // Direct parameter binding for other values\n placeholders.push(`$${paramIdx}`);\n values.push(value);\n paramIdx++;\n }\n }\n\n // Build UPDATE SET clause with same type handling\n // DO NOT reset paramIdx - parameters must be unique across entire query\n const updateSetParts: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n const value = dataValues[i];\n\n if (value === null || value === undefined) {\n // DuckDB requires explicit NULL for null/undefined values\n updateSetParts.push(`${key} = NULL`);\n } else if (value === '' && typeof value === 'string') {\n updateSetParts.push(`${key} = CAST($${paramIdx} AS TEXT)`);\n values.push(value);\n paramIdx++;\n } else if (value instanceof Date) {\n updateSetParts.push(`${key} = $${paramIdx}`);\n values.push(value.toISOString());\n paramIdx++;\n } else if (Array.isArray(value)) {\n // CAST arrays to JSON to prevent DuckDB ANY type inference\n updateSetParts.push(`${key} = CAST($${paramIdx} AS JSON)`);\n values.push(JSON.stringify(value));\n paramIdx++;\n } else if (\n typeof value === 'object' &&\n value !== null &&\n Object.getPrototypeOf(value) === Object.prototype\n ) {\n // CAST plain objects to JSON to prevent DuckDB ANY type inference\n updateSetParts.push(`${key} = CAST($${paramIdx} AS JSON)`);\n values.push(JSON.stringify(value));\n paramIdx++;\n } else {\n updateSetParts.push(`${key} = $${paramIdx}`);\n values.push(value);\n paramIdx++;\n }\n }\n\n // Quote ALL column names to match DuckDB's schema generation\n // SchemaGenerator always quotes column names, so UPSERT must match\n const conflict = conflictColumns.map((col) => `\"${col}\"`).join(', ');\n const quotedKeys = keys.map((key) => `\"${key}\"`).join(', ');\n\n // Quote column names in UPDATE SET clause to match schema and ON CONFLICT\n // Extract the value expression from each updateSetPart (everything after '=')\n const quotedUpdateSetParts = keys.map((key, i) => {\n const part = updateSetParts[i];\n const valueExpr = part.substring(part.indexOf('=') + 1).trim();\n return `\"${key}\" = ${valueExpr}`;\n });\n\n const sql = `INSERT INTO ${table} (${quotedKeys}) VALUES (${placeholders.join(', ')}) ON CONFLICT(${conflict}) DO UPDATE SET ${quotedUpdateSetParts.join(', ')}`;\n\n try {\n await connection.run(sql, values);\n\n // Handle write-back strategy\n if (writeStrategy === 'immediate') {\n await exportTableToJSON(connection, table, dataDir);\n }\n\n return { operation: 'upsert', affected: 1 };\n } catch (e) {\n throw new DatabaseError('Failed to upsert record into table', {\n table,\n sql,\n values,\n conflictColumns,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Gets a record matching the where criteria or inserts it if not found\n *\n * @param table - Table name\n * @param where - Criteria to match existing record\n * @param data - Data to insert if no record found\n * @returns Promise resolving to the record (either retrieved or newly inserted)\n * @throws Error if the operation fails\n */\n const getOrInsert = async (\n table: string,\n where: Record<string, any>,\n data: Record<string, any>,\n ): Promise<Record<string, any>> => {\n const result = await get(table, where);\n if (result) return result;\n\n await insert(table, data);\n const inserted = await get(table, where);\n\n if (!inserted) {\n throw new DatabaseError('Failed to insert and retrieve record', {\n table,\n where,\n data,\n });\n }\n\n return inserted;\n };\n\n /**\n * Deletes records from a table matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records for deletion\n * @returns Promise resolving to operation result with count of deleted rows\n * @throws Error if the delete operation fails\n */\n const deleteRecords = async (\n table: string,\n where: Record<string, any>,\n ): Promise<QueryResult> => {\n validateTableName(table);\n\n const keys = Object.keys(where);\n if (keys.length === 0) {\n throw new DatabaseError(\n 'DELETE requires at least one WHERE condition to prevent accidental deletion of all records',\n { table },\n );\n }\n\n const { sql: whereClause, values } = buildWhere(where, 1, 'duckdb');\n const sql = `DELETE FROM ${table} ${whereClause}`;\n\n try {\n await connection.run(sql, values);\n\n // Handle write-back strategy\n if (writeStrategy === 'immediate') {\n await exportTableToJSON(connection, table, dataDir);\n }\n\n return { operation: 'delete', affected: 1 };\n } catch (e) {\n throw new DatabaseError('Failed to delete records from table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Counts records in a table matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records (optional, counts all if omitted)\n * @returns Promise resolving to count of matching records\n * @throws Error if the count operation fails\n */\n const count = async (\n table: string,\n where?: Record<string, any>,\n ): Promise<number> => {\n validateTableName(table);\n\n try {\n if (!where || Object.keys(where).length === 0) {\n // Count all records\n const result = await connection.runAndReadAll(\n `SELECT COUNT(*) as count FROM ${table}`,\n );\n const rows = result.getRowObjects();\n return Number(rows[0]?.count) || 0;\n }\n\n // Count with conditions\n const { sql: whereClause, values } = buildWhere(where, 1, 'duckdb');\n const sql = `SELECT COUNT(*) as count FROM ${table} ${whereClause}`;\n\n const result = await connection.runAndReadAll(sql, values);\n const rows = result.getRowObjects();\n\n return Number(rows[0]?.count) || 0;\n } catch (e) {\n throw new DatabaseError('Failed to count records in table', {\n table,\n where,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Checks if a table exists in the database\n *\n * @param tableName - Name of the table to check\n * @returns Promise resolving to boolean indicating if the table exists\n */\n const tableExists = async (tableName: string): Promise<boolean> => {\n try {\n // Try to query the table - simpler and works for both tables and views\n await connection.runAndReadAll(`SELECT * FROM ${tableName} LIMIT 1`);\n return true;\n } catch {\n return false;\n }\n };\n\n /**\n * Exports a table to a JSON file (for write-back strategies)\n *\n * @param connection - DuckDB connection\n * @param table - Table name\n * @param dataDir - Directory to write JSON file\n */\n const exportTableToJSON = async (\n connection: any,\n table: string,\n dataDir: string,\n ): Promise<void> => {\n const filePath = join(dataDir, `${table}.json`);\n await connection.run(\n `COPY (SELECT * FROM ${table}) TO '${filePath}' (FORMAT JSON, ARRAY true)`,\n );\n };\n\n /**\n * Manual export method for 'manual' write strategy\n *\n * @param table - Table name to export\n * @returns Promise that resolves when export completes\n */\n const exportTable = async (table: string): Promise<void> => {\n if (writeStrategy === 'none') {\n throw new DatabaseError(\n 'Cannot export table: write strategy is set to none',\n { table, writeStrategy },\n );\n }\n await exportTableToJSON(connection, table, dataDir);\n };\n\n /**\n * Creates a table-specific interface for simplified table operations\n *\n * @param tableName - Table name\n * @returns TableInterface for the specified table\n */\n const table = (tableName: string): TableInterface => ({\n insert: (data) => insert(tableName, data),\n get: (where) => get(tableName, where),\n list: (where) => list(tableName, where),\n });\n\n /**\n * Parses a tagged template literal into a SQL query and values\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Object with SQL query and values array\n */\n const parseTemplate = (strings: TemplateStringsArray, ...vars: any[]) => {\n let sql = strings[0];\n const values = [];\n for (let i = 0; i < vars.length; i++) {\n values.push(vars[i]);\n sql += `$${i + 1}${strings[i + 1]}`;\n }\n return { sql, values };\n };\n\n /**\n * Executes a SQL query using template literals and returns multiple rows\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to array of result records\n * @throws Error if the query fails\n */\n const many = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<Record<string, any>[]> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const reader = await connection.runAndReadAll(sql, values);\n return convertBigInts(reader.getRowObjects());\n } catch (e) {\n throw new DatabaseError('Failed to execute many query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals and returns a single row\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to a single result record or null\n * @throws Error if the query fails\n */\n const single = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<Record<string, any> | null> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const reader = await connection.runAndReadAll(sql, values);\n const rows = reader.getRowObjects();\n return rows[0] ? convertBigInts(rows[0]) : null;\n } catch (e) {\n throw new DatabaseError('Failed to execute single query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals and returns a single value\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to a single value (first column of first row)\n * @throws Error if the query fails\n */\n const pluck = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<any> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const reader = await connection.runAndReadAll(sql, values);\n const rows = reader.getRowObjects();\n if (rows.length === 0) return null;\n const firstRow = rows[0];\n const firstKey = Object.keys(firstRow)[0];\n return convertBigInts(firstRow[firstKey]);\n } catch (e) {\n throw new DatabaseError('Failed to execute pluck query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals without returning results\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise that resolves when the query completes\n * @throws Error if the query fails\n */\n const execute = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<void> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n await connection.run(sql, values);\n } catch (e) {\n throw new DatabaseError('Failed to execute query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a raw SQL query with parameterized values\n *\n * @param str - SQL query string\n * @param values - Variables to use as parameters\n * @returns Promise resolving to query result with rows and metadata\n * @throws Error if the query fails\n */\n const query = async (str: string, ...values: any[]) => {\n const sql = str;\n const args = Array.isArray(values[0]) ? values[0] : values;\n\n try {\n const reader = await connection.runAndReadAll(sql, args);\n const rows = convertBigInts(reader.getRowObjects());\n\n return {\n command: sql.split(' ')[0].toUpperCase(),\n rowCount: rows.length,\n oid: null,\n fields:\n rows.length > 0\n ? Object.keys(rows[0]).map((name) => ({\n name,\n tableID: 0,\n columnID: 0,\n dataTypeID: 0,\n dataTypeSize: -1,\n dataTypeModifier: -1,\n format: 'text',\n }))\n : [],\n rows,\n };\n } catch (e) {\n throw new DatabaseError('Failed to execute raw query', {\n sql,\n args,\n originalError: formatDbError(e),\n });\n }\n };\n\n // Shorthand aliases for query methods\n const oo = many; // (o)bjective-(o)bjects: returns multiple rows\n const oO = single; // (o)bjective-(O)bject: returns a single row\n const ox = pluck; // (o)bjective-(x): returns a single value\n const xx = execute; // e(x)ecute-e(x)ecute: executes without returning\n\n /**\n * Synchronizes database schema with provided SQL DDL\n *\n * DuckDB requires UNIQUE constraints to be defined **inline** in CREATE TABLE\n * statements for ON CONFLICT clauses to work. This method automatically\n * transforms UNIQUE indexes to inline constraints before executing the schema.\n *\n * @param schema - SQL schema definition with CREATE TABLE and CREATE INDEX statements\n * @returns Promise that resolves when schema is synchronized\n */\n const syncSchema = async (schema: string): Promise<void> => {\n const statements = schema\n .trim()\n .split(';')\n .filter((stmt) => stmt.trim() !== '');\n\n const createTableStatements: string[] = [];\n const indexStatements: string[] = [];\n\n // Separate CREATE TABLE from CREATE INDEX statements\n for (const stmt of statements) {\n const trimmed = stmt.trim();\n if (!trimmed) continue;\n\n if (\n trimmed.startsWith('CREATE INDEX') ||\n trimmed.startsWith('CREATE UNIQUE INDEX')\n ) {\n indexStatements.push(trimmed);\n } else if (trimmed.startsWith('CREATE TABLE')) {\n createTableStatements.push(trimmed);\n }\n }\n\n // Process each CREATE TABLE statement\n for (const ddl of createTableStatements) {\n // Transform UNIQUE indexes to inline constraints for DuckDB compatibility\n const { ddl: transformedDDL, indexes: remainingIndexes } =\n convertUniqueIndexesToInlineConstraints(ddl, indexStatements);\n\n // Execute transformed DDL\n try {\n await connection.run(transformedDDL);\n } catch (e) {\n console.error('Schema sync error (CREATE TABLE):', e);\n }\n\n // Execute remaining (non-UNIQUE) indexes for this table\n for (const indexSQL of remainingIndexes) {\n try {\n await connection.run(indexSQL);\n } catch (e) {\n console.error('Schema sync error (CREATE INDEX):', e);\n }\n }\n }\n };\n\n /**\n * Initialize database schemas from JSON manifest\n * Supports dependency resolution and schema overrides\n *\n * @param options - Schema initialization options\n * @returns Promise that resolves when schemas are initialized\n */\n const initializeSchemas = async (\n options: SchemaInitializationOptions,\n ): Promise<void> => {\n const schemaManager = new DatabaseSchemaManager();\n const currentDb: DatabaseInterface = {\n url,\n client: connection,\n query,\n insert,\n update,\n upsert,\n get,\n list,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n tableExists,\n many,\n single,\n pluck,\n execute,\n oo,\n oO,\n ox,\n xx,\n syncSchema,\n };\n\n await schemaManager.initializeSchemas(currentDb, options);\n };\n\n /**\n * Retrieves the schema information for a table\n *\n * @param table - Table name\n * @returns Promise resolving to table schema info or null if table doesn't exist\n * @throws Error if the query fails\n */\n const getTableSchema = async (\n table: string,\n ): Promise<TableSchemaInfo | null> => {\n validateTableName(table);\n\n try {\n // Check if table exists\n const exists = await tableExists(table);\n if (!exists) {\n return null;\n }\n\n // Get column information from information_schema\n const columnRows = await many`\n SELECT\n column_name,\n data_type,\n is_nullable,\n column_default\n FROM information_schema.columns\n WHERE table_name = ${table}\n ORDER BY ordinal_position\n `;\n\n // Get primary key columns from DuckDB system tables\n const pkRows = await many`\n SELECT column_name\n FROM duckdb_constraints() con\n JOIN duckdb_columns() cols\n ON con.table_oid = cols.table_oid\n WHERE con.table_name = ${table}\n AND con.constraint_type = 'PRIMARY KEY'\n AND cols.column_name = ANY(con.constraint_column_names)\n `;\n\n const pkColumns = new Set(pkRows.map((row) => row.column_name));\n\n const columns: Record<string, ColumnDefinition> = {};\n for (const row of columnRows) {\n const colName = row.column_name as string;\n columns[colName] = {\n type: row.data_type as string,\n primaryKey: pkColumns.has(colName),\n notNull: row.is_nullable === 'NO',\n defaultValue: row.column_default,\n };\n }\n\n // Get index information from duckdb_indexes()\n const indexRows = await many`\n SELECT\n index_name,\n sql\n FROM duckdb_indexes()\n WHERE table_name = ${table}\n AND NOT is_primary\n `;\n\n const indexes: IndexDefinition[] = [];\n for (const row of indexRows) {\n const indexName = row.index_name as string;\n const indexDef = (row.sql as string) || '';\n\n // Parse column names from index definition\n const colMatch = indexDef.match(/\\(([^)]+)\\)/);\n const indexColumns = colMatch\n ? colMatch[1].split(',').map((col) => col.trim())\n : [];\n\n const isUnique = indexDef.toUpperCase().includes('UNIQUE');\n\n indexes.push({\n name: indexName,\n columns: indexColumns,\n unique: isUnique,\n });\n }\n\n // Get foreign key information\n const fkRows = await many`\n SELECT\n constraint_column_names,\n constraint_column_indexes,\n constraint_text\n FROM duckdb_constraints()\n WHERE table_name = ${table}\n AND constraint_type = 'FOREIGN KEY'\n `;\n\n const foreignKeys: Array<{\n column: string;\n referencesTable: string;\n referencesColumn: string;\n onDelete?: string;\n onUpdate?: string;\n }> = [];\n\n for (const fkRow of fkRows) {\n // Parse foreign key constraint text to extract referenced table and column\n const fkText = (fkRow.constraint_text as string) || '';\n const referencesMatch = fkText.match(\n /REFERENCES\\s+(\\w+)\\s*\\(([^)]+)\\)/i,\n );\n\n if (\n referencesMatch &&\n Array.isArray(fkRow.constraint_column_names) &&\n fkRow.constraint_column_names.length > 0\n ) {\n const columnName = fkRow.constraint_column_names[0];\n const referencedTable = referencesMatch[1];\n const referencedColumn = referencesMatch[2].trim();\n\n const onDeleteMatch = fkText.match(/ON DELETE\\s+(\\w+)/i);\n const onUpdateMatch = fkText.match(/ON UPDATE\\s+(\\w+)/i);\n\n foreignKeys.push({\n column: columnName,\n referencesTable: referencedTable,\n referencesColumn: referencedColumn,\n onDelete: onDeleteMatch ? onDeleteMatch[1] : undefined,\n onUpdate: onUpdateMatch ? onUpdateMatch[1] : undefined,\n });\n }\n }\n\n return {\n tableName: table,\n columns,\n indexes,\n foreignKeys,\n };\n } catch (e) {\n throw new DatabaseError('Failed to retrieve table schema', {\n table,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * ALTER TABLE operations for schema evolution\n */\n const alterTable = {\n /**\n * Adds a new column to an existing table\n *\n * @param table - Table name\n * @param column - Column definition with name\n * @returns Promise that resolves when column is added\n * @throws Error if the alter operation fails\n */\n addColumn: async (\n table: string,\n column: ColumnDefinitionWithName,\n ): Promise<void> => {\n validateTableName(table);\n validateColumnName(column.name);\n\n try {\n const sql = generateAddColumnStatement(table, column, 'duckdb');\n await connection.run(sql);\n } catch (e) {\n throw new DatabaseError('Failed to add column to table', {\n table,\n column: column.name,\n originalError: formatDbError(e),\n });\n }\n },\n\n /**\n * Adds a new index to an existing table\n *\n * @param table - Table name\n * @param index - Index definition\n * @returns Promise that resolves when index is created\n * @throws Error if the create index operation fails\n */\n addIndex: async (table: string, index: IndexDefinition): Promise<void> => {\n validateTableName(table);\n validateIndexName(index.name);\n\n for (const col of index.columns) {\n validateColumnName(col);\n }\n\n try {\n const sql = generateCreateIndexStatement(table, index);\n await connection.run(sql);\n } catch (e) {\n throw new DatabaseError('Failed to create index on table', {\n table,\n index: index.name,\n originalError: formatDbError(e),\n });\n }\n },\n };\n\n /**\n * Executes a callback within a database transaction\n * Automatically commits on success or rolls back on error\n *\n * @param callback - Function to execute within transaction\n * @returns Promise resolving to callback result\n */\n const transaction = async <T>(\n callback: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> => {\n try {\n await connection.run('BEGIN TRANSACTION');\n\n const result = await callback(createTransactionScope());\n await connection.run('COMMIT');\n return result;\n } catch (error) {\n // A failing ROLLBACK must not replace the caller's error: DuckDB reports\n // \"cannot rollback - no transaction is active\" whenever the transaction\n // is already gone, which says nothing about what actually failed.\n try {\n await connection.run('ROLLBACK');\n } catch {\n // Nothing left to roll back.\n }\n throw error;\n }\n };\n\n /**\n * Builds the transaction-scoped interface handed to a transaction callback.\n *\n * The only difference from the top-level interface is `transaction`, which\n * refuses to nest. DuckDB has no SAVEPOINT, so there is no way to re-enter\n * the transaction already in progress; re-exposing the top-level\n * `transaction` (the previous behaviour) sent the nested call into a second\n * BEGIN on the same connection, which throws and then rolls back the\n * *enclosing* transaction, silently discarding its work.\n */\n const createTransactionScope = (): DatabaseInterface => {\n const txDb: DatabaseInterface = {\n url,\n client: connection,\n insert,\n get,\n list,\n update,\n upsert,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n many,\n single,\n pluck,\n execute,\n query,\n oo,\n oO,\n ox,\n xx,\n tableExists,\n syncSchema,\n transaction: async () => {\n throw new NestedTransactionError(\n 'Nested transactions are not supported by this adapter because its engine has no SAVEPOINT. Pass the existing transaction to the callee instead of opening a new one.',\n { adapter: 'duckdb' },\n );\n },\n };\n\n return txDb;\n };\n\n /**\n * Begins a new transaction and returns a handle for manual control\n *\n * Unlike transaction(), this gives you explicit control over commit/rollback.\n * Ideal for test isolation where you want to rollback after each test.\n *\n * @returns Promise resolving to a TransactionHandle\n */\n const beginTransaction = async (): Promise<TransactionHandle> => {\n await connection.run('BEGIN TRANSACTION');\n\n let active = true;\n\n const commit = async (): Promise<void> => {\n if (!active) {\n throw new DatabaseError('Transaction already ended', {});\n }\n await connection.run('COMMIT');\n active = false;\n };\n\n const rollback = async (): Promise<void> => {\n if (!active) {\n throw new DatabaseError('Transaction already ended', {});\n }\n await connection.run('ROLLBACK');\n active = false;\n };\n\n const isActive = (): boolean => active;\n\n // Create a transaction-scoped database interface with commit/rollback.\n // The handle is inside a transaction for the same reason a callback\n // scope is, so it gets the same non-nesting `transaction`.\n const txHandle: TransactionHandle = {\n ...createTransactionScope(),\n commit,\n rollback,\n isActive,\n };\n\n return txHandle;\n };\n\n return {\n url,\n requiresSchemaCheck: true,\n client: connection,\n query,\n insert,\n update,\n upsert,\n get,\n list,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n tableExists,\n many,\n single,\n pluck,\n execute,\n oo,\n oO,\n ox,\n xx,\n syncSchema,\n initializeSchemas,\n transaction,\n beginTransaction,\n getTableSchema,\n alterTable,\n // DuckDB-specific export method\n exportTable,\n } as DatabaseInterface & { exportTable: (table: string) => Promise<void> };\n}\n"],"mappings":"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"}
|
|
@@ -131,7 +131,7 @@ async function createTablesFromSchemas(client, schemas) {
|
|
|
131
131
|
async function getDatabase(options = {}) {
|
|
132
132
|
const url = options.url || ":memory:";
|
|
133
133
|
if (url === ":memory:" && !options.dbid) options.dbid = generateDbId();
|
|
134
|
-
if (hasNativeSqliteCapabilities(options)) return (await import("./sqlite-native-
|
|
134
|
+
if (hasNativeSqliteCapabilities(options)) return (await import("./sqlite-native-BgiF4301.js")).getNativeSqliteDatabase(options);
|
|
135
135
|
if (options.dbid) {
|
|
136
136
|
const cached = memoryConnectionCache.get(options.dbid);
|
|
137
137
|
if (cached) return cached;
|
|
@@ -403,6 +403,7 @@ async function getDatabase(options = {}) {
|
|
|
403
403
|
});
|
|
404
404
|
}
|
|
405
405
|
};
|
|
406
|
+
let savepointSequence = 0;
|
|
406
407
|
const upsertInCurrentTransaction = async (table, conflictColumns, data, options) => {
|
|
407
408
|
try {
|
|
408
409
|
return await executeUpsert(table, conflictColumns, data, options, false);
|
|
@@ -585,45 +586,88 @@ async function getDatabase(options = {}) {
|
|
|
585
586
|
sql: "BEGIN TRANSACTION",
|
|
586
587
|
args: []
|
|
587
588
|
});
|
|
588
|
-
const result = await callback(
|
|
589
|
-
url,
|
|
590
|
-
client,
|
|
591
|
-
insert,
|
|
592
|
-
get,
|
|
593
|
-
list,
|
|
594
|
-
update,
|
|
595
|
-
upsert: upsertInCurrentTransaction,
|
|
596
|
-
getOrInsert,
|
|
597
|
-
delete: deleteRecords,
|
|
598
|
-
count,
|
|
599
|
-
table,
|
|
600
|
-
many,
|
|
601
|
-
single,
|
|
602
|
-
pluck,
|
|
603
|
-
execute,
|
|
604
|
-
query,
|
|
605
|
-
oo: many,
|
|
606
|
-
oO: single,
|
|
607
|
-
ox: pluck,
|
|
608
|
-
xx: execute,
|
|
609
|
-
tableExists,
|
|
610
|
-
syncSchema,
|
|
611
|
-
transaction
|
|
612
|
-
});
|
|
589
|
+
const result = await callback(createTransactionScope());
|
|
613
590
|
await client.execute({
|
|
614
591
|
sql: "COMMIT",
|
|
615
592
|
args: []
|
|
616
593
|
});
|
|
617
594
|
return result;
|
|
618
595
|
} catch (error) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
596
|
+
try {
|
|
597
|
+
await client.execute({
|
|
598
|
+
sql: "ROLLBACK",
|
|
599
|
+
args: []
|
|
600
|
+
});
|
|
601
|
+
} catch {}
|
|
623
602
|
throw error;
|
|
624
603
|
}
|
|
625
604
|
};
|
|
626
605
|
/**
|
|
606
|
+
* Builds the transaction-scoped interface handed to a transaction callback.
|
|
607
|
+
*
|
|
608
|
+
* The only difference from the top-level interface is `transaction`: this
|
|
609
|
+
* one re-enters the transaction already in progress under a savepoint
|
|
610
|
+
* instead of issuing a second BEGIN. SQLite shares one connection, so the
|
|
611
|
+
* old behaviour of re-exposing the top-level `transaction` sent a nested
|
|
612
|
+
* call into `BEGIN` on a connection that was already in a transaction; that
|
|
613
|
+
* throws, and the nested call's own ROLLBACK then discarded the *enclosing*
|
|
614
|
+
* transaction's work while later writes silently committed in autocommit.
|
|
615
|
+
*/
|
|
616
|
+
const createTransactionScope = () => {
|
|
617
|
+
return {
|
|
618
|
+
url,
|
|
619
|
+
client,
|
|
620
|
+
insert,
|
|
621
|
+
get,
|
|
622
|
+
list,
|
|
623
|
+
update,
|
|
624
|
+
upsert: upsertInCurrentTransaction,
|
|
625
|
+
getOrInsert,
|
|
626
|
+
delete: deleteRecords,
|
|
627
|
+
count,
|
|
628
|
+
table,
|
|
629
|
+
many,
|
|
630
|
+
single,
|
|
631
|
+
pluck,
|
|
632
|
+
execute,
|
|
633
|
+
query,
|
|
634
|
+
oo: many,
|
|
635
|
+
oO: single,
|
|
636
|
+
ox: pluck,
|
|
637
|
+
xx: execute,
|
|
638
|
+
tableExists,
|
|
639
|
+
syncSchema,
|
|
640
|
+
transaction: async (callback) => {
|
|
641
|
+
savepointSequence += 1;
|
|
642
|
+
const name = `hv_sp_${savepointSequence}`;
|
|
643
|
+
await client.execute({
|
|
644
|
+
sql: `SAVEPOINT ${name}`,
|
|
645
|
+
args: []
|
|
646
|
+
});
|
|
647
|
+
try {
|
|
648
|
+
const result = await callback(createTransactionScope());
|
|
649
|
+
await client.execute({
|
|
650
|
+
sql: `RELEASE SAVEPOINT ${name}`,
|
|
651
|
+
args: []
|
|
652
|
+
});
|
|
653
|
+
return result;
|
|
654
|
+
} catch (error) {
|
|
655
|
+
try {
|
|
656
|
+
await client.execute({
|
|
657
|
+
sql: `ROLLBACK TO SAVEPOINT ${name}`,
|
|
658
|
+
args: []
|
|
659
|
+
});
|
|
660
|
+
await client.execute({
|
|
661
|
+
sql: `RELEASE SAVEPOINT ${name}`,
|
|
662
|
+
args: []
|
|
663
|
+
});
|
|
664
|
+
} catch {}
|
|
665
|
+
throw error;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
};
|
|
670
|
+
/**
|
|
627
671
|
* Begins a new transaction and returns a handle for manual control
|
|
628
672
|
*
|
|
629
673
|
* Unlike transaction(), this gives you explicit control over commit/rollback.
|
|
@@ -655,29 +699,7 @@ async function getDatabase(options = {}) {
|
|
|
655
699
|
};
|
|
656
700
|
const isActive = () => active;
|
|
657
701
|
return {
|
|
658
|
-
|
|
659
|
-
client,
|
|
660
|
-
insert,
|
|
661
|
-
get,
|
|
662
|
-
list,
|
|
663
|
-
update,
|
|
664
|
-
upsert: upsertInCurrentTransaction,
|
|
665
|
-
getOrInsert,
|
|
666
|
-
delete: deleteRecords,
|
|
667
|
-
count,
|
|
668
|
-
table,
|
|
669
|
-
many,
|
|
670
|
-
single,
|
|
671
|
-
pluck,
|
|
672
|
-
execute,
|
|
673
|
-
query,
|
|
674
|
-
oo: many,
|
|
675
|
-
oO: single,
|
|
676
|
-
ox: pluck,
|
|
677
|
-
xx: execute,
|
|
678
|
-
tableExists,
|
|
679
|
-
syncSchema,
|
|
680
|
-
transaction,
|
|
702
|
+
...createTransactionScope(),
|
|
681
703
|
commit,
|
|
682
704
|
rollback,
|
|
683
705
|
isActive
|
|
@@ -1042,4 +1064,4 @@ async function getDatabase(options = {}) {
|
|
|
1042
1064
|
//#endregion
|
|
1043
1065
|
export { getDatabase };
|
|
1044
1066
|
|
|
1045
|
-
//# sourceMappingURL=sqlite-
|
|
1067
|
+
//# sourceMappingURL=sqlite-B4ussRTS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-B4ussRTS.js","names":[],"sources":["../../src/sqlite.ts"],"sourcesContent":["import { DatabaseError } from '@happyvertical/utils';\nimport type { Client } from '@libsql/client';\nimport { DatabaseSchemaManager } from './schema-manager';\nimport {\n generateAddColumnStatement,\n generateCreateIndexStatement,\n validateColumnName,\n validateIndexName,\n validateTableName,\n} from './shared/alter-utils';\nimport type {\n ColumnDefinition,\n ColumnDefinitionWithName,\n DatabaseInterface,\n IndexDefinition,\n QueryResult,\n SchemaInitializationOptions,\n SqliteCapabilitiesOptions,\n TableInterface,\n TableSchemaInfo,\n TransactionHandle,\n UpsertOptions,\n} from './shared/types';\nimport { resolveSchemas } from './shared/types';\nimport { buildWhere, formatDbError } from './shared/utils';\n\n/**\n * Connection cache for in-memory databases with memoryId\n * Enables sharing of :memory: databases across multiple getDatabase() calls\n */\nconst memoryConnectionCache = new Map<string, DatabaseInterface>();\n\n/**\n * Pending connection promises to handle concurrent getDatabase() calls\n * Prevents creating duplicate connections when parallel calls happen\n */\nconst pendingConnections = new Map<string, Promise<DatabaseInterface>>();\nconst NULL_AWARE_UPSERT_MAX_ATTEMPTS = 8;\nconst NULL_AWARE_UPSERT_BASE_DELAY_MS = 25;\nconst nullAwareUpsertLocks = new Map<string, Promise<void>>();\n\ntype SqliteExecutor = Pick<Client, 'execute'>;\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetriableSqliteTransactionError(error: unknown): boolean {\n const formatted = formatDbError(error).toLowerCase();\n return (\n formatted.includes('busy') ||\n formatted.includes('locked') ||\n formatted.includes('database is locked')\n );\n}\n\nasync function withNullAwareUpsertLock<T>(\n lockKey: string,\n callback: () => Promise<T>,\n): Promise<T> {\n const previous = nullAwareUpsertLocks.get(lockKey) ?? Promise.resolve();\n let release: () => void = () => {};\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const next = previous.catch(() => {}).then(() => current);\n\n nullAwareUpsertLocks.set(lockKey, next);\n await previous.catch(() => {});\n\n try {\n return await callback();\n } finally {\n release();\n\n if (nullAwareUpsertLocks.get(lockKey) === next) {\n nullAwareUpsertLocks.delete(lockKey);\n }\n }\n}\n\n/**\n * Generates a unique identifier for in-memory databases\n * @returns A unique database identifier string\n */\nfunction generateDbId(): string {\n return `memory-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Creates a LibSQL client using the default client implementation\n * Supports in-memory databases and remote LibSQL URLs\n *\n * @param options - SQLite connection options\n * @returns Promise resolving to a LibSQL client instance\n */\nasync function createLibSQLClient(options: SqliteOptions): Promise<Client> {\n const { url = ':memory:', authToken, encryptionKey } = options;\n\n // Normalize URLs: add file:// prefix for local paths\n let libsqlUrl = url;\n if (\n url !== ':memory:' &&\n !url.startsWith('http://') &&\n !url.startsWith('https://') &&\n !url.startsWith('libsql://') &&\n !url.startsWith('file:')\n ) {\n // Local file path - resolve to absolute and add file:// prefix\n const { resolve } = await import('node:path');\n const absolutePath = resolve(url);\n // Use file:// format (file URL scheme with authority component omitted)\n libsqlUrl = `file://${absolutePath}`;\n }\n\n try {\n // Use explicit external import to avoid bundling\n const libsqlClient = '@libsql/client';\n const { createClient } = await import(/* @vite-ignore */ libsqlClient);\n return createClient({ url: libsqlUrl, authToken, encryptionKey });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Provide helpful error messages for common issues\n if (errorMessage?.includes('URL_SCHEME_NOT_SUPPORTED')) {\n throw new DatabaseError(\n `Unsupported URL scheme. Use ':memory:' for in-memory databases or 'libsql://' for remote LibSQL databases. Original: ${url}, Converted: ${libsqlUrl}`,\n { url: libsqlUrl, originalError: errorMessage },\n );\n }\n\n // Re-throw other errors with context\n throw new DatabaseError(`Failed to create LibSQL client: ${errorMessage}`, {\n url: libsqlUrl,\n originalError: errorMessage,\n });\n }\n}\n\n/**\n * Configuration options for SQLite database connections\n */\nexport interface SqliteOptions {\n /**\n * Connection URL for SQLite database\n * Supported schemes:\n * - ':memory:' for in-memory databases\n * - 'file:path/to/database.db' for local file databases\n * - 'libsql://...' for remote LibSQL/Turso databases\n */\n url?: string;\n\n /**\n * Authentication token for Turso/LibSQL remote connections\n */\n authToken?: string;\n\n /**\n * Encryption key for encrypted SQLite databases (LibSQL feature)\n */\n encryptionKey?: string;\n\n /**\n * Unique identifier for in-memory databases to enable connection sharing\n * When multiple getDatabase() calls use the same dbid, they receive\n * the same database connection instance.\n *\n * Auto-generated for :memory: databases if not provided.\n */\n dbid?: string;\n\n /**\n * Optional native SQLite capabilities for local development and testing.\n *\n * When any capability is enabled, the adapter uses the internal native\n * SQLite implementation instead of the LibSQL client path. Native\n * capabilities are only supported for local SQLite databases.\n */\n capabilities?: SqliteCapabilitiesOptions;\n\n /**\n * Schema definitions for tables.\n * Accepts a record or a lazy function (see SchemasOption).\n *\n * When provided, these schemas will be used for table creation.\n * Accepts a lazy function to defer schema building until needed.\n */\n schemas?: import('./shared/types').SchemasOption;\n}\n\nfunction hasNativeSqliteCapabilities(options: SqliteOptions): boolean {\n return Boolean(\n options.capabilities?.notifications || options.capabilities?.vector,\n );\n}\n\n/**\n * Creates tables from provided schema definitions\n *\n * @param client - LibSQL client\n * @param schemas - Schema definitions to create\n */\nasync function createTablesFromSchemas(\n client: any,\n schemas: Record<string, import('./shared/types').SchemaProvider>,\n): Promise<void> {\n for (const [tableName, schema] of Object.entries(schemas)) {\n try {\n // Check if table already exists\n const result = await client.execute({\n sql: `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,\n args: [tableName],\n });\n\n if (result.rows.length > 0) {\n console.log(`[sqlite] Table ${tableName} already exists, skipping`);\n continue;\n }\n\n console.log(`[sqlite] Creating table ${tableName} from provided schema`);\n\n // Create table from DDL\n await client.execute(schema.ddl);\n\n // Create indexes\n if (schema.indexes && schema.indexes.length > 0) {\n for (const indexSQL of schema.indexes) {\n try {\n await client.execute(indexSQL);\n } catch (error) {\n console.warn(\n `[sqlite] Failed to create index for ${tableName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n\n // Create triggers (if supported)\n if (schema.triggers && schema.triggers.length > 0) {\n for (const triggerSQL of schema.triggers) {\n try {\n await client.execute(triggerSQL);\n } catch (error) {\n console.warn(\n `[sqlite] Failed to create trigger for ${tableName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n }\n } catch (error) {\n console.error(\n `[sqlite] Error creating table ${tableName}:`,\n error instanceof Error ? error.message : String(error),\n );\n console.error(`[sqlite] DDL was:`, schema.ddl?.substring(0, 200) + '...');\n throw new DatabaseError(\n `Failed to create table ${tableName} from schema: ${error instanceof Error ? error.message : String(error)}`,\n {\n tableName,\n schema,\n originalError: error instanceof Error ? error.message : String(error),\n },\n );\n }\n }\n}\n\n/**\n * Creates a SQLite database adapter\n *\n * @param options - SQLite connection options\n * @returns Database interface for SQLite\n */\nexport async function getDatabase(\n options: SqliteOptions = {},\n): Promise<DatabaseInterface> {\n const url = options.url || ':memory:';\n\n // Auto-generate dbid for :memory: databases if not provided\n // Mutate options object to ensure child objects reuse the same connection\n if (url === ':memory:' && !options.dbid) {\n options.dbid = generateDbId();\n }\n\n if (hasNativeSqliteCapabilities(options)) {\n const sqliteNative = await import('./sqlite-native.js');\n return sqliteNative.getNativeSqliteDatabase(options);\n }\n\n // Check if we have a cached connection for this dbid\n if (options.dbid) {\n const cached = memoryConnectionCache.get(options.dbid);\n if (cached) {\n return cached;\n }\n\n // Check if there's a pending connection for this dbid\n const pending = pendingConnections.get(options.dbid);\n if (pending) {\n return pending;\n }\n }\n\n // Create a new connection promise\n const connectionPromise = (async () => {\n const client = await createLibSQLClient(options);\n\n // Initialize tables from provided schemas (resolves lazy function if needed)\n const resolvedSchemas = resolveSchemas(options.schemas);\n if (resolvedSchemas && Object.keys(resolvedSchemas).length > 0) {\n await createTablesFromSchemas(client, resolvedSchemas);\n }\n\n /**\n * Serializes a value for SQLite storage\n * Converts objects and arrays to JSON strings\n * Converts Dates to ISO strings\n * Passes through primitives unchanged\n */\n const serializeValue = (value: any): any => {\n if (value === null || value === undefined) {\n return value;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n return value;\n };\n\n /**\n * Serializes all values in an object\n */\n const serializeRecord = (\n record: Record<string, any>,\n ): Record<string, any> => {\n const serialized: Record<string, any> = {};\n for (const [key, value] of Object.entries(record)) {\n // Skip undefined values - they cannot be passed to the database\n if (value === undefined) {\n continue;\n }\n serialized[key] = serializeValue(value);\n }\n return serialized;\n };\n\n const hasNullConflictValue = (\n conflictColumns: string[],\n data: Record<string, any>,\n ): boolean => conflictColumns.some((col) => data[col] === null);\n\n const buildNullAwareUpsertLockKey = (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n ): string => {\n const conflictValues = conflictColumns\n .map((col) => `${col}:${JSON.stringify(data[col])}`)\n .join('|');\n return `${url}:${table}:${conflictValues}`;\n };\n\n const validateUpsertConflictColumns = (\n table: string,\n conflictColumns: string[],\n serializedData: Record<string, any>,\n ): void => {\n const missingColumns = conflictColumns.filter(\n (col) => !(col in serializedData),\n );\n\n if (missingColumns.length > 0) {\n throw new DatabaseError('Conflict columns missing from data', {\n table,\n conflictColumns,\n missingColumns,\n availableColumns: Object.keys(serializedData),\n hint: 'All columns specified in ON CONFLICT must be present in the data being inserted. Undefined values are filtered out during serialization - consider using null or an empty string instead.',\n });\n }\n };\n\n const executeStandardUpsert = async (\n table: string,\n conflictColumns: string[],\n serializedData: Record<string, any>,\n ): Promise<QueryResult> => {\n const keys = Object.keys(serializedData);\n const values = Object.values(serializedData);\n const placeholders = keys.map(() => '?').join(', ');\n const updateSet = keys\n .map((key) => `${key} = excluded.${key}`)\n .join(', ');\n const conflict = conflictColumns.join(', ');\n const sql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES (${placeholders}) ON CONFLICT(${conflict}) DO UPDATE SET ${updateSet}`;\n\n const result = await client.execute({ sql, args: values });\n return { operation: 'upsert', affected: result.rowsAffected };\n };\n\n const executeNullAwareUpsertAttempt = async (\n executor: SqliteExecutor,\n table: string,\n conflictColumns: string[],\n serializedData: Record<string, any>,\n ): Promise<QueryResult> => {\n const keys = Object.keys(serializedData);\n const values = Object.values(serializedData);\n const updateSet = keys.map((key) => `${key} = ?`).join(', ');\n const whereClause = conflictColumns\n .map((col) => `${col} IS ?`)\n .join(' AND ');\n const whereValues = conflictColumns.map((col) => serializedData[col]);\n\n const updateSql = `UPDATE ${table} SET ${updateSet} WHERE ${whereClause}`;\n const updateResult = await executor.execute({\n sql: updateSql,\n args: [...values, ...whereValues],\n });\n\n if ((updateResult.rowsAffected ?? 0) > 0) {\n return { operation: 'upsert', affected: updateResult.rowsAffected };\n }\n\n const placeholders = keys.map(() => '?').join(', ');\n const insertSql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES (${placeholders})`;\n const insertResult = await executor.execute({\n sql: insertSql,\n args: values,\n });\n\n return { operation: 'upsert', affected: insertResult.rowsAffected };\n };\n\n const executeNullAwareUpsertWithRetry = async (\n table: string,\n conflictColumns: string[],\n serializedData: Record<string, any>,\n ): Promise<QueryResult> => {\n if (url === ':memory:') {\n return executeNullAwareUpsertAttempt(\n client,\n table,\n conflictColumns,\n serializedData,\n );\n }\n\n let lastError: unknown;\n\n for (\n let attempt = 0;\n attempt < NULL_AWARE_UPSERT_MAX_ATTEMPTS;\n attempt++\n ) {\n let transaction: Awaited<ReturnType<Client['transaction']>> | undefined;\n\n try {\n transaction = await client.transaction('write');\n\n const result = await executeNullAwareUpsertAttempt(\n transaction,\n table,\n conflictColumns,\n serializedData,\n );\n\n await transaction.commit();\n return result;\n } catch (error) {\n lastError = error;\n\n if (transaction && !transaction.closed) {\n try {\n await transaction.rollback();\n } catch (_rollbackError) {\n // Preserve the original failure; rollback errors are secondary here.\n }\n }\n } finally {\n transaction?.close();\n }\n\n if (\n lastError &&\n attempt < NULL_AWARE_UPSERT_MAX_ATTEMPTS - 1 &&\n isRetriableSqliteTransactionError(lastError)\n ) {\n await delay(NULL_AWARE_UPSERT_BASE_DELAY_MS * 2 ** attempt);\n continue;\n }\n\n break;\n }\n\n throw lastError;\n };\n\n const executeUpsert = async (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n options: UpsertOptions | undefined,\n acquireTransaction: boolean,\n ): Promise<QueryResult> => {\n const serializedData = serializeRecord(data);\n validateUpsertConflictColumns(table, conflictColumns, serializedData);\n\n if (\n options?.nullsDistinct ||\n !hasNullConflictValue(conflictColumns, serializedData)\n ) {\n return executeStandardUpsert(table, conflictColumns, serializedData);\n }\n\n if (!acquireTransaction) {\n return executeNullAwareUpsertAttempt(\n client,\n table,\n conflictColumns,\n serializedData,\n );\n }\n\n return withNullAwareUpsertLock(\n buildNullAwareUpsertLockKey(table, conflictColumns, serializedData),\n () =>\n executeNullAwareUpsertWithRetry(\n table,\n conflictColumns,\n serializedData,\n ),\n );\n };\n\n /**\n * Inserts one or more records into a table\n *\n * @param table - Table name\n * @param data - Single record or array of records to insert\n * @returns Promise resolving to operation result\n * @throws Error if the insert operation fails\n */\n const insert = async (\n table: string,\n data: Record<string, any> | Record<string, any>[],\n ): Promise<QueryResult> => {\n let sql: string;\n let values: any[];\n\n if (Array.isArray(data)) {\n // Serialize all records in the array\n const serializedRecords: Array<Record<string, any>> = data.map(\n (record) => serializeRecord(record),\n );\n const keys = Object.keys(serializedRecords[0]);\n const placeholders = serializedRecords\n .map(() => `(${keys.map(() => '?').join(', ')})`)\n .join(', ');\n sql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES ${placeholders}`;\n // Flatten all values into a single array for batch insert\n const flattenedValues: any[] = [];\n for (const record of serializedRecords) {\n flattenedValues.push(...Object.values(record));\n }\n values = flattenedValues;\n } else {\n // Serialize the single record\n const serializedData = serializeRecord(data);\n const keys = Object.keys(serializedData);\n const placeholders = keys.map(() => '?').join(', ');\n sql = `INSERT INTO ${table} (${keys.join(', ')}) VALUES (${placeholders})`;\n values = Object.values(serializedData);\n }\n try {\n const result = await client.execute({ sql: sql, args: values });\n return { operation: 'insert', affected: result.rowsAffected };\n } catch (e) {\n throw new DatabaseError('Failed to insert records into table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Retrieves a single record matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records\n * @returns Promise resolving to matching record or null if not found\n * @throws Error if the query fails\n */\n const get = async (\n table: string,\n where: Record<string, any>,\n ): Promise<Record<string, any> | null> => {\n const { sql: whereClause, values } = buildWhere(where, 1, 'sqlite');\n if (!whereClause) {\n throw new DatabaseError(\n 'GET requires at least one WHERE condition to prevent returning an arbitrary record',\n { table },\n );\n }\n\n const sql = `SELECT * FROM ${table} ${whereClause}`;\n try {\n const result = await client.execute({ sql: sql, args: values });\n return result.rows[0] || null;\n } catch (e) {\n throw new DatabaseError('Failed to retrieve record from table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Retrieves multiple records matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records\n * @returns Promise resolving to array of matching records\n * @throws Error if the query fails\n */\n const list = async (\n table: string,\n where: Record<string, any>,\n ): Promise<Record<string, any>[]> => {\n const { sql: whereClause, values } = buildWhere(where, 1, 'sqlite');\n const sql = `SELECT * FROM ${table} ${whereClause}`;\n try {\n const result = await client.execute({ sql, args: values });\n return result.rows;\n } catch (e) {\n throw new DatabaseError('Failed to list records from table', {\n table,\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Updates records matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records to update\n * @param data - New data to set\n * @returns Promise resolving to operation result\n * @throws Error if the update operation fails\n */\n const update = async (\n table: string,\n where: Record<string, any>,\n data: Record<string, any>,\n ): Promise<QueryResult> => {\n // Serialize the data to update\n const serializedData = serializeRecord(data);\n const keys = Object.keys(serializedData);\n const values = Object.values(serializedData);\n const setClause = keys.map((key, i) => `${key} = $${i + 1}`).join(', ');\n const { sql: whereClause, values: whereValues } = buildWhere(\n where,\n values.length + 1,\n 'sqlite',\n );\n if (!whereClause) {\n throw new DatabaseError(\n 'UPDATE requires at least one WHERE condition to prevent accidental update of all records',\n { table },\n );\n }\n\n const sql = `UPDATE ${table} SET ${setClause} ${whereClause}`;\n try {\n const result = await client.execute({\n sql,\n args: [...values, ...whereValues],\n });\n return { operation: 'update', affected: result.rowsAffected };\n } catch (e) {\n throw new DatabaseError('Failed to update records in table', {\n table,\n sql,\n values: [...values, ...whereValues],\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Inserts a record or updates it if it already exists (UPSERT)\n *\n * @param table - Table name\n * @param conflictColumns - Columns that define the uniqueness constraint\n * @param data - Data to insert or update\n * @returns Promise resolving to operation result\n * @throws Error if the upsert operation fails\n */\n const upsert = async (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n options?: UpsertOptions,\n ): Promise<QueryResult> => {\n try {\n return await executeUpsert(table, conflictColumns, data, options, true);\n } catch (e) {\n if (\n e instanceof DatabaseError &&\n e.message === 'Conflict columns missing from data'\n ) {\n throw e;\n }\n\n throw new DatabaseError('Failed to upsert record into table', {\n table,\n values: data,\n conflictColumns,\n originalError: formatDbError(e),\n });\n }\n };\n\n // Names nested savepoints. Only ever appended to an identifier the adapter\n // generates, never caller input.\n let savepointSequence = 0;\n\n const upsertInCurrentTransaction = async (\n table: string,\n conflictColumns: string[],\n data: Record<string, any>,\n options?: UpsertOptions,\n ): Promise<QueryResult> => {\n try {\n return await executeUpsert(\n table,\n conflictColumns,\n data,\n options,\n false,\n );\n } catch (e) {\n if (\n e instanceof DatabaseError &&\n e.message === 'Conflict columns missing from data'\n ) {\n throw e;\n }\n\n throw new DatabaseError('Failed to upsert record into table', {\n table,\n values: data,\n conflictColumns,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Gets a record matching the where criteria or inserts it if not found\n *\n * @param table - Table name\n * @param where - Criteria to match existing record\n * @param data - Data to insert if no record found\n * @returns Promise resolving to the record (either retrieved or newly inserted)\n * @throws Error if the operation fails or if the record cannot be retrieved after insert\n */\n const getOrInsert = async (\n table: string,\n where: Record<string, any>,\n data: Record<string, any>,\n ): Promise<Record<string, any>> => {\n const result = await get(table, where);\n if (result) return result;\n await insert(table, data);\n\n const inserted = await get(table, where);\n if (!inserted) {\n throw new DatabaseError('Failed to insert and retrieve record', {\n table,\n where,\n data,\n });\n }\n return inserted;\n };\n\n /**\n * Deletes records from a table matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records for deletion\n * @returns Promise resolving to operation result with count of deleted rows\n * @throws Error if the delete operation fails\n */\n const deleteRecords = async (\n table: string,\n where: Record<string, any>,\n ): Promise<QueryResult> => {\n validateTableName(table);\n\n const keys = Object.keys(where);\n if (keys.length === 0) {\n throw new DatabaseError(\n 'DELETE requires at least one WHERE condition to prevent accidental deletion of all records',\n { table },\n );\n }\n\n const { sql: whereClause, values } = buildWhere(where, 1, 'sqlite');\n\n try {\n await client.execute({\n sql: `DELETE FROM ${table} ${whereClause}`,\n args: values,\n });\n\n // SQLite doesn't reliably return affected rows, so we can't provide an exact count\n return { operation: 'delete', affected: 1 };\n } catch (e) {\n throw new DatabaseError('Failed to delete records from table', {\n table,\n where,\n originalError: e,\n });\n }\n };\n\n /**\n * Counts records in a table matching the where criteria\n *\n * @param table - Table name\n * @param where - Criteria to match records (optional, counts all if omitted)\n * @returns Promise resolving to count of matching records\n * @throws Error if the count operation fails\n */\n const count = async (\n table: string,\n where?: Record<string, any>,\n ): Promise<number> => {\n validateTableName(table);\n\n try {\n if (!where || Object.keys(where).length === 0) {\n // Count all records\n const result = await pluck`SELECT COUNT(*) FROM ${table}`;\n return Number(result) || 0;\n }\n\n // Count with conditions\n const { sql: whereClause, values } = buildWhere(where, 1, 'sqlite');\n\n const result = await client.execute({\n sql: `SELECT COUNT(*) as count FROM ${table} ${whereClause}`,\n args: values,\n });\n\n return Number(result.rows[0]?.count) || 0;\n } catch (e) {\n throw new DatabaseError('Failed to count records in table', {\n table,\n where,\n originalError: e,\n });\n }\n };\n\n /**\n * Checks if a table exists in the database\n *\n * @param tableName - Name of the table to check\n * @returns Promise resolving to boolean indicating if the table exists\n */\n const tableExists = async (tableName: string): Promise<boolean> => {\n const tableExists =\n !!(await pluck`SELECT name FROM sqlite_master WHERE type='table' AND name=${tableName}`);\n return tableExists;\n };\n\n /**\n * Synchronizes database schema with provided SQL DDL\n * Creates tables if they don't exist and adds missing columns\n *\n * @param schema - SQL schema definition with CREATE TABLE statements\n * @returns Promise that resolves when schema is synchronized\n */\n const syncSchema = async (schema: string): Promise<void> => {\n console.log(\n '[sqlite.syncSchema] Starting schema sync for dbid:',\n options.dbid,\n );\n console.log('[sqlite.syncSchema] Schema length:', schema.length, 'chars');\n\n // List of SQL reserved keywords that need to stay quoted\n const reservedKeywords = new Set([\n 'references',\n 'order',\n 'group',\n 'table',\n 'index',\n 'select',\n 'from',\n 'where',\n 'join',\n 'left',\n 'right',\n 'inner',\n 'outer',\n 'on',\n 'as',\n 'and',\n 'or',\n 'not',\n 'like',\n 'in',\n 'between',\n 'case',\n 'when',\n 'then',\n 'else',\n 'end',\n 'union',\n 'distinct',\n 'having',\n 'limit',\n 'offset',\n 'default',\n 'check',\n 'unique',\n 'primary',\n 'foreign',\n 'key',\n 'constraint',\n 'cascade',\n ]);\n\n // Normalize whitespace and simplify CAST expressions\n let normalizedSchema = schema\n .replace(/\\s+/g, ' ') // Replace multiple whitespace with single space\n .replace(/DEFAULT CAST\\(([^)]+)\\s+AS\\s+\\w+\\)/gi, 'DEFAULT $1') // Simplify CAST in DEFAULT clauses\n .trim();\n\n // Remove quotes around identifiers EXCEPT for reserved keywords\n normalizedSchema = normalizedSchema.replace(\n /\"(\\w+)\"/g,\n (match, identifier) => {\n return reservedKeywords.has(identifier.toLowerCase())\n ? match\n : identifier;\n },\n );\n\n console.log('[sqlite.syncSchema] Normalized schema:', normalizedSchema);\n\n // Split into individual commands\n const commands = normalizedSchema\n .split(';')\n .map((cmd) => cmd.trim())\n .filter((cmd) => cmd.length > 0);\n\n console.log(\n '[sqlite.syncSchema] Found',\n commands.length,\n 'commands to process',\n );\n\n // Execute each command\n for (const command of commands) {\n try {\n console.log(\n '[sqlite.syncSchema] Executing:',\n `${command.substring(0, 50)}...`,\n );\n await client.execute(command);\n console.log('[sqlite.syncSchema] Successfully executed command');\n } catch (error) {\n console.error(\n '[sqlite.syncSchema] Failed to execute command:',\n command,\n );\n console.error('[sqlite.syncSchema] Error:', error);\n throw error;\n }\n }\n };\n\n /**\n * Executes a callback within a database transaction\n * Automatically commits on success or rolls back on error\n *\n * @param callback - Function to execute within transaction\n * @returns Promise resolving to callback result\n */\n const transaction = async <T>(\n callback: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> => {\n try {\n await client.execute({ sql: 'BEGIN TRANSACTION', args: [] });\n\n const result = await callback(createTransactionScope());\n await client.execute({ sql: 'COMMIT', args: [] });\n return result;\n } catch (error) {\n // A failing ROLLBACK must not replace the caller's error — SQLite\n // reports \"cannot rollback - no transaction is active\" whenever the\n // transaction is already gone, which says nothing about what failed.\n try {\n await client.execute({ sql: 'ROLLBACK', args: [] });\n } catch {\n // Nothing left to roll back.\n }\n throw error;\n }\n };\n\n /**\n * Builds the transaction-scoped interface handed to a transaction callback.\n *\n * The only difference from the top-level interface is `transaction`: this\n * one re-enters the transaction already in progress under a savepoint\n * instead of issuing a second BEGIN. SQLite shares one connection, so the\n * old behaviour of re-exposing the top-level `transaction` sent a nested\n * call into `BEGIN` on a connection that was already in a transaction; that\n * throws, and the nested call's own ROLLBACK then discarded the *enclosing*\n * transaction's work while later writes silently committed in autocommit.\n */\n const createTransactionScope = (): DatabaseInterface => {\n // SQLite doesn't have separate transaction clients, so we reuse the same client\n const txDb: DatabaseInterface = {\n url,\n client,\n insert,\n get,\n list,\n update,\n upsert: upsertInCurrentTransaction,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n many,\n single,\n pluck,\n execute,\n query,\n oo: many,\n oO: single,\n ox: pluck,\n xx: execute,\n tableExists,\n syncSchema,\n transaction: async <T>(\n callback: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> => {\n savepointSequence += 1;\n const name = `hv_sp_${savepointSequence}`;\n await client.execute({ sql: `SAVEPOINT ${name}`, args: [] });\n try {\n const result = await callback(createTransactionScope());\n await client.execute({\n sql: `RELEASE SAVEPOINT ${name}`,\n args: [],\n });\n return result;\n } catch (error) {\n try {\n // ROLLBACK TO leaves the savepoint in place, so release it as\n // well or it accumulates for the life of the transaction.\n await client.execute({\n sql: `ROLLBACK TO SAVEPOINT ${name}`,\n args: [],\n });\n await client.execute({\n sql: `RELEASE SAVEPOINT ${name}`,\n args: [],\n });\n } catch {\n // The enclosing transaction is already unwinding; let its own\n // teardown deal with the connection.\n }\n throw error;\n }\n },\n };\n\n return txDb;\n };\n\n /**\n * Begins a new transaction and returns a handle for manual control\n *\n * Unlike transaction(), this gives you explicit control over commit/rollback.\n * Ideal for test isolation where you want to rollback after each test.\n *\n * @returns Promise resolving to a TransactionHandle\n */\n const beginTransaction = async (): Promise<TransactionHandle> => {\n await client.execute({ sql: 'BEGIN TRANSACTION', args: [] });\n\n let active = true;\n\n const commit = async (): Promise<void> => {\n if (!active) {\n throw new DatabaseError('Transaction already ended', {});\n }\n await client.execute({ sql: 'COMMIT', args: [] });\n active = false;\n };\n\n const rollback = async (): Promise<void> => {\n if (!active) {\n throw new DatabaseError('Transaction already ended', {});\n }\n await client.execute({ sql: 'ROLLBACK', args: [] });\n active = false;\n };\n\n const isActive = (): boolean => active;\n\n // Create a transaction-scoped database interface with commit/rollback.\n // The handle is inside a transaction for the same reason a callback scope\n // is, so it gets the same savepoint-based nesting rather than the\n // top-level `transaction`.\n const txHandle: TransactionHandle = {\n ...createTransactionScope(),\n commit,\n rollback,\n isActive,\n };\n\n return txHandle;\n };\n\n /**\n * Creates a table-specific interface for simplified table operations\n *\n * @param tableName - Table name\n * @returns TableInterface for the specified table\n */\n const table = (tableName: string): TableInterface => ({\n insert: (data) => insert(tableName, data),\n get: (where) => get(tableName, where),\n list: (where) => list(tableName, where),\n });\n\n /**\n * Parses a tagged template literal into a SQL query and values\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Object with SQL query and values array\n */\n const parseTemplate = (strings: TemplateStringsArray, ...vars: any[]) => {\n let sql = strings[0];\n const values = [];\n for (let i = 0; i < vars.length; i++) {\n values.push(vars[i]);\n sql += `?${strings[i + 1]}`;\n }\n return { sql, values };\n };\n\n /**\n * Executes a SQL query using template literals and returns a single value\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to a single value (first column of first row)\n * @throws Error if the query fails\n */\n const pluck = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<any> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const result = await client.execute({ sql, args: values });\n return result.rows[0]?.[Object.keys(result.rows[0])[0]] ?? null;\n } catch (e) {\n throw new DatabaseError('Failed to execute pluck query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals and returns a single row\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to a single result record or null\n * @throws Error if the query fails\n */\n const single = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<Record<string, any> | null> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const result = await client.execute({ sql, args: values });\n return result.rows[0] || null;\n } catch (e) {\n throw new DatabaseError('Failed to execute single query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals and returns multiple rows\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise resolving to array of result records\n * @throws Error if the query fails\n */\n const many = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<Record<string, any>[]> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n const result = await client.execute({ sql, args: values });\n return result.rows;\n } catch (e) {\n throw new DatabaseError('Failed to execute many query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a SQL query using template literals without returning results\n *\n * @param strings - Template strings\n * @param vars - Variables to interpolate into the query\n * @returns Promise that resolves when the query completes\n * @throws Error if the query fails\n */\n const execute = async (\n strings: TemplateStringsArray,\n ...vars: any[]\n ): Promise<void> => {\n const { sql, values } = parseTemplate(strings, ...vars);\n try {\n await client.execute({ sql, args: values });\n } catch (e) {\n throw new DatabaseError('Failed to execute query', {\n sql,\n values,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * Executes a raw SQL query with parameterized values\n *\n * @param str - SQL query string\n * @param values - Variables to use as parameters\n * @returns Promise resolving to query result with rows and metadata\n * @throws Error if the query fails\n */\n const query = async (str: string, ...values: any[]) => {\n const sql = str;\n const args = Array.isArray(values[0]) ? values[0] : values;\n try {\n const result = await client.execute({ sql, args });\n return {\n command: sql.split(' ')[0].toUpperCase(),\n rowCount: result.rowsAffected ?? result.rows.length,\n oid: null,\n fields: Object.keys(result.rows[0] || {}).map((name) => ({\n name,\n tableID: 0,\n columnID: 0,\n dataTypeID: 0,\n dataTypeSize: -1,\n dataTypeModifier: -1,\n format: 'text',\n })),\n rows: result.rows,\n };\n } catch (e) {\n throw new DatabaseError('Failed to execute raw query', {\n sql,\n args,\n originalError: formatDbError(e),\n });\n }\n };\n\n // Shorthand aliases for query methods\n const oo = many; // (o)bjective-(o)bjects: returns multiple rows\n const oO = single; // (o)bjective-(O)bject: returns a single row\n const ox = pluck; // (o)bjective-(x): returns a single value\n const xx = execute; // (x)ecute-(x)ecute: executes without returning\n\n /**\n * Initialize database schemas from JSON manifest\n * Supports dependency resolution and schema overrides\n *\n * @param options - Schema initialization options\n * @returns Promise that resolves when schemas are initialized\n */\n const initializeSchemas = async (\n options: SchemaInitializationOptions,\n ): Promise<void> => {\n const schemaManager = new DatabaseSchemaManager();\n const currentDb: DatabaseInterface = {\n url,\n client,\n query,\n insert,\n update,\n upsert,\n get,\n list,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n tableExists,\n many,\n single,\n pluck,\n execute,\n oo,\n oO,\n ox,\n xx,\n syncSchema,\n transaction,\n };\n\n await schemaManager.initializeSchemas(currentDb, options);\n };\n\n /**\n * Retrieves the schema information for a table\n *\n * @param table - Table name\n * @returns Promise resolving to table schema info or null if table doesn't exist\n * @throws Error if the query fails\n */\n const getTableSchema = async (\n table: string,\n ): Promise<TableSchemaInfo | null> => {\n validateTableName(table);\n\n try {\n // Check if table exists\n const exists = await tableExists(table);\n if (!exists) {\n return null;\n }\n\n // Get column information from pragma_table_info\n const columnRows =\n await many`SELECT * FROM pragma_table_info(${table})`;\n\n const columns: Record<string, ColumnDefinition> = {};\n for (const row of columnRows) {\n const colName = row.name as string;\n columns[colName] = {\n type: row.type as string,\n primaryKey: row.pk === 1,\n notNull: row.notnull === 1,\n defaultValue: row.dflt_value,\n };\n }\n\n // Get index information from sqlite_master\n const indexRows = await many`\n SELECT name, sql FROM sqlite_master\n WHERE type = 'index'\n AND tbl_name = ${table}\n AND name NOT LIKE 'sqlite_%'\n `;\n\n const indexes: IndexDefinition[] = [];\n for (const row of indexRows) {\n const indexName = row.name as string;\n\n // Get index columns from pragma_index_info\n const indexInfoRows =\n await many`SELECT * FROM pragma_index_info(${indexName})`;\n\n const indexColumns: string[] = [];\n for (const infoRow of indexInfoRows) {\n indexColumns.push(infoRow.name as string);\n }\n\n // Check if index is unique from pragma_index_list\n const indexListRow =\n await single`SELECT * FROM pragma_index_list(${table}) WHERE name = ${indexName}`;\n\n indexes.push({\n name: indexName,\n columns: indexColumns,\n unique: indexListRow?.unique === 1,\n });\n }\n\n // Get foreign key information from pragma_foreign_key_list\n const fkRows =\n await many`SELECT * FROM pragma_foreign_key_list(${table})`;\n\n const foreignKeys: Array<{\n column: string;\n referencesTable: string;\n referencesColumn: string;\n onDelete?: string;\n onUpdate?: string;\n }> = [];\n\n for (const fkRow of fkRows) {\n foreignKeys.push({\n column: fkRow.from as string,\n referencesTable: fkRow.table as string,\n referencesColumn: fkRow.to as string,\n onDelete: fkRow.on_delete as string | undefined,\n onUpdate: fkRow.on_update as string | undefined,\n });\n }\n\n return {\n tableName: table,\n columns,\n indexes,\n foreignKeys,\n };\n } catch (e) {\n throw new DatabaseError('Failed to retrieve table schema', {\n table,\n originalError: formatDbError(e),\n });\n }\n };\n\n /**\n * ALTER TABLE operations for schema evolution\n */\n const alterTable = {\n /**\n * Adds a new column to an existing table\n *\n * @param table - Table name\n * @param column - Column definition with name\n * @returns Promise that resolves when column is added\n * @throws Error if the alter operation fails\n */\n addColumn: async (\n table: string,\n column: ColumnDefinitionWithName,\n ): Promise<void> => {\n validateTableName(table);\n validateColumnName(column.name);\n\n try {\n const sql = generateAddColumnStatement(table, column, 'sqlite');\n await client.execute({ sql, args: [] });\n } catch (e) {\n throw new DatabaseError('Failed to add column to table', {\n table,\n column: column.name,\n originalError: formatDbError(e),\n });\n }\n },\n\n /**\n * Adds a new index to an existing table\n *\n * @param table - Table name\n * @param index - Index definition\n * @returns Promise that resolves when index is created\n * @throws Error if the create index operation fails\n */\n addIndex: async (\n table: string,\n index: IndexDefinition,\n ): Promise<void> => {\n validateTableName(table);\n validateIndexName(index.name);\n\n for (const col of index.columns) {\n validateColumnName(col);\n }\n\n try {\n const sql = generateCreateIndexStatement(table, index);\n await client.execute({ sql, args: [] });\n } catch (e) {\n throw new DatabaseError('Failed to create index on table', {\n table,\n index: index.name,\n originalError: formatDbError(e),\n });\n }\n },\n };\n\n return {\n url,\n client,\n query,\n insert,\n update,\n upsert,\n get,\n list,\n getOrInsert,\n delete: deleteRecords,\n count,\n table,\n tableExists,\n many,\n single,\n pluck,\n execute,\n oo,\n oO,\n ox,\n xx,\n syncSchema,\n initializeSchemas,\n transaction,\n beginTransaction,\n getTableSchema,\n alterTable,\n };\n })();\n\n // Store the pending connection promise if dbid exists\n if (options.dbid) {\n pendingConnections.set(options.dbid, connectionPromise);\n }\n\n try {\n // Wait for the connection to be established\n const db = await connectionPromise;\n\n // Cache the connection for reuse if dbid exists\n if (options.dbid) {\n memoryConnectionCache.set(options.dbid, db);\n }\n\n return db;\n } finally {\n // Clean up pending connection promise\n if (options.dbid) {\n pendingConnections.delete(options.dbid);\n }\n }\n}\n"],"mappings":"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"}
|