@leonardovida-md/drizzle-neo-duckdb 1.1.1 → 1.1.3
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/README.md +44 -85
- package/dist/client.d.ts +15 -1
- package/dist/columns.d.ts +3 -2
- package/dist/driver.d.ts +7 -3
- package/dist/duckdb-introspect.mjs +595 -50
- package/dist/helpers.mjs +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +621 -50
- package/dist/options.d.ts +10 -0
- package/dist/session.d.ts +11 -5
- package/dist/sql/query-rewriters.d.ts +12 -0
- package/package.json +1 -1
- package/src/client.ts +300 -40
- package/src/columns.ts +51 -4
- package/src/driver.ts +30 -5
- package/src/index.ts +1 -0
- package/src/options.ts +40 -0
- package/src/session.ts +128 -27
- package/src/sql/query-rewriters.ts +503 -0
|
@@ -161,6 +161,9 @@ function walkRight(source, scrubbed, start) {
|
|
|
161
161
|
return [scrubbed.length, source.slice(start)];
|
|
162
162
|
}
|
|
163
163
|
function adaptArrayOperators(query) {
|
|
164
|
+
if (query.indexOf("@>") === -1 && query.indexOf("<@") === -1 && query.indexOf("&&") === -1) {
|
|
165
|
+
return query;
|
|
166
|
+
}
|
|
164
167
|
let rewritten = query;
|
|
165
168
|
let scrubbed = scrubForRewrite(query);
|
|
166
169
|
let searchStart = 0;
|
|
@@ -180,6 +183,328 @@ function adaptArrayOperators(query) {
|
|
|
180
183
|
}
|
|
181
184
|
return rewritten;
|
|
182
185
|
}
|
|
186
|
+
function extractQuotedIdentifier(original, start) {
|
|
187
|
+
if (original[start] !== '"') {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
let pos = start + 1;
|
|
191
|
+
while (pos < original.length && original[pos] !== '"') {
|
|
192
|
+
if (original[pos] === '"' && original[pos + 1] === '"') {
|
|
193
|
+
pos += 2;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
pos++;
|
|
197
|
+
}
|
|
198
|
+
if (pos >= original.length) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
name: original.slice(start + 1, pos),
|
|
203
|
+
end: pos + 1
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function findMainFromClause(scrubbed) {
|
|
207
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
208
|
+
let searchStart = 0;
|
|
209
|
+
const withMatch = /\bwith\s+/i.exec(lowerScrubbed);
|
|
210
|
+
if (withMatch) {
|
|
211
|
+
let depth = 0;
|
|
212
|
+
let pos = withMatch.index + withMatch[0].length;
|
|
213
|
+
while (pos < scrubbed.length) {
|
|
214
|
+
const char = scrubbed[pos];
|
|
215
|
+
if (char === "(") {
|
|
216
|
+
depth++;
|
|
217
|
+
} else if (char === ")") {
|
|
218
|
+
depth--;
|
|
219
|
+
} else if (depth === 0) {
|
|
220
|
+
const remaining = lowerScrubbed.slice(pos);
|
|
221
|
+
if (/^\s*select\s+/i.test(remaining)) {
|
|
222
|
+
searchStart = pos;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
pos++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const fromPattern = /\bfrom\s+/gi;
|
|
230
|
+
fromPattern.lastIndex = searchStart;
|
|
231
|
+
const fromMatch = fromPattern.exec(lowerScrubbed);
|
|
232
|
+
return fromMatch ? fromMatch.index + fromMatch[0].length : -1;
|
|
233
|
+
}
|
|
234
|
+
function parseTableSources(original, scrubbed) {
|
|
235
|
+
const sources = [];
|
|
236
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
237
|
+
const fromPos = findMainFromClause(scrubbed);
|
|
238
|
+
if (fromPos < 0) {
|
|
239
|
+
return sources;
|
|
240
|
+
}
|
|
241
|
+
const fromTable = parseTableRef(original, scrubbed, fromPos);
|
|
242
|
+
if (fromTable) {
|
|
243
|
+
sources.push(fromTable);
|
|
244
|
+
}
|
|
245
|
+
const joinPattern = /\b(left\s+|right\s+|inner\s+|full\s+|cross\s+)?join\s+/gi;
|
|
246
|
+
joinPattern.lastIndex = fromPos;
|
|
247
|
+
let joinMatch;
|
|
248
|
+
while ((joinMatch = joinPattern.exec(lowerScrubbed)) !== null) {
|
|
249
|
+
const tableStart = joinMatch.index + joinMatch[0].length;
|
|
250
|
+
const joinTable = parseTableRef(original, scrubbed, tableStart);
|
|
251
|
+
if (joinTable) {
|
|
252
|
+
sources.push(joinTable);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return sources;
|
|
256
|
+
}
|
|
257
|
+
function parseTableRef(original, scrubbed, start) {
|
|
258
|
+
let pos = start;
|
|
259
|
+
while (pos < scrubbed.length && isWhitespace(scrubbed[pos])) {
|
|
260
|
+
pos++;
|
|
261
|
+
}
|
|
262
|
+
if (original[pos] !== '"') {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const nameStart = pos;
|
|
266
|
+
const firstIdent = extractQuotedIdentifier(original, pos);
|
|
267
|
+
if (!firstIdent) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
let name = firstIdent.name;
|
|
271
|
+
pos = firstIdent.end;
|
|
272
|
+
let afterName = pos;
|
|
273
|
+
while (afterName < scrubbed.length && isWhitespace(scrubbed[afterName])) {
|
|
274
|
+
afterName++;
|
|
275
|
+
}
|
|
276
|
+
if (scrubbed[afterName] === ".") {
|
|
277
|
+
afterName++;
|
|
278
|
+
while (afterName < scrubbed.length && isWhitespace(scrubbed[afterName])) {
|
|
279
|
+
afterName++;
|
|
280
|
+
}
|
|
281
|
+
if (original[afterName] === '"') {
|
|
282
|
+
const tableIdent = extractQuotedIdentifier(original, afterName);
|
|
283
|
+
if (tableIdent) {
|
|
284
|
+
name = tableIdent.name;
|
|
285
|
+
pos = tableIdent.end;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
let alias;
|
|
290
|
+
let aliasPos = pos;
|
|
291
|
+
while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
|
|
292
|
+
aliasPos++;
|
|
293
|
+
}
|
|
294
|
+
const afterTable = scrubbed.slice(aliasPos).toLowerCase();
|
|
295
|
+
if (afterTable.startsWith("as ")) {
|
|
296
|
+
aliasPos += 3;
|
|
297
|
+
while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
|
|
298
|
+
aliasPos++;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (original[aliasPos] === '"' && !afterTable.startsWith("on ") && !afterTable.startsWith("left ") && !afterTable.startsWith("right ") && !afterTable.startsWith("inner ") && !afterTable.startsWith("full ") && !afterTable.startsWith("cross ") && !afterTable.startsWith("join ") && !afterTable.startsWith("where ") && !afterTable.startsWith("group ") && !afterTable.startsWith("order ") && !afterTable.startsWith("limit ") && !afterTable.startsWith("as ")) {
|
|
302
|
+
const aliasIdent = extractQuotedIdentifier(original, aliasPos);
|
|
303
|
+
if (aliasIdent) {
|
|
304
|
+
alias = aliasIdent.name;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
name,
|
|
309
|
+
alias,
|
|
310
|
+
position: nameStart
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function findJoinClauses(original, scrubbed, sources) {
|
|
314
|
+
const clauses = [];
|
|
315
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
316
|
+
const joinPattern = /\b(left\s+|right\s+|inner\s+|full\s+|cross\s+)?join\s+"[^"]*"(\s*\.\s*"[^"]*")?(\s+as)?(\s+"[^"]*")?\s+on\s+/gi;
|
|
317
|
+
let match;
|
|
318
|
+
let sourceIndex = 1;
|
|
319
|
+
while ((match = joinPattern.exec(lowerScrubbed)) !== null) {
|
|
320
|
+
const joinType = (match[1] || "").trim().toLowerCase();
|
|
321
|
+
const joinKeywordEnd = match.index + (match[1] || "").length + "join".length;
|
|
322
|
+
let tableStart = joinKeywordEnd;
|
|
323
|
+
while (tableStart < original.length && isWhitespace(original[tableStart])) {
|
|
324
|
+
tableStart++;
|
|
325
|
+
}
|
|
326
|
+
const tableIdent = extractQuotedIdentifier(original, tableStart);
|
|
327
|
+
if (!tableIdent)
|
|
328
|
+
continue;
|
|
329
|
+
let tableName = tableIdent.name;
|
|
330
|
+
let afterTable = tableIdent.end;
|
|
331
|
+
let checkPos = afterTable;
|
|
332
|
+
while (checkPos < scrubbed.length && isWhitespace(scrubbed[checkPos])) {
|
|
333
|
+
checkPos++;
|
|
334
|
+
}
|
|
335
|
+
if (scrubbed[checkPos] === ".") {
|
|
336
|
+
checkPos++;
|
|
337
|
+
while (checkPos < scrubbed.length && isWhitespace(scrubbed[checkPos])) {
|
|
338
|
+
checkPos++;
|
|
339
|
+
}
|
|
340
|
+
const realTableIdent = extractQuotedIdentifier(original, checkPos);
|
|
341
|
+
if (realTableIdent) {
|
|
342
|
+
tableName = realTableIdent.name;
|
|
343
|
+
afterTable = realTableIdent.end;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
let tableAlias;
|
|
347
|
+
let aliasPos = afterTable;
|
|
348
|
+
while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
|
|
349
|
+
aliasPos++;
|
|
350
|
+
}
|
|
351
|
+
const afterTableStr = scrubbed.slice(aliasPos).toLowerCase();
|
|
352
|
+
if (afterTableStr.startsWith("as ")) {
|
|
353
|
+
aliasPos += 3;
|
|
354
|
+
while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
|
|
355
|
+
aliasPos++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (original[aliasPos] === '"' && !afterTableStr.startsWith("on ")) {
|
|
359
|
+
const aliasIdent = extractQuotedIdentifier(original, aliasPos);
|
|
360
|
+
if (aliasIdent) {
|
|
361
|
+
tableAlias = aliasIdent.name;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const onStart = match.index + match[0].length;
|
|
365
|
+
const endPattern = /\b(left\s+join|right\s+join|inner\s+join|full\s+join|cross\s+join|join|where|group\s+by|order\s+by|limit|$)/i;
|
|
366
|
+
const remaining = lowerScrubbed.slice(onStart);
|
|
367
|
+
const endMatch = endPattern.exec(remaining);
|
|
368
|
+
const onEnd = endMatch ? onStart + endMatch.index : scrubbed.length;
|
|
369
|
+
let leftSource = "";
|
|
370
|
+
if (sourceIndex > 0 && sourceIndex <= sources.length) {
|
|
371
|
+
const prev = sources[sourceIndex - 1];
|
|
372
|
+
leftSource = prev?.alias || prev?.name || "";
|
|
373
|
+
}
|
|
374
|
+
const rightSource = tableAlias || tableName;
|
|
375
|
+
clauses.push({
|
|
376
|
+
joinType,
|
|
377
|
+
tableName,
|
|
378
|
+
tableAlias,
|
|
379
|
+
onStart,
|
|
380
|
+
onEnd,
|
|
381
|
+
leftSource,
|
|
382
|
+
rightSource
|
|
383
|
+
});
|
|
384
|
+
sourceIndex++;
|
|
385
|
+
}
|
|
386
|
+
return clauses;
|
|
387
|
+
}
|
|
388
|
+
function qualifyJoinColumns(query) {
|
|
389
|
+
const lowerQuery = query.toLowerCase();
|
|
390
|
+
if (!lowerQuery.includes("join")) {
|
|
391
|
+
return query;
|
|
392
|
+
}
|
|
393
|
+
const scrubbed = scrubForRewrite(query);
|
|
394
|
+
const sources = parseTableSources(query, scrubbed);
|
|
395
|
+
if (sources.length < 2) {
|
|
396
|
+
return query;
|
|
397
|
+
}
|
|
398
|
+
const joinClauses = findJoinClauses(query, scrubbed, sources);
|
|
399
|
+
if (joinClauses.length === 0) {
|
|
400
|
+
return query;
|
|
401
|
+
}
|
|
402
|
+
let result = query;
|
|
403
|
+
let offset = 0;
|
|
404
|
+
for (const join of joinClauses) {
|
|
405
|
+
const scrubbedOnClause = scrubbed.slice(join.onStart, join.onEnd);
|
|
406
|
+
const originalOnClause = query.slice(join.onStart, join.onEnd);
|
|
407
|
+
let clauseResult = originalOnClause;
|
|
408
|
+
let clauseOffset = 0;
|
|
409
|
+
let eqPos = -1;
|
|
410
|
+
while ((eqPos = scrubbedOnClause.indexOf("=", eqPos + 1)) !== -1) {
|
|
411
|
+
let lhsEnd = eqPos - 1;
|
|
412
|
+
while (lhsEnd >= 0 && isWhitespace(scrubbedOnClause[lhsEnd])) {
|
|
413
|
+
lhsEnd--;
|
|
414
|
+
}
|
|
415
|
+
if (scrubbedOnClause[lhsEnd] !== '"')
|
|
416
|
+
continue;
|
|
417
|
+
let lhsStartPos = lhsEnd - 1;
|
|
418
|
+
while (lhsStartPos >= 0 && scrubbedOnClause[lhsStartPos] !== '"') {
|
|
419
|
+
lhsStartPos--;
|
|
420
|
+
}
|
|
421
|
+
if (lhsStartPos < 0)
|
|
422
|
+
continue;
|
|
423
|
+
const lhsIsQualified = lhsStartPos > 0 && scrubbedOnClause[lhsStartPos - 1] === ".";
|
|
424
|
+
let rhsStartPos = eqPos + 1;
|
|
425
|
+
while (rhsStartPos < scrubbedOnClause.length && isWhitespace(scrubbedOnClause[rhsStartPos])) {
|
|
426
|
+
rhsStartPos++;
|
|
427
|
+
}
|
|
428
|
+
const rhsChar = originalOnClause[rhsStartPos];
|
|
429
|
+
const rhsIsParam = rhsChar === "$";
|
|
430
|
+
const rhsIsStringLiteral = rhsChar === "'";
|
|
431
|
+
const rhsIsColumn = rhsChar === '"';
|
|
432
|
+
if (!rhsIsParam && !rhsIsStringLiteral && !rhsIsColumn)
|
|
433
|
+
continue;
|
|
434
|
+
const rhsIsQualified = !rhsIsColumn || rhsStartPos > 0 && scrubbedOnClause[rhsStartPos - 1] === ".";
|
|
435
|
+
if (lhsIsQualified || rhsIsQualified)
|
|
436
|
+
continue;
|
|
437
|
+
const lhsIdent = extractQuotedIdentifier(originalOnClause, lhsStartPos);
|
|
438
|
+
if (!lhsIdent)
|
|
439
|
+
continue;
|
|
440
|
+
let rhsIdent = null;
|
|
441
|
+
let rhsValue = "";
|
|
442
|
+
let rhsEnd = rhsStartPos;
|
|
443
|
+
if (rhsIsParam) {
|
|
444
|
+
let paramEnd = rhsStartPos + 1;
|
|
445
|
+
while (paramEnd < originalOnClause.length && /\d/.test(originalOnClause[paramEnd])) {
|
|
446
|
+
paramEnd++;
|
|
447
|
+
}
|
|
448
|
+
rhsValue = originalOnClause.slice(rhsStartPos, paramEnd);
|
|
449
|
+
rhsEnd = paramEnd;
|
|
450
|
+
} else if (rhsIsStringLiteral) {
|
|
451
|
+
let literalEnd = rhsStartPos + 1;
|
|
452
|
+
while (literalEnd < originalOnClause.length) {
|
|
453
|
+
if (originalOnClause[literalEnd] === "'") {
|
|
454
|
+
if (originalOnClause[literalEnd + 1] === "'") {
|
|
455
|
+
literalEnd += 2;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
literalEnd++;
|
|
461
|
+
}
|
|
462
|
+
rhsValue = originalOnClause.slice(rhsStartPos, literalEnd + 1);
|
|
463
|
+
rhsEnd = literalEnd + 1;
|
|
464
|
+
} else if (rhsIsColumn) {
|
|
465
|
+
rhsIdent = extractQuotedIdentifier(originalOnClause, rhsStartPos);
|
|
466
|
+
if (rhsIdent) {
|
|
467
|
+
if (rhsIdent.end < scrubbedOnClause.length && scrubbedOnClause[rhsIdent.end] === ".") {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
rhsValue = `"${rhsIdent.name}"`;
|
|
471
|
+
rhsEnd = rhsIdent.end;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (!rhsValue)
|
|
475
|
+
continue;
|
|
476
|
+
if (!rhsIsColumn || !rhsIdent || lhsIdent.name !== rhsIdent.name) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const lhsOriginal = `"${lhsIdent.name}"`;
|
|
480
|
+
let newLhs = lhsOriginal;
|
|
481
|
+
let newRhs = rhsValue;
|
|
482
|
+
if (!lhsIsQualified && join.leftSource) {
|
|
483
|
+
newLhs = `"${join.leftSource}"."${lhsIdent.name}"`;
|
|
484
|
+
}
|
|
485
|
+
if (!rhsIsQualified && rhsIsColumn && rhsIdent && join.rightSource) {
|
|
486
|
+
newRhs = `"${join.rightSource}"."${rhsIdent.name}"`;
|
|
487
|
+
}
|
|
488
|
+
if (newLhs !== lhsOriginal || newRhs !== rhsValue) {
|
|
489
|
+
const opStart = lhsIdent.end;
|
|
490
|
+
let opEnd = opStart;
|
|
491
|
+
while (opEnd < rhsEnd && (isWhitespace(originalOnClause[opEnd]) || originalOnClause[opEnd] === "=")) {
|
|
492
|
+
opEnd++;
|
|
493
|
+
}
|
|
494
|
+
const operator = originalOnClause.slice(opStart, opEnd);
|
|
495
|
+
const newExpr = `${newLhs}${operator}${newRhs}`;
|
|
496
|
+
const oldExprLength = rhsEnd - lhsStartPos;
|
|
497
|
+
clauseResult = clauseResult.slice(0, lhsStartPos + clauseOffset) + newExpr + clauseResult.slice(lhsStartPos + oldExprLength + clauseOffset);
|
|
498
|
+
clauseOffset += newExpr.length - oldExprLength;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (clauseResult !== originalOnClause) {
|
|
502
|
+
result = result.slice(0, join.onStart + offset) + clauseResult + result.slice(join.onEnd + offset);
|
|
503
|
+
offset += clauseResult.length - originalOnClause.length;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
183
508
|
|
|
184
509
|
// src/sql/result-mapper.ts
|
|
185
510
|
import {
|
|
@@ -473,6 +798,7 @@ function wrapperToNodeApiValue(wrapper, toValue) {
|
|
|
473
798
|
function isPool(client) {
|
|
474
799
|
return typeof client.acquire === "function";
|
|
475
800
|
}
|
|
801
|
+
var PREPARED_CACHE = Symbol.for("drizzle-duckdb:prepared-cache");
|
|
476
802
|
function isPgArrayLiteral(value) {
|
|
477
803
|
return value.startsWith("{") && value.endsWith("}");
|
|
478
804
|
}
|
|
@@ -486,16 +812,20 @@ function parsePgArrayLiteral(value) {
|
|
|
486
812
|
}
|
|
487
813
|
function prepareParams(params, options = {}) {
|
|
488
814
|
return params.map((param) => {
|
|
489
|
-
if (typeof param === "string") {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
815
|
+
if (typeof param === "string" && param.length > 0) {
|
|
816
|
+
const firstChar = param[0];
|
|
817
|
+
const maybeArrayLiteral = firstChar === "{" || firstChar === "[" || firstChar === " " || firstChar === "\t";
|
|
818
|
+
if (maybeArrayLiteral) {
|
|
819
|
+
const trimmed = firstChar === "{" || firstChar === "[" ? param : param.trim();
|
|
820
|
+
if (trimmed && isPgArrayLiteral(trimmed)) {
|
|
821
|
+
if (options.rejectStringArrayLiterals) {
|
|
822
|
+
throw new Error("Stringified array literals are not supported. Use duckDbList()/duckDbArray() or pass native arrays.");
|
|
823
|
+
}
|
|
824
|
+
if (options.warnOnStringArrayLiteral) {
|
|
825
|
+
options.warnOnStringArrayLiteral();
|
|
826
|
+
}
|
|
827
|
+
return parsePgArrayLiteral(trimmed);
|
|
497
828
|
}
|
|
498
|
-
return parsePgArrayLiteral(trimmed);
|
|
499
829
|
}
|
|
500
830
|
}
|
|
501
831
|
return param;
|
|
@@ -520,13 +850,121 @@ function toNodeApiValue(value) {
|
|
|
520
850
|
return value;
|
|
521
851
|
}
|
|
522
852
|
function deduplicateColumns(columns) {
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
853
|
+
const counts = new Map;
|
|
854
|
+
let hasDuplicates = false;
|
|
855
|
+
for (const column of columns) {
|
|
856
|
+
const next = (counts.get(column) ?? 0) + 1;
|
|
857
|
+
counts.set(column, next);
|
|
858
|
+
if (next > 1) {
|
|
859
|
+
hasDuplicates = true;
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (!hasDuplicates) {
|
|
864
|
+
return columns;
|
|
865
|
+
}
|
|
866
|
+
counts.clear();
|
|
867
|
+
return columns.map((column) => {
|
|
868
|
+
const count = counts.get(column) ?? 0;
|
|
869
|
+
counts.set(column, count + 1);
|
|
870
|
+
return count === 0 ? column : `${column}_${count}`;
|
|
528
871
|
});
|
|
529
872
|
}
|
|
873
|
+
function destroyPreparedStatement(entry) {
|
|
874
|
+
if (!entry)
|
|
875
|
+
return;
|
|
876
|
+
try {
|
|
877
|
+
entry.statement.destroySync();
|
|
878
|
+
} catch {}
|
|
879
|
+
}
|
|
880
|
+
function getPreparedCache(connection, size) {
|
|
881
|
+
const store = connection;
|
|
882
|
+
const existing = store[PREPARED_CACHE];
|
|
883
|
+
if (existing) {
|
|
884
|
+
existing.size = size;
|
|
885
|
+
return existing;
|
|
886
|
+
}
|
|
887
|
+
const cache = { size, entries: new Map };
|
|
888
|
+
store[PREPARED_CACHE] = cache;
|
|
889
|
+
return cache;
|
|
890
|
+
}
|
|
891
|
+
function evictOldest(cache) {
|
|
892
|
+
const oldest = cache.entries.keys().next();
|
|
893
|
+
if (!oldest.done) {
|
|
894
|
+
const key = oldest.value;
|
|
895
|
+
const entry = cache.entries.get(key);
|
|
896
|
+
cache.entries.delete(key);
|
|
897
|
+
destroyPreparedStatement(entry);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
function evictCacheEntry(cache, key) {
|
|
901
|
+
const entry = cache.entries.get(key);
|
|
902
|
+
cache.entries.delete(key);
|
|
903
|
+
destroyPreparedStatement(entry);
|
|
904
|
+
}
|
|
905
|
+
async function getOrPrepareStatement(connection, query, cacheConfig) {
|
|
906
|
+
const cache = getPreparedCache(connection, cacheConfig.size);
|
|
907
|
+
const cached = cache.entries.get(query);
|
|
908
|
+
if (cached) {
|
|
909
|
+
cache.entries.delete(query);
|
|
910
|
+
cache.entries.set(query, cached);
|
|
911
|
+
return cached.statement;
|
|
912
|
+
}
|
|
913
|
+
const statement = await connection.prepare(query);
|
|
914
|
+
cache.entries.set(query, { statement });
|
|
915
|
+
while (cache.entries.size > cache.size) {
|
|
916
|
+
evictOldest(cache);
|
|
917
|
+
}
|
|
918
|
+
return statement;
|
|
919
|
+
}
|
|
920
|
+
async function materializeResultRows(result) {
|
|
921
|
+
const rows = await result.getRowsJS() ?? [];
|
|
922
|
+
const baseColumns = typeof result.deduplicatedColumnNames === "function" ? result.deduplicatedColumnNames() : result.columnNames();
|
|
923
|
+
const columns = typeof result.deduplicatedColumnNames === "function" ? baseColumns : deduplicateColumns(baseColumns);
|
|
924
|
+
return { columns, rows };
|
|
925
|
+
}
|
|
926
|
+
async function materializeRows(client, query, params, options = {}) {
|
|
927
|
+
if (isPool(client)) {
|
|
928
|
+
const connection2 = await client.acquire();
|
|
929
|
+
try {
|
|
930
|
+
return await materializeRows(connection2, query, params, options);
|
|
931
|
+
} finally {
|
|
932
|
+
await client.release(connection2);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
936
|
+
const connection = client;
|
|
937
|
+
if (options.prepareCache && typeof connection.prepare === "function") {
|
|
938
|
+
const cache = getPreparedCache(connection, options.prepareCache.size);
|
|
939
|
+
try {
|
|
940
|
+
const statement = await getOrPrepareStatement(connection, query, options.prepareCache);
|
|
941
|
+
if (values) {
|
|
942
|
+
statement.bind(values);
|
|
943
|
+
} else {
|
|
944
|
+
statement.clearBindings?.();
|
|
945
|
+
}
|
|
946
|
+
const result2 = await statement.run();
|
|
947
|
+
cache.entries.delete(query);
|
|
948
|
+
cache.entries.set(query, { statement });
|
|
949
|
+
return await materializeResultRows(result2);
|
|
950
|
+
} catch (error) {
|
|
951
|
+
evictCacheEntry(cache, query);
|
|
952
|
+
throw error;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
const result = await connection.run(query, values);
|
|
956
|
+
return await materializeResultRows(result);
|
|
957
|
+
}
|
|
958
|
+
function clearPreparedCache(connection) {
|
|
959
|
+
const store = connection;
|
|
960
|
+
const cache = store[PREPARED_CACHE];
|
|
961
|
+
if (!cache)
|
|
962
|
+
return;
|
|
963
|
+
for (const entry of cache.entries.values()) {
|
|
964
|
+
destroyPreparedStatement(entry);
|
|
965
|
+
}
|
|
966
|
+
cache.entries.clear();
|
|
967
|
+
}
|
|
530
968
|
function mapRowsToObjects(columns, rows) {
|
|
531
969
|
return rows.map((vals) => {
|
|
532
970
|
const obj = {};
|
|
@@ -537,6 +975,7 @@ function mapRowsToObjects(columns, rows) {
|
|
|
537
975
|
});
|
|
538
976
|
}
|
|
539
977
|
async function closeClientConnection(connection) {
|
|
978
|
+
clearPreparedCache(connection);
|
|
540
979
|
if ("close" in connection && typeof connection.close === "function") {
|
|
541
980
|
await connection.close();
|
|
542
981
|
return;
|
|
@@ -549,27 +988,51 @@ async function closeClientConnection(connection) {
|
|
|
549
988
|
connection.disconnectSync();
|
|
550
989
|
}
|
|
551
990
|
}
|
|
552
|
-
async function executeOnClient(client, query, params) {
|
|
991
|
+
async function executeOnClient(client, query, params, options = {}) {
|
|
992
|
+
const { columns, rows } = await materializeRows(client, query, params, options);
|
|
993
|
+
if (!rows || rows.length === 0) {
|
|
994
|
+
return [];
|
|
995
|
+
}
|
|
996
|
+
return mapRowsToObjects(columns, rows);
|
|
997
|
+
}
|
|
998
|
+
async function executeArraysOnClient(client, query, params, options = {}) {
|
|
999
|
+
return await materializeRows(client, query, params, options);
|
|
1000
|
+
}
|
|
1001
|
+
async function* executeInBatches(client, query, params, options = {}) {
|
|
553
1002
|
if (isPool(client)) {
|
|
554
1003
|
const connection = await client.acquire();
|
|
555
1004
|
try {
|
|
556
|
-
|
|
1005
|
+
yield* executeInBatches(connection, query, params, options);
|
|
1006
|
+
return;
|
|
557
1007
|
} finally {
|
|
558
1008
|
await client.release(connection);
|
|
559
1009
|
}
|
|
560
1010
|
}
|
|
1011
|
+
const rowsPerChunk = options.rowsPerChunk && options.rowsPerChunk > 0 ? options.rowsPerChunk : 1e5;
|
|
561
1012
|
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
562
|
-
const result = await client.
|
|
563
|
-
const
|
|
564
|
-
const columns = result.deduplicatedColumnNames
|
|
565
|
-
|
|
566
|
-
|
|
1013
|
+
const result = await client.stream(query, values);
|
|
1014
|
+
const rawColumns = typeof result.deduplicatedColumnNames === "function" ? result.deduplicatedColumnNames() : result.columnNames();
|
|
1015
|
+
const columns = typeof result.deduplicatedColumnNames === "function" ? rawColumns : deduplicateColumns(rawColumns);
|
|
1016
|
+
let buffer = [];
|
|
1017
|
+
for await (const chunk of result.yieldRowsJs()) {
|
|
1018
|
+
const objects = mapRowsToObjects(columns, chunk);
|
|
1019
|
+
for (const row of objects) {
|
|
1020
|
+
buffer.push(row);
|
|
1021
|
+
if (buffer.length >= rowsPerChunk) {
|
|
1022
|
+
yield buffer;
|
|
1023
|
+
buffer = [];
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
if (buffer.length > 0) {
|
|
1028
|
+
yield buffer;
|
|
1029
|
+
}
|
|
567
1030
|
}
|
|
568
|
-
async function*
|
|
1031
|
+
async function* executeInBatchesRaw(client, query, params, options = {}) {
|
|
569
1032
|
if (isPool(client)) {
|
|
570
1033
|
const connection = await client.acquire();
|
|
571
1034
|
try {
|
|
572
|
-
yield*
|
|
1035
|
+
yield* executeInBatchesRaw(connection, query, params, options);
|
|
573
1036
|
return;
|
|
574
1037
|
} finally {
|
|
575
1038
|
await client.release(connection);
|
|
@@ -578,21 +1041,20 @@ async function* executeInBatches(client, query, params, options = {}) {
|
|
|
578
1041
|
const rowsPerChunk = options.rowsPerChunk && options.rowsPerChunk > 0 ? options.rowsPerChunk : 1e5;
|
|
579
1042
|
const values = params.length > 0 ? params.map((param) => toNodeApiValue(param)) : undefined;
|
|
580
1043
|
const result = await client.stream(query, values);
|
|
581
|
-
const
|
|
582
|
-
const
|
|
1044
|
+
const rawColumns = typeof result.deduplicatedColumnNames === "function" ? result.deduplicatedColumnNames() : result.columnNames();
|
|
1045
|
+
const columns = typeof result.deduplicatedColumnNames === "function" ? rawColumns : deduplicateColumns(rawColumns);
|
|
583
1046
|
let buffer = [];
|
|
584
1047
|
for await (const chunk of result.yieldRowsJs()) {
|
|
585
|
-
const
|
|
586
|
-
for (const row of objects) {
|
|
1048
|
+
for (const row of chunk) {
|
|
587
1049
|
buffer.push(row);
|
|
588
1050
|
if (buffer.length >= rowsPerChunk) {
|
|
589
|
-
yield buffer;
|
|
1051
|
+
yield { columns, rows: buffer };
|
|
590
1052
|
buffer = [];
|
|
591
1053
|
}
|
|
592
1054
|
}
|
|
593
1055
|
}
|
|
594
1056
|
if (buffer.length > 0) {
|
|
595
|
-
yield buffer;
|
|
1057
|
+
yield { columns, rows: buffer };
|
|
596
1058
|
}
|
|
597
1059
|
}
|
|
598
1060
|
async function executeArrowOnClient(client, query, params) {
|
|
@@ -620,6 +1082,24 @@ function isSavepointSyntaxError(error) {
|
|
|
620
1082
|
}
|
|
621
1083
|
return error.message.toLowerCase().includes("savepoint") && error.message.toLowerCase().includes("syntax error");
|
|
622
1084
|
}
|
|
1085
|
+
function rewriteQuery(mode, query) {
|
|
1086
|
+
if (mode === "never") {
|
|
1087
|
+
return { sql: query, rewritten: false };
|
|
1088
|
+
}
|
|
1089
|
+
let result = query;
|
|
1090
|
+
let wasRewritten = false;
|
|
1091
|
+
const arrayRewritten = adaptArrayOperators(result);
|
|
1092
|
+
if (arrayRewritten !== result) {
|
|
1093
|
+
result = arrayRewritten;
|
|
1094
|
+
wasRewritten = true;
|
|
1095
|
+
}
|
|
1096
|
+
const joinQualified = qualifyJoinColumns(result);
|
|
1097
|
+
if (joinQualified !== result) {
|
|
1098
|
+
result = joinQualified;
|
|
1099
|
+
wasRewritten = true;
|
|
1100
|
+
}
|
|
1101
|
+
return { sql: result, rewritten: wasRewritten };
|
|
1102
|
+
}
|
|
623
1103
|
|
|
624
1104
|
class DuckDBPreparedQuery extends PgPreparedQuery {
|
|
625
1105
|
client;
|
|
@@ -630,11 +1110,12 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
|
|
|
630
1110
|
fields;
|
|
631
1111
|
_isResponseInArrayMode;
|
|
632
1112
|
customResultMapper;
|
|
633
|
-
|
|
1113
|
+
rewriteArraysMode;
|
|
634
1114
|
rejectStringArrayLiterals;
|
|
1115
|
+
prepareCache;
|
|
635
1116
|
warnOnStringArrayLiteral;
|
|
636
1117
|
static [entityKind] = "DuckDBPreparedQuery";
|
|
637
|
-
constructor(client, dialect, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper,
|
|
1118
|
+
constructor(client, dialect, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper, rewriteArraysMode, rejectStringArrayLiterals, prepareCache, warnOnStringArrayLiteral) {
|
|
638
1119
|
super({ sql: queryString, params });
|
|
639
1120
|
this.client = client;
|
|
640
1121
|
this.dialect = dialect;
|
|
@@ -644,8 +1125,9 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
|
|
|
644
1125
|
this.fields = fields;
|
|
645
1126
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
646
1127
|
this.customResultMapper = customResultMapper;
|
|
647
|
-
this.
|
|
1128
|
+
this.rewriteArraysMode = rewriteArraysMode;
|
|
648
1129
|
this.rejectStringArrayLiterals = rejectStringArrayLiterals;
|
|
1130
|
+
this.prepareCache = prepareCache;
|
|
649
1131
|
this.warnOnStringArrayLiteral = warnOnStringArrayLiteral;
|
|
650
1132
|
}
|
|
651
1133
|
async execute(placeholderValues = {}) {
|
|
@@ -654,18 +1136,23 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
|
|
|
654
1136
|
rejectStringArrayLiterals: this.rejectStringArrayLiterals,
|
|
655
1137
|
warnOnStringArrayLiteral: this.warnOnStringArrayLiteral ? () => this.warnOnStringArrayLiteral?.(this.queryString) : undefined
|
|
656
1138
|
});
|
|
657
|
-
const rewrittenQuery
|
|
658
|
-
if (
|
|
1139
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, this.queryString);
|
|
1140
|
+
if (didRewrite) {
|
|
659
1141
|
this.logger.logQuery(`[duckdb] original query before array rewrite: ${this.queryString}`, params);
|
|
660
1142
|
}
|
|
661
1143
|
this.logger.logQuery(rewrittenQuery, params);
|
|
662
1144
|
const { fields, joinsNotNullableMap, customResultMapper } = this;
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
1145
|
+
if (fields) {
|
|
1146
|
+
const { rows: rows2 } = await executeArraysOnClient(this.client, rewrittenQuery, params, { prepareCache: this.prepareCache });
|
|
1147
|
+
if (rows2.length === 0) {
|
|
1148
|
+
return [];
|
|
1149
|
+
}
|
|
1150
|
+
return customResultMapper ? customResultMapper(rows2) : rows2.map((row) => mapResultRow(fields, row, joinsNotNullableMap));
|
|
666
1151
|
}
|
|
667
|
-
const
|
|
668
|
-
|
|
1152
|
+
const rows = await executeOnClient(this.client, rewrittenQuery, params, {
|
|
1153
|
+
prepareCache: this.prepareCache
|
|
1154
|
+
});
|
|
1155
|
+
return rows;
|
|
669
1156
|
}
|
|
670
1157
|
all(placeholderValues = {}) {
|
|
671
1158
|
return this.execute(placeholderValues);
|
|
@@ -682,8 +1169,9 @@ class DuckDBSession extends PgSession {
|
|
|
682
1169
|
static [entityKind] = "DuckDBSession";
|
|
683
1170
|
dialect;
|
|
684
1171
|
logger;
|
|
685
|
-
|
|
1172
|
+
rewriteArraysMode;
|
|
686
1173
|
rejectStringArrayLiterals;
|
|
1174
|
+
prepareCache;
|
|
687
1175
|
hasWarnedArrayLiteral = false;
|
|
688
1176
|
rollbackOnly = false;
|
|
689
1177
|
constructor(client, dialect, schema, options = {}) {
|
|
@@ -693,11 +1181,17 @@ class DuckDBSession extends PgSession {
|
|
|
693
1181
|
this.options = options;
|
|
694
1182
|
this.dialect = dialect;
|
|
695
1183
|
this.logger = options.logger ?? new NoopLogger;
|
|
696
|
-
this.
|
|
1184
|
+
this.rewriteArraysMode = options.rewriteArrays ?? "auto";
|
|
697
1185
|
this.rejectStringArrayLiterals = options.rejectStringArrayLiterals ?? false;
|
|
1186
|
+
this.prepareCache = options.prepareCache;
|
|
1187
|
+
this.options = {
|
|
1188
|
+
...options,
|
|
1189
|
+
rewriteArrays: this.rewriteArraysMode,
|
|
1190
|
+
prepareCache: this.prepareCache
|
|
1191
|
+
};
|
|
698
1192
|
}
|
|
699
1193
|
prepareQuery(query, fields, name, isResponseInArrayMode, customResultMapper) {
|
|
700
|
-
return new DuckDBPreparedQuery(this.client, this.dialect, query.sql, query.params, this.logger, fields, isResponseInArrayMode, customResultMapper, this.
|
|
1194
|
+
return new DuckDBPreparedQuery(this.client, this.dialect, query.sql, query.params, this.logger, fields, isResponseInArrayMode, customResultMapper, this.rewriteArraysMode, this.rejectStringArrayLiterals, this.prepareCache, this.rejectStringArrayLiterals ? undefined : this.warnOnStringArrayLiteral);
|
|
701
1195
|
}
|
|
702
1196
|
execute(query) {
|
|
703
1197
|
this.dialect.resetPgJsonFlag();
|
|
@@ -757,13 +1251,28 @@ query: ${query}`, []);
|
|
|
757
1251
|
rejectStringArrayLiterals: this.rejectStringArrayLiterals,
|
|
758
1252
|
warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
|
|
759
1253
|
});
|
|
760
|
-
const rewrittenQuery = this.
|
|
761
|
-
if (
|
|
1254
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
|
|
1255
|
+
if (didRewrite) {
|
|
762
1256
|
this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
|
|
763
1257
|
}
|
|
764
1258
|
this.logger.logQuery(rewrittenQuery, params);
|
|
765
1259
|
return executeInBatches(this.client, rewrittenQuery, params, options);
|
|
766
1260
|
}
|
|
1261
|
+
executeBatchesRaw(query, options = {}) {
|
|
1262
|
+
this.dialect.resetPgJsonFlag();
|
|
1263
|
+
const builtQuery = this.dialect.sqlToQuery(query);
|
|
1264
|
+
this.dialect.assertNoPgJsonColumns();
|
|
1265
|
+
const params = prepareParams(builtQuery.params, {
|
|
1266
|
+
rejectStringArrayLiterals: this.rejectStringArrayLiterals,
|
|
1267
|
+
warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
|
|
1268
|
+
});
|
|
1269
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
|
|
1270
|
+
if (didRewrite) {
|
|
1271
|
+
this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
|
|
1272
|
+
}
|
|
1273
|
+
this.logger.logQuery(rewrittenQuery, params);
|
|
1274
|
+
return executeInBatchesRaw(this.client, rewrittenQuery, params, options);
|
|
1275
|
+
}
|
|
767
1276
|
async executeArrow(query) {
|
|
768
1277
|
this.dialect.resetPgJsonFlag();
|
|
769
1278
|
const builtQuery = this.dialect.sqlToQuery(query);
|
|
@@ -772,8 +1281,8 @@ query: ${query}`, []);
|
|
|
772
1281
|
rejectStringArrayLiterals: this.rejectStringArrayLiterals,
|
|
773
1282
|
warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
|
|
774
1283
|
});
|
|
775
|
-
const rewrittenQuery = this.
|
|
776
|
-
if (
|
|
1284
|
+
const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
|
|
1285
|
+
if (didRewrite) {
|
|
777
1286
|
this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
|
|
778
1287
|
}
|
|
779
1288
|
this.logger.logQuery(rewrittenQuery, params);
|
|
@@ -811,6 +1320,9 @@ class DuckDBTransaction extends PgTransaction {
|
|
|
811
1320
|
executeBatches(query, options = {}) {
|
|
812
1321
|
return this.session.executeBatches(query, options);
|
|
813
1322
|
}
|
|
1323
|
+
executeBatchesRaw(query, options = {}) {
|
|
1324
|
+
return this.session.executeBatchesRaw(query, options);
|
|
1325
|
+
}
|
|
814
1326
|
executeArrow(query) {
|
|
815
1327
|
return this.session.executeArrow(query);
|
|
816
1328
|
}
|
|
@@ -1222,6 +1734,32 @@ function createDuckDBConnectionPool(instance, options = {}) {
|
|
|
1222
1734
|
};
|
|
1223
1735
|
}
|
|
1224
1736
|
|
|
1737
|
+
// src/options.ts
|
|
1738
|
+
var DEFAULT_REWRITE_ARRAYS_MODE = "auto";
|
|
1739
|
+
function resolveRewriteArraysOption(value) {
|
|
1740
|
+
if (value === undefined)
|
|
1741
|
+
return DEFAULT_REWRITE_ARRAYS_MODE;
|
|
1742
|
+
if (value === true)
|
|
1743
|
+
return "auto";
|
|
1744
|
+
if (value === false)
|
|
1745
|
+
return "never";
|
|
1746
|
+
return value;
|
|
1747
|
+
}
|
|
1748
|
+
var DEFAULT_PREPARED_CACHE_SIZE = 32;
|
|
1749
|
+
function resolvePrepareCacheOption(option) {
|
|
1750
|
+
if (!option)
|
|
1751
|
+
return;
|
|
1752
|
+
if (option === true) {
|
|
1753
|
+
return { size: DEFAULT_PREPARED_CACHE_SIZE };
|
|
1754
|
+
}
|
|
1755
|
+
if (typeof option === "number") {
|
|
1756
|
+
const size2 = Math.max(1, Math.floor(option));
|
|
1757
|
+
return { size: size2 };
|
|
1758
|
+
}
|
|
1759
|
+
const size = option.size ?? DEFAULT_PREPARED_CACHE_SIZE;
|
|
1760
|
+
return { size: Math.max(1, Math.floor(size)) };
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1225
1763
|
// src/driver.ts
|
|
1226
1764
|
class DuckDBDriver {
|
|
1227
1765
|
client;
|
|
@@ -1236,8 +1774,9 @@ class DuckDBDriver {
|
|
|
1236
1774
|
createSession(schema) {
|
|
1237
1775
|
return new DuckDBSession(this.client, this.dialect, schema, {
|
|
1238
1776
|
logger: this.options.logger,
|
|
1239
|
-
rewriteArrays: this.options.rewriteArrays,
|
|
1240
|
-
rejectStringArrayLiterals: this.options.rejectStringArrayLiterals
|
|
1777
|
+
rewriteArrays: this.options.rewriteArrays ?? "auto",
|
|
1778
|
+
rejectStringArrayLiterals: this.options.rejectStringArrayLiterals,
|
|
1779
|
+
prepareCache: this.options.prepareCache
|
|
1241
1780
|
});
|
|
1242
1781
|
}
|
|
1243
1782
|
}
|
|
@@ -1250,6 +1789,8 @@ function isConfigObject(data) {
|
|
|
1250
1789
|
}
|
|
1251
1790
|
function createFromClient(client, config = {}, instance) {
|
|
1252
1791
|
const dialect = new DuckDBDialect;
|
|
1792
|
+
const rewriteArraysMode = resolveRewriteArraysOption(config.rewriteArrays);
|
|
1793
|
+
const prepareCache = resolvePrepareCacheOption(config.prepareCache);
|
|
1253
1794
|
const logger = config.logger === true ? new DefaultLogger : config.logger || undefined;
|
|
1254
1795
|
let schema;
|
|
1255
1796
|
if (config.schema) {
|
|
@@ -1262,8 +1803,9 @@ function createFromClient(client, config = {}, instance) {
|
|
|
1262
1803
|
}
|
|
1263
1804
|
const driver = new DuckDBDriver(client, dialect, {
|
|
1264
1805
|
logger,
|
|
1265
|
-
rewriteArrays:
|
|
1266
|
-
rejectStringArrayLiterals: config.rejectStringArrayLiterals
|
|
1806
|
+
rewriteArrays: rewriteArraysMode,
|
|
1807
|
+
rejectStringArrayLiterals: config.rejectStringArrayLiterals,
|
|
1808
|
+
prepareCache
|
|
1267
1809
|
});
|
|
1268
1810
|
const session = driver.createSession(schema);
|
|
1269
1811
|
const db = new DuckDBDatabase(dialect, session, schema, client, instance);
|
|
@@ -1343,6 +1885,9 @@ class DuckDBDatabase extends PgDatabase {
|
|
|
1343
1885
|
executeBatches(query, options = {}) {
|
|
1344
1886
|
return this.session.executeBatches(query, options);
|
|
1345
1887
|
}
|
|
1888
|
+
executeBatchesRaw(query, options = {}) {
|
|
1889
|
+
return this.session.executeBatchesRaw(query, options);
|
|
1890
|
+
}
|
|
1346
1891
|
executeArrow(query) {
|
|
1347
1892
|
return this.session.executeArrow(query);
|
|
1348
1893
|
}
|