@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.
- package/dist/backup/index.js +210 -188
- package/dist/backup/index.js.map +1 -1
- package/dist/chunks/alter-utils-K7tiuj5L.js +135 -0
- package/dist/chunks/alter-utils-K7tiuj5L.js.map +1 -0
- package/dist/chunks/duckdb-DykBBzd6.js +1056 -0
- package/dist/chunks/duckdb-DykBBzd6.js.map +1 -0
- package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js +115 -0
- package/dist/chunks/duckdb-schema-utils-B-XBP8QF.js.map +1 -0
- package/dist/chunks/postgres-cli-DzZcXSIG.js +272 -0
- package/dist/chunks/postgres-cli-DzZcXSIG.js.map +1 -0
- package/dist/chunks/schema-manager-a8RlxIE2.js +450 -0
- package/dist/chunks/schema-manager-a8RlxIE2.js.map +1 -0
- package/dist/chunks/sqlite-YgU9LCVy.js +1045 -0
- package/dist/chunks/sqlite-YgU9LCVy.js.map +1 -0
- package/dist/chunks/sqlite-native-BGtpx7Ro.js +902 -0
- package/dist/chunks/sqlite-native-BGtpx7Ro.js.map +1 -0
- package/dist/cli/claude-context.js +17 -17
- package/dist/cli/claude-context.js.map +1 -1
- package/dist/index.js +3244 -35
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunks/duckdb-B6m78QdL.js +0 -924
- package/dist/chunks/duckdb-B6m78QdL.js.map +0 -1
- package/dist/chunks/index-CzdYvRFp.js +0 -3692
- package/dist/chunks/index-CzdYvRFp.js.map +0 -1
- package/dist/chunks/postgres-cli-Cr6bBZ3q.js +0 -209
- package/dist/chunks/postgres-cli-Cr6bBZ3q.js.map +0 -1
- package/dist/chunks/sqlite-CPCNeJIH.js +0 -937
- package/dist/chunks/sqlite-CPCNeJIH.js.map +0 -1
- package/dist/chunks/sqlite-native-DqVPKNUu.js +0 -1129
- package/dist/chunks/sqlite-native-DqVPKNUu.js.map +0 -1
|
@@ -1,924 +0,0 @@
|
|
|
1
|
-
import { readdir } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join, extname, basename } from "node:path";
|
|
4
|
-
import { DatabaseError } from "@happyvertical/utils";
|
|
5
|
-
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, e as convertUniqueIndexesToInlineConstraints, d as buildWhere } from "./index-CzdYvRFp.js";
|
|
6
|
-
async function createTablesFromSchemas(connection, schemas) {
|
|
7
|
-
for (const [tableName, schema] of Object.entries(schemas)) {
|
|
8
|
-
try {
|
|
9
|
-
const result = await connection.runAndReadAll(
|
|
10
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}'`
|
|
11
|
-
);
|
|
12
|
-
const rows = result.getRowObjects();
|
|
13
|
-
if (rows.length > 0) {
|
|
14
|
-
console.log(`[duckdb] Table ${tableName} already exists, skipping`);
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
console.log(`[duckdb] Creating table ${tableName} from provided schema`);
|
|
18
|
-
const transformed = convertUniqueIndexesToInlineConstraints(
|
|
19
|
-
schema.ddl,
|
|
20
|
-
schema.indexes
|
|
21
|
-
);
|
|
22
|
-
await connection.run(transformed.ddl);
|
|
23
|
-
if (transformed.indexes && transformed.indexes.length > 0) {
|
|
24
|
-
for (const indexSQL of transformed.indexes) {
|
|
25
|
-
try {
|
|
26
|
-
await connection.run(indexSQL);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.warn(
|
|
29
|
-
`[duckdb] Failed to create index for ${tableName}: ${error instanceof Error ? error.message : String(error)}`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (schema.triggers && schema.triggers.length > 0) {
|
|
35
|
-
for (const triggerSQL of schema.triggers) {
|
|
36
|
-
try {
|
|
37
|
-
await connection.run(triggerSQL);
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.warn(
|
|
40
|
-
`[duckdb] Failed to create trigger for ${tableName}: ${error instanceof Error ? error.message : String(error)}`
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
} catch (error) {
|
|
46
|
-
throw new DatabaseError(
|
|
47
|
-
`Failed to create table ${tableName} from schema`,
|
|
48
|
-
{
|
|
49
|
-
tableName,
|
|
50
|
-
schema,
|
|
51
|
-
originalError: error instanceof Error ? error.message : String(error)
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
function resolveDuckDBUrl(url) {
|
|
58
|
-
if (url === ":memory:") {
|
|
59
|
-
return url;
|
|
60
|
-
}
|
|
61
|
-
if (url.startsWith(":memory:")) {
|
|
62
|
-
const suffix = url.slice(":memory:".length);
|
|
63
|
-
const tempPath = join(tmpdir(), `duckdb-memory-${suffix}.db`);
|
|
64
|
-
return tempPath;
|
|
65
|
-
}
|
|
66
|
-
return url;
|
|
67
|
-
}
|
|
68
|
-
async function createDuckDBConnection(options) {
|
|
69
|
-
const {
|
|
70
|
-
url = ":memory:",
|
|
71
|
-
dataDir = "./data",
|
|
72
|
-
autoRegisterJSON = true
|
|
73
|
-
} = options;
|
|
74
|
-
const schemas = resolveSchemas(options.schemas) ?? {};
|
|
75
|
-
const resolvedUrl = resolveDuckDBUrl(url);
|
|
76
|
-
try {
|
|
77
|
-
const duckdbModule = "@duckdb/node-api";
|
|
78
|
-
const { DuckDBInstance } = await import(
|
|
79
|
-
/* @vite-ignore */
|
|
80
|
-
duckdbModule
|
|
81
|
-
);
|
|
82
|
-
const instance = await DuckDBInstance.create(resolvedUrl);
|
|
83
|
-
const connection = await instance.connect();
|
|
84
|
-
if (schemas && Object.keys(schemas).length > 0) {
|
|
85
|
-
await createTablesFromSchemas(connection, schemas);
|
|
86
|
-
}
|
|
87
|
-
if (autoRegisterJSON && dataDir) {
|
|
88
|
-
await registerJSONFiles(connection, dataDir);
|
|
89
|
-
}
|
|
90
|
-
return connection;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
93
|
-
throw new DatabaseError(
|
|
94
|
-
`Failed to create DuckDB connection: ${errorMessage}`,
|
|
95
|
-
{
|
|
96
|
-
url,
|
|
97
|
-
originalError: errorMessage
|
|
98
|
-
}
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async function registerJSONFiles(connection, dataDir) {
|
|
103
|
-
try {
|
|
104
|
-
const files = await readdir(dataDir);
|
|
105
|
-
const jsonFiles = files.filter(
|
|
106
|
-
(file) => extname(file).toLowerCase() === ".json"
|
|
107
|
-
);
|
|
108
|
-
for (const file of jsonFiles) {
|
|
109
|
-
const filePath = join(dataDir, file);
|
|
110
|
-
const tableName = basename(file, ".json");
|
|
111
|
-
await connection.run(
|
|
112
|
-
`CREATE OR REPLACE VIEW ${tableName} AS SELECT * FROM read_json('${filePath}', auto_detect=true, format='auto', timestampformat='iso', dateformat='iso')`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
} catch (error) {
|
|
116
|
-
if (error.code !== "ENOENT") {
|
|
117
|
-
throw new DatabaseError(`Failed to register JSON files from ${dataDir}`, {
|
|
118
|
-
dataDir,
|
|
119
|
-
originalError: error instanceof Error ? error.message : String(error)
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function convertBigInts(obj) {
|
|
125
|
-
if (obj === null || obj === void 0) return obj;
|
|
126
|
-
if (typeof obj === "bigint") return Number(obj);
|
|
127
|
-
if (typeof obj === "object" && !Array.isArray(obj) && "micros" in obj && Object.keys(obj).length === 1 && (typeof obj.micros === "number" || typeof obj.micros === "bigint")) {
|
|
128
|
-
const micros = typeof obj.micros === "bigint" ? Number(obj.micros) : obj.micros;
|
|
129
|
-
const milliseconds = micros / 1e3;
|
|
130
|
-
return new Date(milliseconds);
|
|
131
|
-
}
|
|
132
|
-
if (Array.isArray(obj)) return obj.map(convertBigInts);
|
|
133
|
-
if (typeof obj === "object") {
|
|
134
|
-
const result = {};
|
|
135
|
-
for (const key in obj) {
|
|
136
|
-
result[key] = convertBigInts(obj[key]);
|
|
137
|
-
}
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
return obj;
|
|
141
|
-
}
|
|
142
|
-
async function getDatabase(options = {}) {
|
|
143
|
-
const connection = await createDuckDBConnection(options);
|
|
144
|
-
const writeStrategy = options.writeStrategy || "none";
|
|
145
|
-
const dataDir = options.dataDir || "./data";
|
|
146
|
-
const url = resolveDuckDBUrl(options.url || ":memory:");
|
|
147
|
-
const insert = async (table2, data) => {
|
|
148
|
-
const records = Array.isArray(data) ? data : [data];
|
|
149
|
-
if (records.length === 0) {
|
|
150
|
-
return { operation: "insert", affected: 0 };
|
|
151
|
-
}
|
|
152
|
-
const keys = Object.keys(records[0]);
|
|
153
|
-
const values = [];
|
|
154
|
-
let paramIdx = 1;
|
|
155
|
-
const placeholders = records.map((record) => {
|
|
156
|
-
const rowPlaceholders = keys.map((key) => {
|
|
157
|
-
const value = record[key];
|
|
158
|
-
if (value === null || value === void 0) {
|
|
159
|
-
return "NULL";
|
|
160
|
-
} else if (value === "" && typeof value === "string") {
|
|
161
|
-
values.push(value);
|
|
162
|
-
return `CAST($${paramIdx++} AS TEXT)`;
|
|
163
|
-
} else if (value instanceof Date) {
|
|
164
|
-
values.push(value.toISOString());
|
|
165
|
-
return `$${paramIdx++}`;
|
|
166
|
-
} else if (Array.isArray(value)) {
|
|
167
|
-
values.push(JSON.stringify(value));
|
|
168
|
-
return `CAST($${paramIdx++} AS JSON)`;
|
|
169
|
-
} else if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype) {
|
|
170
|
-
values.push(JSON.stringify(value));
|
|
171
|
-
return `CAST($${paramIdx++} AS JSON)`;
|
|
172
|
-
} else {
|
|
173
|
-
values.push(value);
|
|
174
|
-
return `$${paramIdx++}`;
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
return `(${rowPlaceholders.join(", ")})`;
|
|
178
|
-
}).join(", ");
|
|
179
|
-
const sql = `INSERT INTO ${table2} (${keys.join(", ")}) VALUES ${placeholders}`;
|
|
180
|
-
try {
|
|
181
|
-
await connection.run(sql, values);
|
|
182
|
-
const affected = records.length;
|
|
183
|
-
if (writeStrategy === "immediate") {
|
|
184
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
185
|
-
}
|
|
186
|
-
return { operation: "insert", affected };
|
|
187
|
-
} catch (e) {
|
|
188
|
-
throw new DatabaseError("Failed to insert records into table", {
|
|
189
|
-
table: table2,
|
|
190
|
-
sql,
|
|
191
|
-
values,
|
|
192
|
-
originalError: formatDbError(e)
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
const get = async (table2, where) => {
|
|
197
|
-
const { sql: whereClause, values } = buildWhere(where, 1, "duckdb");
|
|
198
|
-
const sql = `SELECT * FROM ${table2} ${whereClause} LIMIT 1`;
|
|
199
|
-
try {
|
|
200
|
-
const reader = await connection.runAndReadAll(sql, values);
|
|
201
|
-
const rows = reader.getRowObjects();
|
|
202
|
-
return rows.length > 0 ? convertBigInts(rows[0]) : null;
|
|
203
|
-
} catch (e) {
|
|
204
|
-
throw new DatabaseError("Failed to retrieve record from table", {
|
|
205
|
-
table: table2,
|
|
206
|
-
sql,
|
|
207
|
-
values,
|
|
208
|
-
originalError: formatDbError(e)
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
const list = async (table2, where) => {
|
|
213
|
-
const { sql: whereClause, values } = buildWhere(where, 1, "duckdb");
|
|
214
|
-
const sql = `SELECT * FROM ${table2} ${whereClause}`;
|
|
215
|
-
try {
|
|
216
|
-
const reader = await connection.runAndReadAll(sql, values);
|
|
217
|
-
return convertBigInts(reader.getRowObjects());
|
|
218
|
-
} catch (e) {
|
|
219
|
-
throw new DatabaseError("Failed to list records from table", {
|
|
220
|
-
table: table2,
|
|
221
|
-
sql,
|
|
222
|
-
values,
|
|
223
|
-
originalError: formatDbError(e)
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
const update = async (table2, where, data) => {
|
|
228
|
-
const keys = Object.keys(data);
|
|
229
|
-
const setClause = keys.map((key, idx) => `${key} = $${idx + 1}`).join(", ");
|
|
230
|
-
const { sql: whereClause, values: whereValues } = buildWhere(
|
|
231
|
-
where,
|
|
232
|
-
keys.length + 1,
|
|
233
|
-
"duckdb"
|
|
234
|
-
);
|
|
235
|
-
const sql = `UPDATE ${table2} SET ${setClause} ${whereClause}`;
|
|
236
|
-
const values = [...Object.values(data), ...whereValues];
|
|
237
|
-
try {
|
|
238
|
-
await connection.run(sql, values);
|
|
239
|
-
if (writeStrategy === "immediate") {
|
|
240
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
241
|
-
}
|
|
242
|
-
return { operation: "update", affected: 1 };
|
|
243
|
-
} catch (e) {
|
|
244
|
-
throw new DatabaseError("Failed to update records in table", {
|
|
245
|
-
table: table2,
|
|
246
|
-
sql,
|
|
247
|
-
values,
|
|
248
|
-
originalError: formatDbError(e)
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
const buildDuckDBValueExpression = (value, values, paramIdx) => {
|
|
253
|
-
if (value === null || value === void 0) {
|
|
254
|
-
return "NULL";
|
|
255
|
-
}
|
|
256
|
-
if (value === "" && typeof value === "string") {
|
|
257
|
-
values.push(value);
|
|
258
|
-
return `CAST($${paramIdx.value++} AS TEXT)`;
|
|
259
|
-
}
|
|
260
|
-
if (value instanceof Date) {
|
|
261
|
-
values.push(value.toISOString());
|
|
262
|
-
return `$${paramIdx.value++}`;
|
|
263
|
-
}
|
|
264
|
-
if (Array.isArray(value)) {
|
|
265
|
-
values.push(JSON.stringify(value));
|
|
266
|
-
return `CAST($${paramIdx.value++} AS JSON)`;
|
|
267
|
-
}
|
|
268
|
-
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype) {
|
|
269
|
-
values.push(JSON.stringify(value));
|
|
270
|
-
return `CAST($${paramIdx.value++} AS JSON)`;
|
|
271
|
-
}
|
|
272
|
-
values.push(value);
|
|
273
|
-
return `$${paramIdx.value++}`;
|
|
274
|
-
};
|
|
275
|
-
const executeNullAwareDuckDBUpsert = async (table2, conflictColumns, data) => {
|
|
276
|
-
const conflictWhere = Object.fromEntries(
|
|
277
|
-
conflictColumns.map((col) => [col, data[col]])
|
|
278
|
-
);
|
|
279
|
-
const existing = await get(table2, conflictWhere);
|
|
280
|
-
if (!existing) {
|
|
281
|
-
return insert(table2, data);
|
|
282
|
-
}
|
|
283
|
-
const keys = Object.keys(data);
|
|
284
|
-
const values = [];
|
|
285
|
-
const paramIdx = { value: 1 };
|
|
286
|
-
const assignments = keys.map((key) => {
|
|
287
|
-
const valueExpr = buildDuckDBValueExpression(data[key], values, paramIdx);
|
|
288
|
-
return `"${key}" = ${valueExpr}`;
|
|
289
|
-
});
|
|
290
|
-
const { sql: whereClause, values: whereValues } = buildWhere(
|
|
291
|
-
conflictWhere,
|
|
292
|
-
paramIdx.value,
|
|
293
|
-
"duckdb"
|
|
294
|
-
);
|
|
295
|
-
const sql = `UPDATE ${table2} SET ${assignments.join(", ")} ${whereClause}`;
|
|
296
|
-
try {
|
|
297
|
-
await connection.run(sql, [...values, ...whereValues]);
|
|
298
|
-
if (writeStrategy === "immediate") {
|
|
299
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
300
|
-
}
|
|
301
|
-
return { operation: "upsert", affected: 1 };
|
|
302
|
-
} catch (e) {
|
|
303
|
-
throw new DatabaseError("Failed to upsert record into table", {
|
|
304
|
-
table: table2,
|
|
305
|
-
sql,
|
|
306
|
-
values: [...values, ...whereValues],
|
|
307
|
-
conflictColumns,
|
|
308
|
-
originalError: formatDbError(e)
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
const upsert = async (table2, conflictColumns, data, options2) => {
|
|
313
|
-
const missingColumns = conflictColumns.filter((col) => !(col in data));
|
|
314
|
-
if (missingColumns.length > 0) {
|
|
315
|
-
throw new DatabaseError("Conflict columns missing from data", {
|
|
316
|
-
table: table2,
|
|
317
|
-
conflictColumns,
|
|
318
|
-
missingColumns,
|
|
319
|
-
availableColumns: Object.keys(data),
|
|
320
|
-
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."
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
if (!options2?.nullsDistinct && conflictColumns.some((col) => data[col] === null)) {
|
|
324
|
-
return executeNullAwareDuckDBUpsert(table2, conflictColumns, data);
|
|
325
|
-
}
|
|
326
|
-
const keys = Object.keys(data);
|
|
327
|
-
const dataValues = Object.values(data);
|
|
328
|
-
const placeholders = [];
|
|
329
|
-
const values = [];
|
|
330
|
-
let paramIdx = 1;
|
|
331
|
-
for (const value of dataValues) {
|
|
332
|
-
if (value === null || value === void 0) {
|
|
333
|
-
placeholders.push("NULL");
|
|
334
|
-
} else if (value === "" && typeof value === "string") {
|
|
335
|
-
placeholders.push(`CAST($${paramIdx} AS TEXT)`);
|
|
336
|
-
values.push(value);
|
|
337
|
-
paramIdx++;
|
|
338
|
-
} else if (value instanceof Date) {
|
|
339
|
-
placeholders.push(`$${paramIdx}`);
|
|
340
|
-
values.push(value.toISOString());
|
|
341
|
-
paramIdx++;
|
|
342
|
-
} else if (Array.isArray(value)) {
|
|
343
|
-
placeholders.push(`CAST($${paramIdx} AS JSON)`);
|
|
344
|
-
values.push(JSON.stringify(value));
|
|
345
|
-
paramIdx++;
|
|
346
|
-
} else if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype) {
|
|
347
|
-
placeholders.push(`CAST($${paramIdx} AS JSON)`);
|
|
348
|
-
values.push(JSON.stringify(value));
|
|
349
|
-
paramIdx++;
|
|
350
|
-
} else {
|
|
351
|
-
placeholders.push(`$${paramIdx}`);
|
|
352
|
-
values.push(value);
|
|
353
|
-
paramIdx++;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
const updateSetParts = [];
|
|
357
|
-
for (let i = 0; i < keys.length; i++) {
|
|
358
|
-
const key = keys[i];
|
|
359
|
-
const value = dataValues[i];
|
|
360
|
-
if (value === null || value === void 0) {
|
|
361
|
-
updateSetParts.push(`${key} = NULL`);
|
|
362
|
-
} else if (value === "" && typeof value === "string") {
|
|
363
|
-
updateSetParts.push(`${key} = CAST($${paramIdx} AS TEXT)`);
|
|
364
|
-
values.push(value);
|
|
365
|
-
paramIdx++;
|
|
366
|
-
} else if (value instanceof Date) {
|
|
367
|
-
updateSetParts.push(`${key} = $${paramIdx}`);
|
|
368
|
-
values.push(value.toISOString());
|
|
369
|
-
paramIdx++;
|
|
370
|
-
} else if (Array.isArray(value)) {
|
|
371
|
-
updateSetParts.push(`${key} = CAST($${paramIdx} AS JSON)`);
|
|
372
|
-
values.push(JSON.stringify(value));
|
|
373
|
-
paramIdx++;
|
|
374
|
-
} else if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype) {
|
|
375
|
-
updateSetParts.push(`${key} = CAST($${paramIdx} AS JSON)`);
|
|
376
|
-
values.push(JSON.stringify(value));
|
|
377
|
-
paramIdx++;
|
|
378
|
-
} else {
|
|
379
|
-
updateSetParts.push(`${key} = $${paramIdx}`);
|
|
380
|
-
values.push(value);
|
|
381
|
-
paramIdx++;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
const conflict = conflictColumns.map((col) => `"${col}"`).join(", ");
|
|
385
|
-
const quotedKeys = keys.map((key) => `"${key}"`).join(", ");
|
|
386
|
-
const quotedUpdateSetParts = keys.map((key, i) => {
|
|
387
|
-
const part = updateSetParts[i];
|
|
388
|
-
const valueExpr = part.substring(part.indexOf("=") + 1).trim();
|
|
389
|
-
return `"${key}" = ${valueExpr}`;
|
|
390
|
-
});
|
|
391
|
-
const sql = `INSERT INTO ${table2} (${quotedKeys}) VALUES (${placeholders.join(", ")}) ON CONFLICT(${conflict}) DO UPDATE SET ${quotedUpdateSetParts.join(", ")}`;
|
|
392
|
-
try {
|
|
393
|
-
await connection.run(sql, values);
|
|
394
|
-
if (writeStrategy === "immediate") {
|
|
395
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
396
|
-
}
|
|
397
|
-
return { operation: "upsert", affected: 1 };
|
|
398
|
-
} catch (e) {
|
|
399
|
-
throw new DatabaseError("Failed to upsert record into table", {
|
|
400
|
-
table: table2,
|
|
401
|
-
sql,
|
|
402
|
-
values,
|
|
403
|
-
conflictColumns,
|
|
404
|
-
originalError: formatDbError(e)
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
const getOrInsert = async (table2, where, data) => {
|
|
409
|
-
const result = await get(table2, where);
|
|
410
|
-
if (result) return result;
|
|
411
|
-
await insert(table2, data);
|
|
412
|
-
const inserted = await get(table2, where);
|
|
413
|
-
if (!inserted) {
|
|
414
|
-
throw new DatabaseError("Failed to insert and retrieve record", {
|
|
415
|
-
table: table2,
|
|
416
|
-
where,
|
|
417
|
-
data
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
return inserted;
|
|
421
|
-
};
|
|
422
|
-
const deleteRecords = async (table2, where) => {
|
|
423
|
-
validateTableName(table2);
|
|
424
|
-
const keys = Object.keys(where);
|
|
425
|
-
if (keys.length === 0) {
|
|
426
|
-
throw new DatabaseError(
|
|
427
|
-
"DELETE requires at least one WHERE condition to prevent accidental deletion of all records",
|
|
428
|
-
{ table: table2 }
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
const { sql: whereClause, values } = buildWhere(where, 1, "duckdb");
|
|
432
|
-
const sql = `DELETE FROM ${table2} ${whereClause}`;
|
|
433
|
-
try {
|
|
434
|
-
await connection.run(sql, values);
|
|
435
|
-
if (writeStrategy === "immediate") {
|
|
436
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
437
|
-
}
|
|
438
|
-
return { operation: "delete", affected: 1 };
|
|
439
|
-
} catch (e) {
|
|
440
|
-
throw new DatabaseError("Failed to delete records from table", {
|
|
441
|
-
table: table2,
|
|
442
|
-
sql,
|
|
443
|
-
values,
|
|
444
|
-
originalError: formatDbError(e)
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
const count = async (table2, where) => {
|
|
449
|
-
validateTableName(table2);
|
|
450
|
-
try {
|
|
451
|
-
if (!where || Object.keys(where).length === 0) {
|
|
452
|
-
const result2 = await connection.runAndReadAll(
|
|
453
|
-
`SELECT COUNT(*) as count FROM ${table2}`
|
|
454
|
-
);
|
|
455
|
-
const rows2 = result2.getRowObjects();
|
|
456
|
-
return Number(rows2[0]?.count) || 0;
|
|
457
|
-
}
|
|
458
|
-
const { sql: whereClause, values } = buildWhere(where, 1, "duckdb");
|
|
459
|
-
const sql = `SELECT COUNT(*) as count FROM ${table2} ${whereClause}`;
|
|
460
|
-
const result = await connection.runAndReadAll(sql, values);
|
|
461
|
-
const rows = result.getRowObjects();
|
|
462
|
-
return Number(rows[0]?.count) || 0;
|
|
463
|
-
} catch (e) {
|
|
464
|
-
throw new DatabaseError("Failed to count records in table", {
|
|
465
|
-
table: table2,
|
|
466
|
-
where,
|
|
467
|
-
originalError: formatDbError(e)
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
const tableExists = async (tableName) => {
|
|
472
|
-
try {
|
|
473
|
-
await connection.runAndReadAll(`SELECT * FROM ${tableName} LIMIT 1`);
|
|
474
|
-
return true;
|
|
475
|
-
} catch {
|
|
476
|
-
return false;
|
|
477
|
-
}
|
|
478
|
-
};
|
|
479
|
-
const exportTableToJSON = async (connection2, table2, dataDir2) => {
|
|
480
|
-
const filePath = join(dataDir2, `${table2}.json`);
|
|
481
|
-
await connection2.run(
|
|
482
|
-
`COPY (SELECT * FROM ${table2}) TO '${filePath}' (FORMAT JSON, ARRAY true)`
|
|
483
|
-
);
|
|
484
|
-
};
|
|
485
|
-
const exportTable = async (table2) => {
|
|
486
|
-
if (writeStrategy === "none") {
|
|
487
|
-
throw new DatabaseError(
|
|
488
|
-
"Cannot export table: write strategy is set to none",
|
|
489
|
-
{ table: table2, writeStrategy }
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
await exportTableToJSON(connection, table2, dataDir);
|
|
493
|
-
};
|
|
494
|
-
const table = (tableName) => ({
|
|
495
|
-
insert: (data) => insert(tableName, data),
|
|
496
|
-
get: (where) => get(tableName, where),
|
|
497
|
-
list: (where) => list(tableName, where)
|
|
498
|
-
});
|
|
499
|
-
const parseTemplate = (strings, ...vars) => {
|
|
500
|
-
let sql = strings[0];
|
|
501
|
-
const values = [];
|
|
502
|
-
for (let i = 0; i < vars.length; i++) {
|
|
503
|
-
values.push(vars[i]);
|
|
504
|
-
sql += `$${i + 1}${strings[i + 1]}`;
|
|
505
|
-
}
|
|
506
|
-
return { sql, values };
|
|
507
|
-
};
|
|
508
|
-
const many = async (strings, ...vars) => {
|
|
509
|
-
const { sql, values } = parseTemplate(strings, ...vars);
|
|
510
|
-
try {
|
|
511
|
-
const reader = await connection.runAndReadAll(sql, values);
|
|
512
|
-
return convertBigInts(reader.getRowObjects());
|
|
513
|
-
} catch (e) {
|
|
514
|
-
throw new DatabaseError("Failed to execute many query", {
|
|
515
|
-
sql,
|
|
516
|
-
values,
|
|
517
|
-
originalError: formatDbError(e)
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
const single = async (strings, ...vars) => {
|
|
522
|
-
const { sql, values } = parseTemplate(strings, ...vars);
|
|
523
|
-
try {
|
|
524
|
-
const reader = await connection.runAndReadAll(sql, values);
|
|
525
|
-
const rows = reader.getRowObjects();
|
|
526
|
-
return rows[0] ? convertBigInts(rows[0]) : null;
|
|
527
|
-
} catch (e) {
|
|
528
|
-
throw new DatabaseError("Failed to execute single query", {
|
|
529
|
-
sql,
|
|
530
|
-
values,
|
|
531
|
-
originalError: formatDbError(e)
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
const pluck = async (strings, ...vars) => {
|
|
536
|
-
const { sql, values } = parseTemplate(strings, ...vars);
|
|
537
|
-
try {
|
|
538
|
-
const reader = await connection.runAndReadAll(sql, values);
|
|
539
|
-
const rows = reader.getRowObjects();
|
|
540
|
-
if (rows.length === 0) return null;
|
|
541
|
-
const firstRow = rows[0];
|
|
542
|
-
const firstKey = Object.keys(firstRow)[0];
|
|
543
|
-
return convertBigInts(firstRow[firstKey]);
|
|
544
|
-
} catch (e) {
|
|
545
|
-
throw new DatabaseError("Failed to execute pluck query", {
|
|
546
|
-
sql,
|
|
547
|
-
values,
|
|
548
|
-
originalError: formatDbError(e)
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
const execute = async (strings, ...vars) => {
|
|
553
|
-
const { sql, values } = parseTemplate(strings, ...vars);
|
|
554
|
-
try {
|
|
555
|
-
await connection.run(sql, values);
|
|
556
|
-
} catch (e) {
|
|
557
|
-
throw new DatabaseError("Failed to execute query", {
|
|
558
|
-
sql,
|
|
559
|
-
values,
|
|
560
|
-
originalError: formatDbError(e)
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
};
|
|
564
|
-
const query = async (str, ...values) => {
|
|
565
|
-
const sql = str;
|
|
566
|
-
const args = Array.isArray(values[0]) ? values[0] : values;
|
|
567
|
-
try {
|
|
568
|
-
const reader = await connection.runAndReadAll(sql, args);
|
|
569
|
-
const rows = convertBigInts(reader.getRowObjects());
|
|
570
|
-
return {
|
|
571
|
-
command: sql.split(" ")[0].toUpperCase(),
|
|
572
|
-
rowCount: rows.length,
|
|
573
|
-
oid: null,
|
|
574
|
-
fields: rows.length > 0 ? Object.keys(rows[0]).map((name) => ({
|
|
575
|
-
name,
|
|
576
|
-
tableID: 0,
|
|
577
|
-
columnID: 0,
|
|
578
|
-
dataTypeID: 0,
|
|
579
|
-
dataTypeSize: -1,
|
|
580
|
-
dataTypeModifier: -1,
|
|
581
|
-
format: "text"
|
|
582
|
-
})) : [],
|
|
583
|
-
rows
|
|
584
|
-
};
|
|
585
|
-
} catch (e) {
|
|
586
|
-
throw new DatabaseError("Failed to execute raw query", {
|
|
587
|
-
sql,
|
|
588
|
-
args,
|
|
589
|
-
originalError: formatDbError(e)
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
const oo = many;
|
|
594
|
-
const oO = single;
|
|
595
|
-
const ox = pluck;
|
|
596
|
-
const xx = execute;
|
|
597
|
-
const syncSchema = async (schema) => {
|
|
598
|
-
const statements = schema.trim().split(";").filter((stmt) => stmt.trim() !== "");
|
|
599
|
-
const createTableStatements = [];
|
|
600
|
-
const indexStatements = [];
|
|
601
|
-
for (const stmt of statements) {
|
|
602
|
-
const trimmed = stmt.trim();
|
|
603
|
-
if (!trimmed) continue;
|
|
604
|
-
if (trimmed.startsWith("CREATE INDEX") || trimmed.startsWith("CREATE UNIQUE INDEX")) {
|
|
605
|
-
indexStatements.push(trimmed);
|
|
606
|
-
} else if (trimmed.startsWith("CREATE TABLE")) {
|
|
607
|
-
createTableStatements.push(trimmed);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
for (const ddl of createTableStatements) {
|
|
611
|
-
const { ddl: transformedDDL, indexes: remainingIndexes } = convertUniqueIndexesToInlineConstraints(ddl, indexStatements);
|
|
612
|
-
try {
|
|
613
|
-
await connection.run(transformedDDL);
|
|
614
|
-
} catch (e) {
|
|
615
|
-
console.error("Schema sync error (CREATE TABLE):", e);
|
|
616
|
-
}
|
|
617
|
-
for (const indexSQL of remainingIndexes) {
|
|
618
|
-
try {
|
|
619
|
-
await connection.run(indexSQL);
|
|
620
|
-
} catch (e) {
|
|
621
|
-
console.error("Schema sync error (CREATE INDEX):", e);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
};
|
|
626
|
-
const initializeSchemas = async (options2) => {
|
|
627
|
-
const schemaManager = new DatabaseSchemaManager();
|
|
628
|
-
const currentDb = {
|
|
629
|
-
url,
|
|
630
|
-
client: connection,
|
|
631
|
-
query,
|
|
632
|
-
insert,
|
|
633
|
-
update,
|
|
634
|
-
upsert,
|
|
635
|
-
get,
|
|
636
|
-
list,
|
|
637
|
-
getOrInsert,
|
|
638
|
-
delete: deleteRecords,
|
|
639
|
-
count,
|
|
640
|
-
table,
|
|
641
|
-
tableExists,
|
|
642
|
-
many,
|
|
643
|
-
single,
|
|
644
|
-
pluck,
|
|
645
|
-
execute,
|
|
646
|
-
oo,
|
|
647
|
-
oO,
|
|
648
|
-
ox,
|
|
649
|
-
xx,
|
|
650
|
-
syncSchema
|
|
651
|
-
};
|
|
652
|
-
await schemaManager.initializeSchemas(currentDb, options2);
|
|
653
|
-
};
|
|
654
|
-
const getTableSchema = async (table2) => {
|
|
655
|
-
validateTableName(table2);
|
|
656
|
-
try {
|
|
657
|
-
const exists = await tableExists(table2);
|
|
658
|
-
if (!exists) {
|
|
659
|
-
return null;
|
|
660
|
-
}
|
|
661
|
-
const columnRows = await many`
|
|
662
|
-
SELECT
|
|
663
|
-
column_name,
|
|
664
|
-
data_type,
|
|
665
|
-
is_nullable,
|
|
666
|
-
column_default
|
|
667
|
-
FROM information_schema.columns
|
|
668
|
-
WHERE table_name = ${table2}
|
|
669
|
-
ORDER BY ordinal_position
|
|
670
|
-
`;
|
|
671
|
-
const pkRows = await many`
|
|
672
|
-
SELECT column_name
|
|
673
|
-
FROM duckdb_constraints() con
|
|
674
|
-
JOIN duckdb_columns() cols
|
|
675
|
-
ON con.table_oid = cols.table_oid
|
|
676
|
-
WHERE con.table_name = ${table2}
|
|
677
|
-
AND con.constraint_type = 'PRIMARY KEY'
|
|
678
|
-
AND cols.column_name = ANY(con.constraint_column_names)
|
|
679
|
-
`;
|
|
680
|
-
const pkColumns = new Set(pkRows.map((row) => row.column_name));
|
|
681
|
-
const columns = {};
|
|
682
|
-
for (const row of columnRows) {
|
|
683
|
-
const colName = row.column_name;
|
|
684
|
-
columns[colName] = {
|
|
685
|
-
type: row.data_type,
|
|
686
|
-
primaryKey: pkColumns.has(colName),
|
|
687
|
-
notNull: row.is_nullable === "NO",
|
|
688
|
-
defaultValue: row.column_default
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
const indexRows = await many`
|
|
692
|
-
SELECT
|
|
693
|
-
index_name,
|
|
694
|
-
sql
|
|
695
|
-
FROM duckdb_indexes()
|
|
696
|
-
WHERE table_name = ${table2}
|
|
697
|
-
AND NOT is_primary
|
|
698
|
-
`;
|
|
699
|
-
const indexes = [];
|
|
700
|
-
for (const row of indexRows) {
|
|
701
|
-
const indexName = row.index_name;
|
|
702
|
-
const indexDef = row.sql || "";
|
|
703
|
-
const colMatch = indexDef.match(/\(([^)]+)\)/);
|
|
704
|
-
const indexColumns = colMatch ? colMatch[1].split(",").map((col) => col.trim()) : [];
|
|
705
|
-
const isUnique = indexDef.toUpperCase().includes("UNIQUE");
|
|
706
|
-
indexes.push({
|
|
707
|
-
name: indexName,
|
|
708
|
-
columns: indexColumns,
|
|
709
|
-
unique: isUnique
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
const fkRows = await many`
|
|
713
|
-
SELECT
|
|
714
|
-
constraint_column_names,
|
|
715
|
-
constraint_column_indexes,
|
|
716
|
-
constraint_text
|
|
717
|
-
FROM duckdb_constraints()
|
|
718
|
-
WHERE table_name = ${table2}
|
|
719
|
-
AND constraint_type = 'FOREIGN KEY'
|
|
720
|
-
`;
|
|
721
|
-
const foreignKeys = [];
|
|
722
|
-
for (const fkRow of fkRows) {
|
|
723
|
-
const fkText = fkRow.constraint_text || "";
|
|
724
|
-
const referencesMatch = fkText.match(
|
|
725
|
-
/REFERENCES\s+(\w+)\s*\(([^)]+)\)/i
|
|
726
|
-
);
|
|
727
|
-
if (referencesMatch && Array.isArray(fkRow.constraint_column_names) && fkRow.constraint_column_names.length > 0) {
|
|
728
|
-
const columnName = fkRow.constraint_column_names[0];
|
|
729
|
-
const referencedTable = referencesMatch[1];
|
|
730
|
-
const referencedColumn = referencesMatch[2].trim();
|
|
731
|
-
const onDeleteMatch = fkText.match(/ON DELETE\s+(\w+)/i);
|
|
732
|
-
const onUpdateMatch = fkText.match(/ON UPDATE\s+(\w+)/i);
|
|
733
|
-
foreignKeys.push({
|
|
734
|
-
column: columnName,
|
|
735
|
-
referencesTable: referencedTable,
|
|
736
|
-
referencesColumn: referencedColumn,
|
|
737
|
-
onDelete: onDeleteMatch ? onDeleteMatch[1] : void 0,
|
|
738
|
-
onUpdate: onUpdateMatch ? onUpdateMatch[1] : void 0
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
return {
|
|
743
|
-
tableName: table2,
|
|
744
|
-
columns,
|
|
745
|
-
indexes,
|
|
746
|
-
foreignKeys
|
|
747
|
-
};
|
|
748
|
-
} catch (e) {
|
|
749
|
-
throw new DatabaseError("Failed to retrieve table schema", {
|
|
750
|
-
table: table2,
|
|
751
|
-
originalError: formatDbError(e)
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
};
|
|
755
|
-
const alterTable = {
|
|
756
|
-
/**
|
|
757
|
-
* Adds a new column to an existing table
|
|
758
|
-
*
|
|
759
|
-
* @param table - Table name
|
|
760
|
-
* @param column - Column definition with name
|
|
761
|
-
* @returns Promise that resolves when column is added
|
|
762
|
-
* @throws Error if the alter operation fails
|
|
763
|
-
*/
|
|
764
|
-
addColumn: async (table2, column) => {
|
|
765
|
-
validateTableName(table2);
|
|
766
|
-
validateColumnName(column.name);
|
|
767
|
-
try {
|
|
768
|
-
const sql = generateAddColumnStatement(table2, column, "duckdb");
|
|
769
|
-
await connection.run(sql);
|
|
770
|
-
} catch (e) {
|
|
771
|
-
throw new DatabaseError("Failed to add column to table", {
|
|
772
|
-
table: table2,
|
|
773
|
-
column: column.name,
|
|
774
|
-
originalError: formatDbError(e)
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
},
|
|
778
|
-
/**
|
|
779
|
-
* Adds a new index to an existing table
|
|
780
|
-
*
|
|
781
|
-
* @param table - Table name
|
|
782
|
-
* @param index - Index definition
|
|
783
|
-
* @returns Promise that resolves when index is created
|
|
784
|
-
* @throws Error if the create index operation fails
|
|
785
|
-
*/
|
|
786
|
-
addIndex: async (table2, index) => {
|
|
787
|
-
validateTableName(table2);
|
|
788
|
-
validateIndexName(index.name);
|
|
789
|
-
for (const col of index.columns) {
|
|
790
|
-
validateColumnName(col);
|
|
791
|
-
}
|
|
792
|
-
try {
|
|
793
|
-
const sql = generateCreateIndexStatement(table2, index);
|
|
794
|
-
await connection.run(sql);
|
|
795
|
-
} catch (e) {
|
|
796
|
-
throw new DatabaseError("Failed to create index on table", {
|
|
797
|
-
table: table2,
|
|
798
|
-
index: index.name,
|
|
799
|
-
originalError: formatDbError(e)
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
};
|
|
804
|
-
const transaction = async (callback) => {
|
|
805
|
-
try {
|
|
806
|
-
await connection.run("BEGIN TRANSACTION");
|
|
807
|
-
const txDb = {
|
|
808
|
-
url,
|
|
809
|
-
client: connection,
|
|
810
|
-
insert,
|
|
811
|
-
get,
|
|
812
|
-
list,
|
|
813
|
-
update,
|
|
814
|
-
upsert,
|
|
815
|
-
getOrInsert,
|
|
816
|
-
delete: deleteRecords,
|
|
817
|
-
count,
|
|
818
|
-
table,
|
|
819
|
-
many,
|
|
820
|
-
single,
|
|
821
|
-
pluck,
|
|
822
|
-
execute,
|
|
823
|
-
query,
|
|
824
|
-
oo,
|
|
825
|
-
oO,
|
|
826
|
-
ox,
|
|
827
|
-
xx,
|
|
828
|
-
tableExists,
|
|
829
|
-
syncSchema,
|
|
830
|
-
transaction
|
|
831
|
-
};
|
|
832
|
-
const result = await callback(txDb);
|
|
833
|
-
await connection.run("COMMIT");
|
|
834
|
-
return result;
|
|
835
|
-
} catch (error) {
|
|
836
|
-
await connection.run("ROLLBACK");
|
|
837
|
-
throw error;
|
|
838
|
-
}
|
|
839
|
-
};
|
|
840
|
-
const beginTransaction = async () => {
|
|
841
|
-
await connection.run("BEGIN TRANSACTION");
|
|
842
|
-
let active = true;
|
|
843
|
-
const commit = async () => {
|
|
844
|
-
if (!active) {
|
|
845
|
-
throw new DatabaseError("Transaction already ended", {});
|
|
846
|
-
}
|
|
847
|
-
await connection.run("COMMIT");
|
|
848
|
-
active = false;
|
|
849
|
-
};
|
|
850
|
-
const rollback = async () => {
|
|
851
|
-
if (!active) {
|
|
852
|
-
throw new DatabaseError("Transaction already ended", {});
|
|
853
|
-
}
|
|
854
|
-
await connection.run("ROLLBACK");
|
|
855
|
-
active = false;
|
|
856
|
-
};
|
|
857
|
-
const isActive = () => active;
|
|
858
|
-
const txHandle = {
|
|
859
|
-
url,
|
|
860
|
-
client: connection,
|
|
861
|
-
insert,
|
|
862
|
-
get,
|
|
863
|
-
list,
|
|
864
|
-
update,
|
|
865
|
-
upsert,
|
|
866
|
-
getOrInsert,
|
|
867
|
-
delete: deleteRecords,
|
|
868
|
-
count,
|
|
869
|
-
table,
|
|
870
|
-
many,
|
|
871
|
-
single,
|
|
872
|
-
pluck,
|
|
873
|
-
execute,
|
|
874
|
-
query,
|
|
875
|
-
oo,
|
|
876
|
-
oO,
|
|
877
|
-
ox,
|
|
878
|
-
xx,
|
|
879
|
-
tableExists,
|
|
880
|
-
syncSchema,
|
|
881
|
-
transaction,
|
|
882
|
-
commit,
|
|
883
|
-
rollback,
|
|
884
|
-
isActive
|
|
885
|
-
};
|
|
886
|
-
return txHandle;
|
|
887
|
-
};
|
|
888
|
-
return {
|
|
889
|
-
url,
|
|
890
|
-
requiresSchemaCheck: true,
|
|
891
|
-
client: connection,
|
|
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
|
-
// DuckDB-specific export method
|
|
918
|
-
exportTable
|
|
919
|
-
};
|
|
920
|
-
}
|
|
921
|
-
export {
|
|
922
|
-
getDatabase
|
|
923
|
-
};
|
|
924
|
-
//# sourceMappingURL=duckdb-B6m78QdL.js.map
|