@happyvertical/sql 0.80.0 → 0.80.2

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.
Files changed (31) hide show
  1. package/dist/backup/index.js +210 -188
  2. package/dist/backup/index.js.map +1 -1
  3. package/dist/chunks/alter-utils-K7tiuj5L.js +135 -0
  4. package/dist/chunks/alter-utils-K7tiuj5L.js.map +1 -0
  5. package/dist/chunks/duckdb-DykBBzd6.js +1056 -0
  6. package/dist/chunks/duckdb-DykBBzd6.js.map +1 -0
  7. package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js +115 -0
  8. package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js.map +1 -0
  9. package/dist/chunks/postgres-cli-DzZcXSIG.js +272 -0
  10. package/dist/chunks/postgres-cli-DzZcXSIG.js.map +1 -0
  11. package/dist/chunks/schema-manager-a8RlxIE2.js +450 -0
  12. package/dist/chunks/schema-manager-a8RlxIE2.js.map +1 -0
  13. package/dist/chunks/sqlite-YgU9LCVy.js +1045 -0
  14. package/dist/chunks/sqlite-YgU9LCVy.js.map +1 -0
  15. package/dist/chunks/sqlite-native-BGtpx7Ro.js +902 -0
  16. package/dist/chunks/sqlite-native-BGtpx7Ro.js.map +1 -0
  17. package/dist/cli/claude-context.js +17 -17
  18. package/dist/cli/claude-context.js.map +1 -1
  19. package/dist/index.js +3244 -35
  20. package/dist/index.js.map +1 -1
  21. package/package.json +5 -5
  22. package/dist/chunks/duckdb-B6m78QdL.js +0 -924
  23. package/dist/chunks/duckdb-B6m78QdL.js.map +0 -1
  24. package/dist/chunks/index-CzdYvRFp.js +0 -3692
  25. package/dist/chunks/index-CzdYvRFp.js.map +0 -1
  26. package/dist/chunks/postgres-cli-Cr6bBZ3q.js +0 -209
  27. package/dist/chunks/postgres-cli-Cr6bBZ3q.js.map +0 -1
  28. package/dist/chunks/sqlite-CPCNeJIH.js +0 -937
  29. package/dist/chunks/sqlite-CPCNeJIH.js.map +0 -1
  30. package/dist/chunks/sqlite-native-DqVPKNUu.js +0 -1129
  31. package/dist/chunks/sqlite-native-DqVPKNUu.js.map +0 -1
