@leonardovida-md/drizzle-neo-duckdb 1.1.3 → 1.1.4
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/duckdb-introspect.mjs +287 -11
- package/dist/helpers.mjs +10 -0
- package/dist/index.mjs +290 -11
- package/dist/sql/query-rewriters.d.ts +4 -3
- package/package.json +5 -2
- package/src/columns.ts +6 -1
- package/src/sql/query-rewriters.ts +481 -28
package/dist/index.mjs
CHANGED
|
@@ -180,10 +180,13 @@ function extractQuotedIdentifier(original, start) {
|
|
|
180
180
|
return null;
|
|
181
181
|
}
|
|
182
182
|
let pos = start + 1;
|
|
183
|
-
while (pos < original.length
|
|
184
|
-
if (original[pos] === '"'
|
|
185
|
-
pos
|
|
186
|
-
|
|
183
|
+
while (pos < original.length) {
|
|
184
|
+
if (original[pos] === '"') {
|
|
185
|
+
if (original[pos + 1] === '"') {
|
|
186
|
+
pos += 2;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
187
190
|
}
|
|
188
191
|
pos++;
|
|
189
192
|
}
|
|
@@ -251,6 +254,39 @@ function parseTableRef(original, scrubbed, start) {
|
|
|
251
254
|
while (pos < scrubbed.length && isWhitespace(scrubbed[pos])) {
|
|
252
255
|
pos++;
|
|
253
256
|
}
|
|
257
|
+
if (scrubbed[pos] === "(") {
|
|
258
|
+
const nameStart2 = pos;
|
|
259
|
+
let depth = 1;
|
|
260
|
+
pos++;
|
|
261
|
+
while (pos < scrubbed.length && depth > 0) {
|
|
262
|
+
if (scrubbed[pos] === "(")
|
|
263
|
+
depth++;
|
|
264
|
+
else if (scrubbed[pos] === ")")
|
|
265
|
+
depth--;
|
|
266
|
+
pos++;
|
|
267
|
+
}
|
|
268
|
+
while (pos < scrubbed.length && isWhitespace(scrubbed[pos])) {
|
|
269
|
+
pos++;
|
|
270
|
+
}
|
|
271
|
+
const afterSubquery = scrubbed.slice(pos).toLowerCase();
|
|
272
|
+
if (afterSubquery.startsWith("as ")) {
|
|
273
|
+
pos += 3;
|
|
274
|
+
while (pos < scrubbed.length && isWhitespace(scrubbed[pos])) {
|
|
275
|
+
pos++;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (original[pos] === '"') {
|
|
279
|
+
const aliasIdent = extractQuotedIdentifier(original, pos);
|
|
280
|
+
if (aliasIdent) {
|
|
281
|
+
return {
|
|
282
|
+
name: aliasIdent.name,
|
|
283
|
+
alias: aliasIdent.name,
|
|
284
|
+
position: nameStart2
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
254
290
|
if (original[pos] !== '"') {
|
|
255
291
|
return null;
|
|
256
292
|
}
|
|
@@ -290,7 +326,8 @@ function parseTableRef(original, scrubbed, start) {
|
|
|
290
326
|
aliasPos++;
|
|
291
327
|
}
|
|
292
328
|
}
|
|
293
|
-
|
|
329
|
+
const afterAlias = scrubbed.slice(aliasPos).toLowerCase();
|
|
330
|
+
if (original[aliasPos] === '"' && !afterAlias.startsWith("on ") && !afterAlias.startsWith("left ") && !afterAlias.startsWith("right ") && !afterAlias.startsWith("inner ") && !afterAlias.startsWith("full ") && !afterAlias.startsWith("cross ") && !afterAlias.startsWith("join ") && !afterAlias.startsWith("where ") && !afterAlias.startsWith("group ") && !afterAlias.startsWith("order ") && !afterAlias.startsWith("limit ")) {
|
|
294
331
|
const aliasIdent = extractQuotedIdentifier(original, aliasPos);
|
|
295
332
|
if (aliasIdent) {
|
|
296
333
|
alias = aliasIdent.name;
|
|
@@ -302,10 +339,11 @@ function parseTableRef(original, scrubbed, start) {
|
|
|
302
339
|
position: nameStart
|
|
303
340
|
};
|
|
304
341
|
}
|
|
305
|
-
function findJoinClauses(original, scrubbed, sources) {
|
|
342
|
+
function findJoinClauses(original, scrubbed, sources, fromPos) {
|
|
306
343
|
const clauses = [];
|
|
307
344
|
const lowerScrubbed = scrubbed.toLowerCase();
|
|
308
345
|
const joinPattern = /\b(left\s+|right\s+|inner\s+|full\s+|cross\s+)?join\s+"[^"]*"(\s*\.\s*"[^"]*")?(\s+as)?(\s+"[^"]*")?\s+on\s+/gi;
|
|
346
|
+
joinPattern.lastIndex = fromPos;
|
|
309
347
|
let match;
|
|
310
348
|
let sourceIndex = 1;
|
|
311
349
|
while ((match = joinPattern.exec(lowerScrubbed)) !== null) {
|
|
@@ -377,22 +415,182 @@ function findJoinClauses(original, scrubbed, sources) {
|
|
|
377
415
|
}
|
|
378
416
|
return clauses;
|
|
379
417
|
}
|
|
418
|
+
function findMainSelectClause(scrubbed) {
|
|
419
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
420
|
+
let searchStart = 0;
|
|
421
|
+
const withMatch = /\bwith\s+/i.exec(lowerScrubbed);
|
|
422
|
+
if (withMatch) {
|
|
423
|
+
let depth2 = 0;
|
|
424
|
+
let pos2 = withMatch.index + withMatch[0].length;
|
|
425
|
+
while (pos2 < scrubbed.length) {
|
|
426
|
+
const char = scrubbed[pos2];
|
|
427
|
+
if (char === "(") {
|
|
428
|
+
depth2++;
|
|
429
|
+
} else if (char === ")") {
|
|
430
|
+
depth2--;
|
|
431
|
+
} else if (depth2 === 0) {
|
|
432
|
+
const remaining = lowerScrubbed.slice(pos2);
|
|
433
|
+
if (/^\s*select\s+/i.test(remaining)) {
|
|
434
|
+
searchStart = pos2;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
pos2++;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const selectPattern = /\bselect\s+/gi;
|
|
442
|
+
selectPattern.lastIndex = searchStart;
|
|
443
|
+
const selectMatch = selectPattern.exec(lowerScrubbed);
|
|
444
|
+
if (!selectMatch)
|
|
445
|
+
return null;
|
|
446
|
+
const selectStart = selectMatch.index + selectMatch[0].length;
|
|
447
|
+
let depth = 0;
|
|
448
|
+
let pos = selectStart;
|
|
449
|
+
while (pos < scrubbed.length) {
|
|
450
|
+
const char = scrubbed[pos];
|
|
451
|
+
if (char === "(") {
|
|
452
|
+
depth++;
|
|
453
|
+
} else if (char === ")") {
|
|
454
|
+
depth--;
|
|
455
|
+
} else if (depth === 0) {
|
|
456
|
+
const remaining = lowerScrubbed.slice(pos);
|
|
457
|
+
if (/^\s*from\s+/i.test(remaining)) {
|
|
458
|
+
return { start: selectStart, end: pos };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
pos++;
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
function findWhereClause(scrubbed, fromPos) {
|
|
466
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
467
|
+
let depth = 0;
|
|
468
|
+
let pos = fromPos;
|
|
469
|
+
let whereStart = -1;
|
|
470
|
+
while (pos < scrubbed.length) {
|
|
471
|
+
const char = scrubbed[pos];
|
|
472
|
+
if (char === "(") {
|
|
473
|
+
depth++;
|
|
474
|
+
} else if (char === ")") {
|
|
475
|
+
depth--;
|
|
476
|
+
} else if (depth === 0) {
|
|
477
|
+
const remaining = lowerScrubbed.slice(pos);
|
|
478
|
+
if (whereStart === -1 && /^\s*where\s+/i.test(remaining)) {
|
|
479
|
+
const match = /^\s*where\s+/i.exec(remaining);
|
|
480
|
+
if (match) {
|
|
481
|
+
whereStart = pos + match[0].length;
|
|
482
|
+
}
|
|
483
|
+
} else if (whereStart !== -1 && /^\s*(group\s+by|order\s+by|limit|having|union|intersect|except|$)/i.test(remaining)) {
|
|
484
|
+
return { start: whereStart, end: pos };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
pos++;
|
|
488
|
+
}
|
|
489
|
+
if (whereStart !== -1) {
|
|
490
|
+
return { start: whereStart, end: scrubbed.length };
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
function findOrderByClause(scrubbed, fromPos) {
|
|
495
|
+
const lowerScrubbed = scrubbed.toLowerCase();
|
|
496
|
+
let depth = 0;
|
|
497
|
+
let pos = fromPos;
|
|
498
|
+
let orderStart = -1;
|
|
499
|
+
while (pos < scrubbed.length) {
|
|
500
|
+
const char = scrubbed[pos];
|
|
501
|
+
if (char === "(") {
|
|
502
|
+
depth++;
|
|
503
|
+
} else if (char === ")") {
|
|
504
|
+
depth--;
|
|
505
|
+
} else if (depth === 0) {
|
|
506
|
+
const remaining = lowerScrubbed.slice(pos);
|
|
507
|
+
if (orderStart === -1 && /^\s*order\s+by\s+/i.test(remaining)) {
|
|
508
|
+
const match = /^\s*order\s+by\s+/i.exec(remaining);
|
|
509
|
+
if (match) {
|
|
510
|
+
orderStart = pos + match[0].length;
|
|
511
|
+
}
|
|
512
|
+
} else if (orderStart !== -1 && /^\s*(limit|offset|fetch|for\s+update|$)/i.test(remaining)) {
|
|
513
|
+
return { start: orderStart, end: pos };
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
pos++;
|
|
517
|
+
}
|
|
518
|
+
if (orderStart !== -1) {
|
|
519
|
+
return { start: orderStart, end: scrubbed.length };
|
|
520
|
+
}
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
function qualifyClauseColumnsSelective(original, scrubbed, clauseStart, clauseEnd, defaultSource, ambiguousColumns) {
|
|
524
|
+
const clauseOriginal = original.slice(clauseStart, clauseEnd);
|
|
525
|
+
const clauseScrubbed = scrubbed.slice(clauseStart, clauseEnd);
|
|
526
|
+
let result = clauseOriginal;
|
|
527
|
+
let offset = 0;
|
|
528
|
+
let pos = 0;
|
|
529
|
+
while (pos < clauseScrubbed.length) {
|
|
530
|
+
const quotePos = clauseScrubbed.indexOf('"', pos);
|
|
531
|
+
if (quotePos === -1)
|
|
532
|
+
break;
|
|
533
|
+
if (quotePos > 0 && clauseScrubbed[quotePos - 1] === ".") {
|
|
534
|
+
const ident2 = extractQuotedIdentifier(clauseOriginal, quotePos);
|
|
535
|
+
pos = ident2 ? ident2.end : quotePos + 1;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const ident = extractQuotedIdentifier(clauseOriginal, quotePos);
|
|
539
|
+
if (!ident) {
|
|
540
|
+
pos = quotePos + 1;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (ident.end < clauseScrubbed.length && clauseScrubbed[ident.end] === ".") {
|
|
544
|
+
pos = ident.end + 1;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (!ambiguousColumns.has(ident.name)) {
|
|
548
|
+
pos = ident.end;
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
let afterIdent = ident.end;
|
|
552
|
+
while (afterIdent < clauseScrubbed.length && isWhitespace(clauseScrubbed[afterIdent])) {
|
|
553
|
+
afterIdent++;
|
|
554
|
+
}
|
|
555
|
+
if (clauseScrubbed[afterIdent] === "(") {
|
|
556
|
+
pos = ident.end;
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
const beforeQuote = clauseScrubbed.slice(0, quotePos).toLowerCase();
|
|
560
|
+
if (/\bas\s*$/i.test(beforeQuote)) {
|
|
561
|
+
pos = ident.end;
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
const qualified = `"${defaultSource}"."${ident.name}"`;
|
|
565
|
+
const oldLength = ident.end - quotePos;
|
|
566
|
+
result = result.slice(0, quotePos + offset) + qualified + result.slice(quotePos + oldLength + offset);
|
|
567
|
+
offset += qualified.length - oldLength;
|
|
568
|
+
pos = ident.end;
|
|
569
|
+
}
|
|
570
|
+
return { result, offset };
|
|
571
|
+
}
|
|
380
572
|
function qualifyJoinColumns(query) {
|
|
381
573
|
const lowerQuery = query.toLowerCase();
|
|
382
574
|
if (!lowerQuery.includes("join")) {
|
|
383
575
|
return query;
|
|
384
576
|
}
|
|
385
577
|
const scrubbed = scrubForRewrite(query);
|
|
578
|
+
const fromPos = findMainFromClause(scrubbed);
|
|
579
|
+
if (fromPos < 0) {
|
|
580
|
+
return query;
|
|
581
|
+
}
|
|
386
582
|
const sources = parseTableSources(query, scrubbed);
|
|
387
583
|
if (sources.length < 2) {
|
|
388
584
|
return query;
|
|
389
585
|
}
|
|
390
|
-
const joinClauses = findJoinClauses(query, scrubbed, sources);
|
|
586
|
+
const joinClauses = findJoinClauses(query, scrubbed, sources, fromPos);
|
|
391
587
|
if (joinClauses.length === 0) {
|
|
392
588
|
return query;
|
|
393
589
|
}
|
|
590
|
+
const firstSource = sources[0];
|
|
591
|
+
const defaultQualifier = firstSource.alias || firstSource.name;
|
|
394
592
|
let result = query;
|
|
395
|
-
let
|
|
593
|
+
let totalOffset = 0;
|
|
396
594
|
for (const join of joinClauses) {
|
|
397
595
|
const scrubbedOnClause = scrubbed.slice(join.onStart, join.onEnd);
|
|
398
596
|
const originalOnClause = query.slice(join.onStart, join.onEnd);
|
|
@@ -407,7 +605,14 @@ function qualifyJoinColumns(query) {
|
|
|
407
605
|
if (scrubbedOnClause[lhsEnd] !== '"')
|
|
408
606
|
continue;
|
|
409
607
|
let lhsStartPos = lhsEnd - 1;
|
|
410
|
-
while (lhsStartPos >= 0
|
|
608
|
+
while (lhsStartPos >= 0) {
|
|
609
|
+
if (scrubbedOnClause[lhsStartPos] === '"') {
|
|
610
|
+
if (lhsStartPos > 0 && scrubbedOnClause[lhsStartPos - 1] === '"') {
|
|
611
|
+
lhsStartPos -= 2;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
411
616
|
lhsStartPos--;
|
|
412
617
|
}
|
|
413
618
|
if (lhsStartPos < 0)
|
|
@@ -491,8 +696,79 @@ function qualifyJoinColumns(query) {
|
|
|
491
696
|
}
|
|
492
697
|
}
|
|
493
698
|
if (clauseResult !== originalOnClause) {
|
|
494
|
-
result = result.slice(0, join.onStart +
|
|
495
|
-
|
|
699
|
+
result = result.slice(0, join.onStart + totalOffset) + clauseResult + result.slice(join.onEnd + totalOffset);
|
|
700
|
+
totalOffset += clauseResult.length - originalOnClause.length;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const ambiguousColumns = new Set;
|
|
704
|
+
for (const join of joinClauses) {
|
|
705
|
+
const scrubbedOnClause = scrubbed.slice(join.onStart, join.onEnd);
|
|
706
|
+
const originalOnClause = query.slice(join.onStart, join.onEnd);
|
|
707
|
+
let eqPos = -1;
|
|
708
|
+
while ((eqPos = scrubbedOnClause.indexOf("=", eqPos + 1)) !== -1) {
|
|
709
|
+
let lhsEnd = eqPos - 1;
|
|
710
|
+
while (lhsEnd >= 0 && isWhitespace(scrubbedOnClause[lhsEnd])) {
|
|
711
|
+
lhsEnd--;
|
|
712
|
+
}
|
|
713
|
+
if (scrubbedOnClause[lhsEnd] !== '"')
|
|
714
|
+
continue;
|
|
715
|
+
let lhsStartPos = lhsEnd - 1;
|
|
716
|
+
while (lhsStartPos >= 0) {
|
|
717
|
+
if (scrubbedOnClause[lhsStartPos] === '"') {
|
|
718
|
+
if (lhsStartPos > 0 && scrubbedOnClause[lhsStartPos - 1] === '"') {
|
|
719
|
+
lhsStartPos -= 2;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
lhsStartPos--;
|
|
725
|
+
}
|
|
726
|
+
if (lhsStartPos < 0)
|
|
727
|
+
continue;
|
|
728
|
+
let rhsStartPos = eqPos + 1;
|
|
729
|
+
while (rhsStartPos < scrubbedOnClause.length && isWhitespace(scrubbedOnClause[rhsStartPos])) {
|
|
730
|
+
rhsStartPos++;
|
|
731
|
+
}
|
|
732
|
+
if (originalOnClause[rhsStartPos] !== '"')
|
|
733
|
+
continue;
|
|
734
|
+
const lhsIdent = extractQuotedIdentifier(originalOnClause, lhsStartPos);
|
|
735
|
+
const rhsIdent = extractQuotedIdentifier(originalOnClause, rhsStartPos);
|
|
736
|
+
if (lhsIdent && rhsIdent && lhsIdent.name === rhsIdent.name) {
|
|
737
|
+
ambiguousColumns.add(lhsIdent.name);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (ambiguousColumns.size === 0) {
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
const updatedScrubbed = scrubForRewrite(result);
|
|
745
|
+
const selectClause = findMainSelectClause(updatedScrubbed);
|
|
746
|
+
if (selectClause) {
|
|
747
|
+
const { result: selectResult, offset: selectOffset } = qualifyClauseColumnsSelective(result, updatedScrubbed, selectClause.start, selectClause.end, defaultQualifier, ambiguousColumns);
|
|
748
|
+
if (selectOffset !== 0) {
|
|
749
|
+
result = result.slice(0, selectClause.start) + selectResult + result.slice(selectClause.end);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const scrubbed2 = scrubForRewrite(result);
|
|
753
|
+
const fromPos2 = findMainFromClause(scrubbed2);
|
|
754
|
+
if (fromPos2 >= 0) {
|
|
755
|
+
const whereClause = findWhereClause(scrubbed2, fromPos2);
|
|
756
|
+
if (whereClause) {
|
|
757
|
+
const { result: whereResult, offset: whereOffset } = qualifyClauseColumnsSelective(result, scrubbed2, whereClause.start, whereClause.end, defaultQualifier, ambiguousColumns);
|
|
758
|
+
if (whereOffset !== 0) {
|
|
759
|
+
result = result.slice(0, whereClause.start) + whereResult + result.slice(whereClause.end);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
const scrubbed3 = scrubForRewrite(result);
|
|
764
|
+
const fromPos3 = findMainFromClause(scrubbed3);
|
|
765
|
+
if (fromPos3 >= 0) {
|
|
766
|
+
const orderByClause = findOrderByClause(scrubbed3, fromPos3);
|
|
767
|
+
if (orderByClause) {
|
|
768
|
+
const { result: orderResult, offset: orderOffset } = qualifyClauseColumnsSelective(result, scrubbed3, orderByClause.start, orderByClause.end, defaultQualifier, ambiguousColumns);
|
|
769
|
+
if (orderOffset !== 0) {
|
|
770
|
+
result = result.slice(0, orderByClause.start) + orderResult + result.slice(orderByClause.end);
|
|
771
|
+
}
|
|
496
772
|
}
|
|
497
773
|
}
|
|
498
774
|
return result;
|
|
@@ -2062,6 +2338,9 @@ var duckDbMap = (name, valueType) => customType({
|
|
|
2062
2338
|
return `MAP (STRING, ${valueType})`;
|
|
2063
2339
|
},
|
|
2064
2340
|
toDriver(value) {
|
|
2341
|
+
if (Object.keys(value).length === 0) {
|
|
2342
|
+
return buildMapLiteral(value, valueType);
|
|
2343
|
+
}
|
|
2065
2344
|
return wrapMap(value, valueType);
|
|
2066
2345
|
},
|
|
2067
2346
|
fromDriver(value) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export declare function scrubForRewrite(query: string): string;
|
|
2
2
|
export declare function adaptArrayOperators(query: string): string;
|
|
3
3
|
/**
|
|
4
|
-
* Qualifies unqualified column references in JOIN ON clauses
|
|
4
|
+
* Qualifies unqualified column references in JOIN ON clauses, SELECT, WHERE,
|
|
5
|
+
* and ORDER BY clauses.
|
|
5
6
|
*
|
|
6
7
|
* Transforms patterns like:
|
|
7
|
-
* `left join "b" on "col" = "col"`
|
|
8
|
+
* `select "col" from "a" left join "b" on "col" = "col" where "col" in (...)`
|
|
8
9
|
* To:
|
|
9
|
-
* `left join "b" on "a"."col" = "b"."col"`
|
|
10
|
+
* `select "a"."col" from "a" left join "b" on "a"."col" = "b"."col" where "a"."col" in (...)`
|
|
10
11
|
*
|
|
11
12
|
* This fixes the issue where drizzle-orm generates unqualified column
|
|
12
13
|
* references when joining CTEs with eq().
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"module": "./dist/index.mjs",
|
|
4
4
|
"main": "./dist/index.mjs",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
|
-
"version": "1.1.
|
|
6
|
+
"version": "1.1.4",
|
|
7
7
|
"description": "A drizzle ORM client for use with DuckDB. Based on drizzle's Postgres client.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|
|
@@ -77,5 +77,8 @@
|
|
|
77
77
|
"src/**/*.ts",
|
|
78
78
|
"dist/*.mjs",
|
|
79
79
|
"dist/**/*.d.ts"
|
|
80
|
-
]
|
|
80
|
+
],
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"@duckdb/node-bindings-darwin-arm64": "^1.4.2-r.1"
|
|
83
|
+
}
|
|
81
84
|
}
|
package/src/columns.ts
CHANGED
|
@@ -237,7 +237,12 @@ export const duckDbMap = <TData extends Record<string, any>>(
|
|
|
237
237
|
dataType() {
|
|
238
238
|
return `MAP (STRING, ${valueType})`;
|
|
239
239
|
},
|
|
240
|
-
toDriver(value: TData)
|
|
240
|
+
toDriver(value: TData) {
|
|
241
|
+
// Use SQL literals for empty maps due to DuckDB type inference issues
|
|
242
|
+
// with mapValue() when there are no entries to infer types from
|
|
243
|
+
if (Object.keys(value).length === 0) {
|
|
244
|
+
return buildMapLiteral(value, valueType);
|
|
245
|
+
}
|
|
241
246
|
return wrapMap(value, valueType);
|
|
242
247
|
},
|
|
243
248
|
fromDriver(value: TData | MapValueWrapper): TData {
|