@@ -1,937 +0,0 @@
1
- import { DatabaseError } from "@happyvertical/utils";
2
- import { r as resolveSchemas, v as validateTableName, a as validateIndexName, b as validateColumnName, g as generateCreateIndexStatement, f as formatDbError, c as generateAddColumnStatement, D as DatabaseSchemaManager, d as buildWhere } from "./index-CzdYvRFp.js";
3
- const memoryConnectionCache = /* @__PURE__ */ new Map();
4
- const pendingConnections = /* @__PURE__ */ new Map();
5
- const NULL_AWARE_UPSERT_MAX_ATTEMPTS = 8;
6
- const NULL_AWARE_UPSERT_BASE_DELAY_MS = 25;
7
- const nullAwareUpsertLocks = /* @__PURE__ */ new Map();
8
- function delay(ms) {
9
- return new Promise((resolve) => setTimeout(resolve, ms));
10
- }
11
- function isRetriableSqliteTransactionError(error) {
12
- const formatted = formatDbError(error).toLowerCase();
13
- return formatted.includes("busy") || formatted.includes("locked") || formatted.includes("database is locked");
14
- }
15
- async function withNullAwareUpsertLock(lockKey, callback) {
16
- const previous = nullAwareUpsertLocks.get(lockKey) ?? Promise.resolve();
17
- let release = () => {
18
- };
19
- const current = new Promise((resolve) => {
20
- release = resolve;
21
- });
22
- const next = previous.catch(() => {
23
- }).then(() => current);
24
- nullAwareUpsertLocks.set(lockKey, next);
25
- await previous.catch(() => {
26
- });
27
- try {
28
- return await callback();
29
- } finally {
30
- release();
31
- if (nullAwareUpsertLocks.get(lockKey) === next) {
32
- nullAwareUpsertLocks.delete(lockKey);
33
- }
34
- }
35
- }
36
- function generateDbId() {
37
- return `memory-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
38
- }
39
- async function createLibSQLClient(options) {
40
- const { url = ":memory:", authToken, encryptionKey } = options;
41
- let libsqlUrl = url;
42
- if (url !== ":memory:" && !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("libsql://") && !url.startsWith("file:")) {
43
- const { resolve } = await import("node:path");
44
- const absolutePath = resolve(url);
45
- libsqlUrl = `file://${absolutePath}`;
46
- }
47
- try {
48
- const libsqlClient = "@libsql/client";
49
- const { createClient } = await import(
50
- /* @vite-ignore */
51
- libsqlClient
52
- );
53
- return createClient({ url: libsqlUrl, authToken, encryptionKey });
54
- } catch (error) {
55
- const errorMessage = error instanceof Error ? error.message : String(error);
56
- if (errorMessage?.includes("URL_SCHEME_NOT_SUPPORTED")) {
57
- throw new DatabaseError(
58
- `Unsupported URL scheme. Use ':memory:' for in-memory databases or 'libsql://' for remote LibSQL databases. Original: ${url}, Converted: ${libsqlUrl}`,
59
- { url: libsqlUrl, originalError: errorMessage }
60
- );
61
- }
62
- throw new DatabaseError(`Failed to create LibSQL client: ${errorMessage}`, {
63
- url: libsqlUrl,
64
- originalError: errorMessage
65
- });
66
- }
67
- }
68
- function hasNativeSqliteCapabilities(options) {
69
- return Boolean(
70
- options.capabilities?.notifications || options.capabilities?.vector
71
- );
72
- }
73
- async function createTablesFromSchemas(client, schemas) {
74
- for (const [tableName, schema] of Object.entries(schemas)) {
75
- try {
76
- const result = await client.execute({
77
- sql: `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
78
- args: [tableName]
79
- });
80
- if (result.rows.length > 0) {
81
- console.log(`[sqlite] Table ${tableName} already exists, skipping`);
82
- continue;
83
- }
84
- console.log(`[sqlite] Creating table ${tableName} from provided schema`);
85
- await client.execute(schema.ddl);
86
- if (schema.indexes && schema.indexes.length > 0) {
87
- for (const indexSQL of schema.indexes) {
88
- try {
89
- await client.execute(indexSQL);
90
- } catch (error) {
91
- console.warn(
92
- `[sqlite] Failed to create index for ${tableName}: ${error instanceof Error ? error.message : String(error)}`
93
- );
94
- }
95
- }
96
- }
97
- if (schema.triggers && schema.triggers.length > 0) {
98
- for (const triggerSQL of schema.triggers) {
99
- try {
100
- await client.execute(triggerSQL);
101
- } catch (error) {
102
- console.warn(
103
- `[sqlite] Failed to create trigger for ${tableName}: ${error instanceof Error ? error.message : String(error)}`
104
- );
105
- }
106
- }
107
- }
108
- } catch (error) {
109
- console.error(
110
- `[sqlite] Error creating table ${tableName}:`,
111
- error instanceof Error ? error.message : String(error)
112
- );
113
- console.error(`[sqlite] DDL was:`, schema.ddl?.substring(0, 200) + "...");
114
- throw new DatabaseError(
115
- `Failed to create table ${tableName} from schema: ${error instanceof Error ? error.message : String(error)}`,
116
- {
117
- tableName,
118
- schema,
119
- originalError: error instanceof Error ? error.message : String(error)
120
- }
121
- );
122
- }
123
- }
124
- }
125
- async function getDatabase(options = {}) {
126
- const url = options.url || ":memory:";
127
- if (url === ":memory:" && !options.dbid) {
128
- options.dbid = generateDbId();
129
- }
130
- if (hasNativeSqliteCapabilities(options)) {
131
- const sqliteNative = await import("./sqlite-native-DqVPKNUu.js");
132
- return sqliteNative.getNativeSqliteDatabase(options);
133
- }
134
- if (options.dbid) {
135
- const cached = memoryConnectionCache.get(options.dbid);
136
- if (cached) {
137
- return cached;
138
- }
139
- const pending = pendingConnections.get(options.dbid);
140
- if (pending) {
141
- return pending;
142
- }
143
- }
144
- const connectionPromise = (async () => {
145
- const client = await createLibSQLClient(options);
146
- const resolvedSchemas = resolveSchemas(options.schemas);
147
- if (resolvedSchemas && Object.keys(resolvedSchemas).length > 0) {
148
- await createTablesFromSchemas(client, resolvedSchemas);
149
- }
150
- const serializeValue = (value) => {
151
- if (value === null || value === void 0) {
152
- return value;
153
- }
154
- if (value instanceof Date) {
155
- return value.toISOString();
156
- }
157
- if (typeof value === "object") {
158
- return JSON.stringify(value);
159
- }
160
- return value;
161
- };
162
- const serializeRecord = (record) => {
163
- const serialized = {};
164
- for (const [key, value] of Object.entries(record)) {
165
- if (value === void 0) {
166
- continue;
167
- }
168
- serialized[key] = serializeValue(value);
169
- }
170
- return serialized;
171
- };
172
- const hasNullConflictValue = (conflictColumns, data) => conflictColumns.some((col) => data[col] === null);
173
- const buildNullAwareUpsertLockKey = (table2, conflictColumns, data) => {
174
- const conflictValues = conflictColumns.map((col) => `${col}:${JSON.stringify(data[col])}`).join("|");
175
- return `${url}:${table2}:${conflictValues}`;
176
- };
177
- const validateUpsertConflictColumns = (table2, conflictColumns, serializedData) => {
178
- const missingColumns = conflictColumns.filter(
179
- (col) => !(col in serializedData)
180
- );
181
- if (missingColumns.length > 0) {
182
- throw new DatabaseError("Conflict columns missing from data", {
183
- table: table2,
184
- conflictColumns,
185
- missingColumns,
186
- availableColumns: Object.keys(serializedData),
187
- 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."
188
- });
189
- }
190
- };
191
- const executeStandardUpsert = async (table2, conflictColumns, serializedData) => {
192
- const keys = Object.keys(serializedData);
193
- const values = Object.values(serializedData);
194
- const placeholders = keys.map(() => "?").join(", ");
195
- const updateSet = keys.map((key) => `${key} = excluded.${key}`).join(", ");
196
- const conflict = conflictColumns.join(", ");
197
- const sql = `INSERT INTO ${table2} (${keys.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflict}) DO UPDATE SET ${updateSet}`;
198
- const result = await client.execute({ sql, args: values });
199
- return { operation: "upsert", affected: result.rowsAffected };
200
- };
201
- const executeNullAwareUpsertAttempt = async (executor, table2, conflictColumns, serializedData) => {
202
- const keys = Object.keys(serializedData);
203
- const values = Object.values(serializedData);
204
- const updateSet = keys.map((key) => `${key} = ?`).join(", ");
205
- const whereClause = conflictColumns.map((col) => `${col} IS ?`).join(" AND ");
206
- const whereValues = conflictColumns.map((col) => serializedData[col]);
207
- const updateSql = `UPDATE ${table2} SET ${updateSet} WHERE ${whereClause}`;
208
- const updateResult = await executor.execute({
209
- sql: updateSql,
210
- args: [...values, ...whereValues]
211
- });
212
- if ((updateResult.rowsAffected ?? 0) > 0) {
213
- return { operation: "upsert", affected: updateResult.rowsAffected };
214
- }
215
- const placeholders = keys.map(() => "?").join(", ");
216
- const insertSql = `INSERT INTO ${table2} (${keys.join(", ")}) VALUES (${placeholders})`;
217
- const insertResult = await executor.execute({
218
- sql: insertSql,
219
- args: values
220
- });
221
- return { operation: "upsert", affected: insertResult.rowsAffected };
222
- };
223
- const executeNullAwareUpsertWithRetry = async (table2, conflictColumns, serializedData) => {
224
- if (url === ":memory:") {
225
- return executeNullAwareUpsertAttempt(
226
- client,
227
- table2,
228
- conflictColumns,
229
- serializedData
230
- );
231
- }
232
- let lastError;
233
- for (let attempt = 0; attempt < NULL_AWARE_UPSERT_MAX_ATTEMPTS; attempt++) {
234
- let transaction2;
235
- try {
236
- transaction2 = await client.transaction("write");
237
- const result = await executeNullAwareUpsertAttempt(
238
- transaction2,
239
- table2,
240
- conflictColumns,
241
- serializedData
242
- );
243
- await transaction2.commit();
244
- return result;
245
- } catch (error) {
246
- lastError = error;
247
- if (transaction2 && !transaction2.closed) {
248
- try {
249
- await transaction2.rollback();
250
- } catch (_rollbackError) {
251
- }
252
- }
253
- } finally {
254
- transaction2?.close();
255
- }
256
- if (lastError && attempt < NULL_AWARE_UPSERT_MAX_ATTEMPTS - 1 && isRetriableSqliteTransactionError(lastError)) {
257
- await delay(NULL_AWARE_UPSERT_BASE_DELAY_MS * 2 ** attempt);
258
- continue;
259
- }
260
- break;
261
- }
262
- throw lastError;
263
- };
264
- const executeUpsert = async (table2, conflictColumns, data, options2, acquireTransaction) => {
265
- const serializedData = serializeRecord(data);
266
- validateUpsertConflictColumns(table2, conflictColumns, serializedData);
267
- if (options2?.nullsDistinct || !hasNullConflictValue(conflictColumns, serializedData)) {
268
- return executeStandardUpsert(table2, conflictColumns, serializedData);
269
- }
270
- if (!acquireTransaction) {
271
- return executeNullAwareUpsertAttempt(
272
- client,
273
- table2,
274
- conflictColumns,
275
- serializedData
276
- );
277
- }
278
- return withNullAwareUpsertLock(
279
- buildNullAwareUpsertLockKey(table2, conflictColumns, serializedData),
280
- () => executeNullAwareUpsertWithRetry(
281
- table2,
282
- conflictColumns,
283
- serializedData
284
- )
285
- );
286
- };
287
- const insert = async (table2, data) => {
288
- let sql;
289
- let values;
290
- if (Array.isArray(data)) {
291
- const serializedRecords = data.map(
292
- (record) => serializeRecord(record)
293
- );
294
- const keys = Object.keys(serializedRecords[0]);
295
- const placeholders = serializedRecords.map(() => `(${keys.map(() => "?").join(", ")})`).join(", ");
296
- sql = `INSERT INTO ${table2} (${keys.join(", ")}) VALUES ${placeholders}`;
297
- const flattenedValues = [];
298
- for (const record of serializedRecords) {
299
- flattenedValues.push(...Object.values(record));
300
- }
301
- values = flattenedValues;
302
- } else {
303
- const serializedData = serializeRecord(data);
304
- const keys = Object.keys(serializedData);
305
- const placeholders = keys.map(() => "?").join(", ");
306
- sql = `INSERT INTO ${table2} (${keys.join(", ")}) VALUES (${placeholders})`;
307
- values = Object.values(serializedData);
308
- }
309
- try {
310
- const result = await client.execute({ sql, args: values });
311
- return { operation: "insert", affected: result.rowsAffected };
312
- } catch (e) {
313
- throw new DatabaseError("Failed to insert records into table", {
314
- table: table2,
315
- sql,
316
- values,
317
- originalError: formatDbError(e)
318
- });
319
- }
320
- };
321
- const get = async (table2, where) => {
322
- const { sql: whereClause, values } = buildWhere(where, 1, "sqlite");
323
- if (!whereClause) {
324
- throw new DatabaseError(
325
- "GET requires at least one WHERE condition to prevent returning an arbitrary record",
326
- { table: table2 }
327
- );
328
- }
329
- const sql = `SELECT * FROM ${table2} ${whereClause}`;
330
- try {
331
- const result = await client.execute({ sql, args: values });
332
- return result.rows[0] || null;
333
- } catch (e) {
334
- throw new DatabaseError("Failed to retrieve record from table", {
335
- table: table2,
336
- sql,
337
- values,
338
- originalError: formatDbError(e)
339
- });
340
- }
341
- };
342
- const list = async (table2, where) => {
343
- const { sql: whereClause, values } = buildWhere(where, 1, "sqlite");
344
- const sql = `SELECT * FROM ${table2} ${whereClause}`;
345
- try {
346
- const result = await client.execute({ sql, args: values });
347
- return result.rows;
348
- } catch (e) {
349
- throw new DatabaseError("Failed to list records from table", {
350
- table: table2,
351
- sql,
352
- values,
353
- originalError: formatDbError(e)
354
- });
355
- }
356
- };
357
- const update = async (table2, where, data) => {
358
- const serializedData = serializeRecord(data);
359
- const keys = Object.keys(serializedData);
360
- const values = Object.values(serializedData);
361
- const setClause = keys.map((key, i) => `${key} = $${i + 1}`).join(", ");
362
- const { sql: whereClause, values: whereValues } = buildWhere(
363
- where,
364
- values.length + 1,
365
- "sqlite"
366
- );
367
- if (!whereClause) {
368
- throw new DatabaseError(
369
- "UPDATE requires at least one WHERE condition to prevent accidental update of all records",
370
- { table: table2 }
371
- );
372
- }
373
- const sql = `UPDATE ${table2} SET ${setClause} ${whereClause}`;
374
- try {
375
- const result = await client.execute({
376
- sql,
377
- args: [...values, ...whereValues]
378
- });
379
- return { operation: "update", affected: result.rowsAffected };
380
- } catch (e) {
381
- throw new DatabaseError("Failed to update records in table", {
382
- table: table2,
383
- sql,
384
- values: [...values, ...whereValues],
385
- originalError: formatDbError(e)
386
- });
387
- }
388
- };
389
- const upsert = async (table2, conflictColumns, data, options2) => {
390
- try {
391
- return await executeUpsert(table2, conflictColumns, data, options2, true);
392
- } catch (e) {
393
- if (e instanceof DatabaseError && e.message === "Conflict columns missing from data") {
394
- throw e;
395
- }
396
- throw new DatabaseError("Failed to upsert record into table", {
397
- table: table2,
398
- values: data,
399
- conflictColumns,
400
- originalError: formatDbError(e)
401
- });
402
- }
403
- };
404
- const upsertInCurrentTransaction = async (table2, conflictColumns, data, options2) => {
405
- try {
406
- return await executeUpsert(
407
- table2,
408
- conflictColumns,
409
- data,
410
- options2,
411
- false
412
- );
413
- } catch (e) {
414
- if (e instanceof DatabaseError && e.message === "Conflict columns missing from data") {
415
- throw e;
416
- }
417
- throw new DatabaseError("Failed to upsert record into table", {
418
- table: table2,
419
- values: data,
420
- conflictColumns,
421
- originalError: formatDbError(e)
422
- });
423
- }
424
- };
425
- const getOrInsert = async (table2, where, data) => {
426
- const result = await get(table2, where);
427
- if (result) return result;
428
- await insert(table2, data);
429
- const inserted = await get(table2, where);
430
- if (!inserted) {
431
- throw new DatabaseError("Failed to insert and retrieve record", {
432
- table: table2,
433
- where,
434
- data
435
- });
436
- }
437
- return inserted;
438
- };
439
- const deleteRecords = async (table2, where) => {
440
- validateTableName(table2);
441
- const keys = Object.keys(where);
442
- if (keys.length === 0) {
443
- throw new DatabaseError(
444
- "DELETE requires at least one WHERE condition to prevent accidental deletion of all records",
445
- { table: table2 }
446
- );
447
- }
448
- const { sql: whereClause, values } = buildWhere(where, 1, "sqlite");
449
- try {
450
- await client.execute({
451
- sql: `DELETE FROM ${table2} ${whereClause}`,
452
- args: values
453
- });
454
- return { operation: "delete", affected: 1 };
455
- } catch (e) {
456
- throw new DatabaseError("Failed to delete records from table", {
457
- table: table2,
458
- where,
459
- originalError: e
460
- });
461
- }
462
- };
463
- const count = async (table2, where) => {
464
- validateTableName(table2);
465
- try {
466
- if (!where || Object.keys(where).length === 0) {
467
- const result2 = await pluck`SELECT COUNT(*) FROM ${table2}`;
468
- return Number(result2) || 0;
469
- }
470
- const { sql: whereClause, values } = buildWhere(where, 1, "sqlite");
471
- const result = await client.execute({
472
- sql: `SELECT COUNT(*) as count FROM ${table2} ${whereClause}`,
473
- args: values
474
- });
475
- return Number(result.rows[0]?.count) || 0;
476
- } catch (e) {
477
- throw new DatabaseError("Failed to count records in table", {
478
- table: table2,
479
- where,
480
- originalError: e
481
- });
482
- }
483
- };
484
- const tableExists = async (tableName) => {
485
- const tableExists2 = !!await pluck`SELECT name FROM sqlite_master WHERE type='table' AND name=${tableName}`;
486
- return tableExists2;
487
- };
488
- const syncSchema = async (schema) => {
489
- console.log(
490
- "[sqlite.syncSchema] Starting schema sync for dbid:",
491
- options.dbid
492
- );
493
- console.log("[sqlite.syncSchema] Schema length:", schema.length, "chars");
494
- const reservedKeywords = /* @__PURE__ */ new Set([
495
- "references",
496
- "order",
497
- "group",
498
- "table",
499
- "index",
500
- "select",
501
- "from",
502
- "where",
503
- "join",
504
- "left",
505
- "right",
506
- "inner",
507
- "outer",
508
- "on",
509
- "as",
510
- "and",
511
- "or",
512
- "not",
513
- "like",
514
- "in",
515
- "between",
516
- "case",
517
- "when",
518
- "then",
519
- "else",
520
- "end",
521
- "union",
522
- "distinct",
523
- "having",
524
- "limit",
525
- "offset",
526
- "default",
527
- "check",
528
- "unique",
529
- "primary",
530
- "foreign",
531
- "key",
532
- "constraint",
533
- "cascade"
534
- ]);
535
- let normalizedSchema = schema.replace(/\s+/g, " ").replace(/DEFAULT CAST\(([^)]+)\s+AS\s+\w+\)/gi, "DEFAULT $1").trim();
536
- normalizedSchema = normalizedSchema.replace(
537
- /"(\w+)"/g,
538
- (match, identifier) => {
539
- return reservedKeywords.has(identifier.toLowerCase()) ? match : identifier;
540
- }
541
- );
542
- console.log("[sqlite.syncSchema] Normalized schema:", normalizedSchema);
543
- const commands = normalizedSchema.split(";").map((cmd) => cmd.trim()).filter((cmd) => cmd.length > 0);
544
- console.log(
545
- "[sqlite.syncSchema] Found",
546
- commands.length,
547
- "commands to process"
548
- );
549
- for (const command of commands) {
550
- try {
551
- console.log(
552
- "[sqlite.syncSchema] Executing:",
553
- `${command.substring(0, 50)}...`
554
- );
555
- await client.execute(command);
556
- console.log("[sqlite.syncSchema] Successfully executed command");
557
- } catch (error) {
558
- console.error(
559
- "[sqlite.syncSchema] Failed to execute command:",
560
- command
561
- );
562
- console.error("[sqlite.syncSchema] Error:", error);
563
- throw error;
564
- }
565
- }
566
- };
567
- const transaction = async (callback) => {
568
- try {
569
- await client.execute({ sql: "BEGIN TRANSACTION", args: [] });
570
- const txDb = {
571
- url,
572
- client,
573
- insert,
574
- get,
575
- list,
576
- update,
577
- upsert: upsertInCurrentTransaction,
578
- getOrInsert,
579
- delete: deleteRecords,
580
- count,
581
- table,
582
- many,
583
- single,
584
- pluck,
585
- execute,
586
- query,
587
- oo: many,
588
- oO: single,
589
- ox: pluck,
590
- xx: execute,
591
- tableExists,
592
- syncSchema,
593
- transaction
594
- };
595
- const result = await callback(txDb);
596
- await client.execute({ sql: "COMMIT", args: [] });
597
- return result;
598
- } catch (error) {
599
- await client.execute({ sql: "ROLLBACK", args: [] });
600
- throw error;
601
- }
602
- };
603
- const beginTransaction = async () => {
604
- await client.execute({ sql: "BEGIN TRANSACTION", args: [] });
605
- let active = true;
606
- const commit = async () => {
607
- if (!active) {
608
- throw new DatabaseError("Transaction already ended", {});
609
- }
610
- await client.execute({ sql: "COMMIT", args: [] });
611
- active = false;
612
- };
613
- const rollback = async () => {
614
- if (!active) {
615
- throw new DatabaseError("Transaction already ended", {});
616
- }
617
- await client.execute({ sql: "ROLLBACK", args: [] });
618
- active = false;
619
- };
620
- const isActive = () => active;
621
- const txHandle = {
622
- url,
623
- client,
624
- insert,
625
- get,
626
- list,
627
- update,
628
- upsert: upsertInCurrentTransaction,
629
- getOrInsert,
630
- delete: deleteRecords,
631
- count,
632
- table,
633
- many,
634
- single,
635
- pluck,
636
- execute,
637
- query,
638
- oo: many,
639
- oO: single,
640
- ox: pluck,
641
- xx: execute,
642
- tableExists,
643
- syncSchema,
644
- transaction,
645
- commit,
646
- rollback,
647
- isActive
648
- };
649
- return txHandle;
650
- };
651
- const table = (tableName) => ({
652
- insert: (data) => insert(tableName, data),
653
- get: (where) => get(tableName, where),
654
- list: (where) => list(tableName, where)
655
- });
656
- const parseTemplate = (strings, ...vars) => {
657
- let sql = strings[0];
658
- const values = [];
659
- for (let i = 0; i < vars.length; i++) {
660
- values.push(vars[i]);
661
- sql += `?${strings[i + 1]}`;
662
- }
663
- return { sql, values };
664
- };
665
- const pluck = async (strings, ...vars) => {
666
- const { sql, values } = parseTemplate(strings, ...vars);
667
- try {
668
- const result = await client.execute({ sql, args: values });
669
- return result.rows[0]?.[Object.keys(result.rows[0])[0]] ?? null;
670
- } catch (e) {
671
- throw new DatabaseError("Failed to execute pluck query", {
672
- sql,
673
- values,
674
- originalError: formatDbError(e)
675
- });
676
- }
677
- };
678
- const single = async (strings, ...vars) => {
679
- const { sql, values } = parseTemplate(strings, ...vars);
680
- try {
681
- const result = await client.execute({ sql, args: values });
682
- return result.rows[0] || null;
683
- } catch (e) {
684
- throw new DatabaseError("Failed to execute single query", {
685
- sql,
686
- values,
687
- originalError: formatDbError(e)
688
- });
689
- }
690
- };
691
- const many = async (strings, ...vars) => {
692
- const { sql, values } = parseTemplate(strings, ...vars);
693
- try {
694
- const result = await client.execute({ sql, args: values });
695
- return result.rows;
696
- } catch (e) {
697
- throw new DatabaseError("Failed to execute many query", {
698
- sql,
699
- values,
700
- originalError: formatDbError(e)
701
- });
702
- }
703
- };
704
- const execute = async (strings, ...vars) => {
705
- const { sql, values } = parseTemplate(strings, ...vars);
706
- try {
707
- await client.execute({ sql, args: values });
708
- } catch (e) {
709
- throw new DatabaseError("Failed to execute query", {
710
- sql,
711
- values,
712
- originalError: formatDbError(e)
713
- });
714
- }
715
- };
716
- const query = async (str, ...values) => {
717
- const sql = str;
718
- const args = Array.isArray(values[0]) ? values[0] : values;
719
- try {
720
- const result = await client.execute({ sql, args });
721
- return {
722
- command: sql.split(" ")[0].toUpperCase(),
723
- rowCount: result.rowsAffected ?? result.rows.length,
724
- oid: null,
725
- fields: Object.keys(result.rows[0] || {}).map((name) => ({
726
- name,
727
- tableID: 0,
728
- columnID: 0,
729
- dataTypeID: 0,
730
- dataTypeSize: -1,
731
- dataTypeModifier: -1,
732
- format: "text"
733
- })),
734
- rows: result.rows
735
- };
736
- } catch (e) {
737
- throw new DatabaseError("Failed to execute raw query", {
738
- sql,
739
- args,
740
- originalError: formatDbError(e)
741
- });
742
- }
743
- };
744
- const oo = many;
745
- const oO = single;
746
- const ox = pluck;
747
- const xx = execute;
748
- const initializeSchemas = async (options2) => {
749
- const schemaManager = new DatabaseSchemaManager();
750
- const currentDb = {
751
- url,
752
- client,
753
- query,
754
- insert,
755
- update,
756
- upsert,
757
- get,
758
- list,
759
- getOrInsert,
760
- delete: deleteRecords,
761
- count,
762
- table,
763
- tableExists,
764
- many,
765
- single,
766
- pluck,
767
- execute,
768
- oo,
769
- oO,
770
- ox,
771
- xx,
772
- syncSchema,
773
- transaction
774
- };
775
- await schemaManager.initializeSchemas(currentDb, options2);
776
- };
777
- const getTableSchema = async (table2) => {
778
- validateTableName(table2);
779
- try {
780
- const exists = await tableExists(table2);
781
- if (!exists) {
782
- return null;
783
- }
784
- const columnRows = await many`SELECT * FROM pragma_table_info(${table2})`;
785
- const columns = {};
786
- for (const row of columnRows) {
787
- const colName = row.name;
788
- columns[colName] = {
789
- type: row.type,
790
- primaryKey: row.pk === 1,
791
- notNull: row.notnull === 1,
792
- defaultValue: row.dflt_value
793
- };
794
- }
795
- const indexRows = await many`
796
- SELECT name, sql FROM sqlite_master
797
- WHERE type = 'index'
798
- AND tbl_name = ${table2}
799
- AND name NOT LIKE 'sqlite_%'
800
- `;
801
- const indexes = [];
802
- for (const row of indexRows) {
803
- const indexName = row.name;
804
- const indexInfoRows = await many`SELECT * FROM pragma_index_info(${indexName})`;
805
- const indexColumns = [];
806
- for (const infoRow of indexInfoRows) {
807
- indexColumns.push(infoRow.name);
808
- }
809
- const indexListRow = await single`SELECT * FROM pragma_index_list(${table2}) WHERE name = ${indexName}`;
810
- indexes.push({
811
- name: indexName,
812
- columns: indexColumns,
813
- unique: indexListRow?.unique === 1
814
- });
815
- }
816
- const fkRows = await many`SELECT * FROM pragma_foreign_key_list(${table2})`;
817
- const foreignKeys = [];
818
- for (const fkRow of fkRows) {
819
- foreignKeys.push({
820
- column: fkRow.from,
821
- referencesTable: fkRow.table,
822
- referencesColumn: fkRow.to,
823
- onDelete: fkRow.on_delete,
824
- onUpdate: fkRow.on_update
825
- });
826
- }
827
- return {
828
- tableName: table2,
829
- columns,
830
- indexes,
831
- foreignKeys
832
- };
833
- } catch (e) {
834
- throw new DatabaseError("Failed to retrieve table schema", {
835
- table: table2,
836
- originalError: formatDbError(e)
837
- });
838
- }
839
- };
840
- const alterTable = {
841
- /**
842
- * Adds a new column to an existing table
843
- *
844
- * @param table - Table name
845
- * @param column - Column definition with name
846
- * @returns Promise that resolves when column is added
847
- * @throws Error if the alter operation fails
848
- */
849
- addColumn: async (table2, column) => {
850
- validateTableName(table2);
851
- validateColumnName(column.name);
852
- try {
853
- const sql = generateAddColumnStatement(table2, column, "sqlite");
854
- await client.execute({ sql, args: [] });
855
- } catch (e) {
856
- throw new DatabaseError("Failed to add column to table", {
857
- table: table2,
858
- column: column.name,
859
- originalError: formatDbError(e)
860
- });
861
- }
862
- },
863
- /**
864
- * Adds a new index to an existing table
865
- *
866
- * @param table - Table name
867
- * @param index - Index definition
868
- * @returns Promise that resolves when index is created
869
- * @throws Error if the create index operation fails
870
- */
871
- addIndex: async (table2, index) => {
872
- validateTableName(table2);
873
- validateIndexName(index.name);
874
- for (const col of index.columns) {
875
- validateColumnName(col);
876
- }
877
- try {
878
- const sql = generateCreateIndexStatement(table2, index);
879
- await client.execute({ sql, args: [] });
880
- } catch (e) {
881
- throw new DatabaseError("Failed to create index on table", {
882
- table: table2,
883
- index: index.name,
884
- originalError: formatDbError(e)
885
- });
886
- }
887
- }
888
- };
889
- return {
890
- url,
891
- client,
892
- query,
893
- insert,
894
- update,
895
- upsert,
896
- get,
897
- list,
898
- getOrInsert,
899
- delete: deleteRecords,
900
- count,
901
- table,
902
- tableExists,
903
- many,
904
- single,
905
- pluck,
906
- execute,
907
- oo,
908
- oO,
909
- ox,
910
- xx,
911
- syncSchema,
912
- initializeSchemas,
913
- transaction,
914
- beginTransaction,
915
- getTableSchema,
916
- alterTable
917
- };
918
- })();
919
- if (options.dbid) {
920
- pendingConnections.set(options.dbid, connectionPromise);
921
- }
922
- try {
923
- const db = await connectionPromise;
924
- if (options.dbid) {
925
- memoryConnectionCache.set(options.dbid, db);
926
- }
927
- return db;
928
- } finally {
929
- if (options.dbid) {
930
- pendingConnections.delete(options.dbid);
931
- }
932
- }
933
- }
934
- export {
935
- getDatabase
936
- };
937
- //# sourceMappingURL=sqlite-CPCNeJIH.js.map