@leonardovida-md/drizzle-neo-duckdb 1.1.4 → 1.2.0

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/index.mjs CHANGED
@@ -15,765 +15,6 @@ import { PgTransaction } from "drizzle-orm/pg-core";
15
15
  import { PgPreparedQuery, PgSession } from "drizzle-orm/pg-core/session";
16
16
  import { fillPlaceholders, sql } from "drizzle-orm/sql/sql";
17
17
 
18
- // src/sql/query-rewriters.ts
19
- var OPERATORS = [
20
- { token: "@>", fn: "array_has_all" },
21
- { token: "<@", fn: "array_has_all", swap: true },
22
- { token: "&&", fn: "array_has_any" }
23
- ];
24
- var isWhitespace = (char) => char !== undefined && /\s/.test(char);
25
- function scrubForRewrite(query) {
26
- let scrubbed = "";
27
- let state = "code";
28
- for (let i = 0;i < query.length; i += 1) {
29
- const char = query[i];
30
- const next = query[i + 1];
31
- if (state === "code") {
32
- if (char === "'") {
33
- scrubbed += "'";
34
- state = "single";
35
- continue;
36
- }
37
- if (char === '"') {
38
- scrubbed += '"';
39
- state = "double";
40
- continue;
41
- }
42
- if (char === "-" && next === "-") {
43
- scrubbed += " ";
44
- i += 1;
45
- state = "lineComment";
46
- continue;
47
- }
48
- if (char === "/" && next === "*") {
49
- scrubbed += " ";
50
- i += 1;
51
- state = "blockComment";
52
- continue;
53
- }
54
- scrubbed += char;
55
- continue;
56
- }
57
- if (state === "single") {
58
- if (char === "'" && next === "'") {
59
- scrubbed += "''";
60
- i += 1;
61
- continue;
62
- }
63
- scrubbed += char === "'" ? "'" : ".";
64
- if (char === "'") {
65
- state = "code";
66
- }
67
- continue;
68
- }
69
- if (state === "double") {
70
- if (char === '"' && next === '"') {
71
- scrubbed += '""';
72
- i += 1;
73
- continue;
74
- }
75
- scrubbed += char === '"' ? '"' : ".";
76
- if (char === '"') {
77
- state = "code";
78
- }
79
- continue;
80
- }
81
- if (state === "lineComment") {
82
- scrubbed += char === `
83
- ` ? `
84
- ` : " ";
85
- if (char === `
86
- `) {
87
- state = "code";
88
- }
89
- continue;
90
- }
91
- if (state === "blockComment") {
92
- if (char === "*" && next === "/") {
93
- scrubbed += " ";
94
- i += 1;
95
- state = "code";
96
- } else {
97
- scrubbed += " ";
98
- }
99
- }
100
- }
101
- return scrubbed;
102
- }
103
- function findNextOperator(scrubbed, start) {
104
- for (let idx = start;idx < scrubbed.length; idx += 1) {
105
- for (const operator of OPERATORS) {
106
- if (scrubbed.startsWith(operator.token, idx)) {
107
- return { index: idx, operator };
108
- }
109
- }
110
- }
111
- return null;
112
- }
113
- function walkLeft(source, scrubbed, start) {
114
- let idx = start;
115
- while (idx >= 0 && isWhitespace(scrubbed[idx])) {
116
- idx -= 1;
117
- }
118
- let depth = 0;
119
- for (;idx >= 0; idx -= 1) {
120
- const ch = scrubbed[idx];
121
- if (ch === ")" || ch === "]") {
122
- depth += 1;
123
- } else if (ch === "(" || ch === "[") {
124
- if (depth === 0) {
125
- return [idx + 1, source.slice(idx + 1, start + 1)];
126
- }
127
- depth = Math.max(0, depth - 1);
128
- } else if (depth === 0 && isWhitespace(ch)) {
129
- return [idx + 1, source.slice(idx + 1, start + 1)];
130
- }
131
- }
132
- return [0, source.slice(0, start + 1)];
133
- }
134
- function walkRight(source, scrubbed, start) {
135
- let idx = start;
136
- while (idx < scrubbed.length && isWhitespace(scrubbed[idx])) {
137
- idx += 1;
138
- }
139
- let depth = 0;
140
- for (;idx < scrubbed.length; idx += 1) {
141
- const ch = scrubbed[idx];
142
- if (ch === "(" || ch === "[") {
143
- depth += 1;
144
- } else if (ch === ")" || ch === "]") {
145
- if (depth === 0) {
146
- return [idx, source.slice(start, idx)];
147
- }
148
- depth = Math.max(0, depth - 1);
149
- } else if (depth === 0 && isWhitespace(ch)) {
150
- return [idx, source.slice(start, idx)];
151
- }
152
- }
153
- return [scrubbed.length, source.slice(start)];
154
- }
155
- function adaptArrayOperators(query) {
156
- if (query.indexOf("@>") === -1 && query.indexOf("<@") === -1 && query.indexOf("&&") === -1) {
157
- return query;
158
- }
159
- let rewritten = query;
160
- let scrubbed = scrubForRewrite(query);
161
- let searchStart = 0;
162
- while (true) {
163
- const next = findNextOperator(scrubbed, searchStart);
164
- if (!next)
165
- break;
166
- const { index, operator } = next;
167
- const [leftStart, leftExpr] = walkLeft(rewritten, scrubbed, index - 1);
168
- const [rightEnd, rightExpr] = walkRight(rewritten, scrubbed, index + operator.token.length);
169
- const left = leftExpr.trim();
170
- const right = rightExpr.trim();
171
- const replacement = `${operator.fn}(${operator.swap ? right : left}, ${operator.swap ? left : right})`;
172
- rewritten = rewritten.slice(0, leftStart) + replacement + rewritten.slice(rightEnd);
173
- scrubbed = scrubForRewrite(rewritten);
174
- searchStart = leftStart + replacement.length;
175
- }
176
- return rewritten;
177
- }
178
- function extractQuotedIdentifier(original, start) {
179
- if (original[start] !== '"') {
180
- return null;
181
- }
182
- let pos = start + 1;
183
- while (pos < original.length) {
184
- if (original[pos] === '"') {
185
- if (original[pos + 1] === '"') {
186
- pos += 2;
187
- continue;
188
- }
189
- break;
190
- }
191
- pos++;
192
- }
193
- if (pos >= original.length) {
194
- return null;
195
- }
196
- return {
197
- name: original.slice(start + 1, pos),
198
- end: pos + 1
199
- };
200
- }
201
- function findMainFromClause(scrubbed) {
202
- const lowerScrubbed = scrubbed.toLowerCase();
203
- let searchStart = 0;
204
- const withMatch = /\bwith\s+/i.exec(lowerScrubbed);
205
- if (withMatch) {
206
- let depth = 0;
207
- let pos = withMatch.index + withMatch[0].length;
208
- while (pos < scrubbed.length) {
209
- const char = scrubbed[pos];
210
- if (char === "(") {
211
- depth++;
212
- } else if (char === ")") {
213
- depth--;
214
- } else if (depth === 0) {
215
- const remaining = lowerScrubbed.slice(pos);
216
- if (/^\s*select\s+/i.test(remaining)) {
217
- searchStart = pos;
218
- break;
219
- }
220
- }
221
- pos++;
222
- }
223
- }
224
- const fromPattern = /\bfrom\s+/gi;
225
- fromPattern.lastIndex = searchStart;
226
- const fromMatch = fromPattern.exec(lowerScrubbed);
227
- return fromMatch ? fromMatch.index + fromMatch[0].length : -1;
228
- }
229
- function parseTableSources(original, scrubbed) {
230
- const sources = [];
231
- const lowerScrubbed = scrubbed.toLowerCase();
232
- const fromPos = findMainFromClause(scrubbed);
233
- if (fromPos < 0) {
234
- return sources;
235
- }
236
- const fromTable = parseTableRef(original, scrubbed, fromPos);
237
- if (fromTable) {
238
- sources.push(fromTable);
239
- }
240
- const joinPattern = /\b(left\s+|right\s+|inner\s+|full\s+|cross\s+)?join\s+/gi;
241
- joinPattern.lastIndex = fromPos;
242
- let joinMatch;
243
- while ((joinMatch = joinPattern.exec(lowerScrubbed)) !== null) {
244
- const tableStart = joinMatch.index + joinMatch[0].length;
245
- const joinTable = parseTableRef(original, scrubbed, tableStart);
246
- if (joinTable) {
247
- sources.push(joinTable);
248
- }
249
- }
250
- return sources;
251
- }
252
- function parseTableRef(original, scrubbed, start) {
253
- let pos = start;
254
- while (pos < scrubbed.length && isWhitespace(scrubbed[pos])) {
255
- pos++;
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
- }
290
- if (original[pos] !== '"') {
291
- return null;
292
- }
293
- const nameStart = pos;
294
- const firstIdent = extractQuotedIdentifier(original, pos);
295
- if (!firstIdent) {
296
- return null;
297
- }
298
- let name = firstIdent.name;
299
- pos = firstIdent.end;
300
- let afterName = pos;
301
- while (afterName < scrubbed.length && isWhitespace(scrubbed[afterName])) {
302
- afterName++;
303
- }
304
- if (scrubbed[afterName] === ".") {
305
- afterName++;
306
- while (afterName < scrubbed.length && isWhitespace(scrubbed[afterName])) {
307
- afterName++;
308
- }
309
- if (original[afterName] === '"') {
310
- const tableIdent = extractQuotedIdentifier(original, afterName);
311
- if (tableIdent) {
312
- name = tableIdent.name;
313
- pos = tableIdent.end;
314
- }
315
- }
316
- }
317
- let alias;
318
- let aliasPos = pos;
319
- while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
320
- aliasPos++;
321
- }
322
- const afterTable = scrubbed.slice(aliasPos).toLowerCase();
323
- if (afterTable.startsWith("as ")) {
324
- aliasPos += 3;
325
- while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
326
- aliasPos++;
327
- }
328
- }
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 ")) {
331
- const aliasIdent = extractQuotedIdentifier(original, aliasPos);
332
- if (aliasIdent) {
333
- alias = aliasIdent.name;
334
- }
335
- }
336
- return {
337
- name,
338
- alias,
339
- position: nameStart
340
- };
341
- }
342
- function findJoinClauses(original, scrubbed, sources, fromPos) {
343
- const clauses = [];
344
- const lowerScrubbed = scrubbed.toLowerCase();
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;
347
- let match;
348
- let sourceIndex = 1;
349
- while ((match = joinPattern.exec(lowerScrubbed)) !== null) {
350
- const joinType = (match[1] || "").trim().toLowerCase();
351
- const joinKeywordEnd = match.index + (match[1] || "").length + "join".length;
352
- let tableStart = joinKeywordEnd;
353
- while (tableStart < original.length && isWhitespace(original[tableStart])) {
354
- tableStart++;
355
- }
356
- const tableIdent = extractQuotedIdentifier(original, tableStart);
357
- if (!tableIdent)
358
- continue;
359
- let tableName = tableIdent.name;
360
- let afterTable = tableIdent.end;
361
- let checkPos = afterTable;
362
- while (checkPos < scrubbed.length && isWhitespace(scrubbed[checkPos])) {
363
- checkPos++;
364
- }
365
- if (scrubbed[checkPos] === ".") {
366
- checkPos++;
367
- while (checkPos < scrubbed.length && isWhitespace(scrubbed[checkPos])) {
368
- checkPos++;
369
- }
370
- const realTableIdent = extractQuotedIdentifier(original, checkPos);
371
- if (realTableIdent) {
372
- tableName = realTableIdent.name;
373
- afterTable = realTableIdent.end;
374
- }
375
- }
376
- let tableAlias;
377
- let aliasPos = afterTable;
378
- while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
379
- aliasPos++;
380
- }
381
- const afterTableStr = scrubbed.slice(aliasPos).toLowerCase();
382
- if (afterTableStr.startsWith("as ")) {
383
- aliasPos += 3;
384
- while (aliasPos < scrubbed.length && isWhitespace(scrubbed[aliasPos])) {
385
- aliasPos++;
386
- }
387
- }
388
- if (original[aliasPos] === '"' && !afterTableStr.startsWith("on ")) {
389
- const aliasIdent = extractQuotedIdentifier(original, aliasPos);
390
- if (aliasIdent) {
391
- tableAlias = aliasIdent.name;
392
- }
393
- }
394
- const onStart = match.index + match[0].length;
395
- 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;
396
- const remaining = lowerScrubbed.slice(onStart);
397
- const endMatch = endPattern.exec(remaining);
398
- const onEnd = endMatch ? onStart + endMatch.index : scrubbed.length;
399
- let leftSource = "";
400
- if (sourceIndex > 0 && sourceIndex <= sources.length) {
401
- const prev = sources[sourceIndex - 1];
402
- leftSource = prev?.alias || prev?.name || "";
403
- }
404
- const rightSource = tableAlias || tableName;
405
- clauses.push({
406
- joinType,
407
- tableName,
408
- tableAlias,
409
- onStart,
410
- onEnd,
411
- leftSource,
412
- rightSource
413
- });
414
- sourceIndex++;
415
- }
416
- return clauses;
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
- }
572
- function qualifyJoinColumns(query) {
573
- const lowerQuery = query.toLowerCase();
574
- if (!lowerQuery.includes("join")) {
575
- return query;
576
- }
577
- const scrubbed = scrubForRewrite(query);
578
- const fromPos = findMainFromClause(scrubbed);
579
- if (fromPos < 0) {
580
- return query;
581
- }
582
- const sources = parseTableSources(query, scrubbed);
583
- if (sources.length < 2) {
584
- return query;
585
- }
586
- const joinClauses = findJoinClauses(query, scrubbed, sources, fromPos);
587
- if (joinClauses.length === 0) {
588
- return query;
589
- }
590
- const firstSource = sources[0];
591
- const defaultQualifier = firstSource.alias || firstSource.name;
592
- let result = query;
593
- let totalOffset = 0;
594
- for (const join of joinClauses) {
595
- const scrubbedOnClause = scrubbed.slice(join.onStart, join.onEnd);
596
- const originalOnClause = query.slice(join.onStart, join.onEnd);
597
- let clauseResult = originalOnClause;
598
- let clauseOffset = 0;
599
- let eqPos = -1;
600
- while ((eqPos = scrubbedOnClause.indexOf("=", eqPos + 1)) !== -1) {
601
- let lhsEnd = eqPos - 1;
602
- while (lhsEnd >= 0 && isWhitespace(scrubbedOnClause[lhsEnd])) {
603
- lhsEnd--;
604
- }
605
- if (scrubbedOnClause[lhsEnd] !== '"')
606
- continue;
607
- let lhsStartPos = lhsEnd - 1;
608
- while (lhsStartPos >= 0) {
609
- if (scrubbedOnClause[lhsStartPos] === '"') {
610
- if (lhsStartPos > 0 && scrubbedOnClause[lhsStartPos - 1] === '"') {
611
- lhsStartPos -= 2;
612
- continue;
613
- }
614
- break;
615
- }
616
- lhsStartPos--;
617
- }
618
- if (lhsStartPos < 0)
619
- continue;
620
- const lhsIsQualified = lhsStartPos > 0 && scrubbedOnClause[lhsStartPos - 1] === ".";
621
- let rhsStartPos = eqPos + 1;
622
- while (rhsStartPos < scrubbedOnClause.length && isWhitespace(scrubbedOnClause[rhsStartPos])) {
623
- rhsStartPos++;
624
- }
625
- const rhsChar = originalOnClause[rhsStartPos];
626
- const rhsIsParam = rhsChar === "$";
627
- const rhsIsStringLiteral = rhsChar === "'";
628
- const rhsIsColumn = rhsChar === '"';
629
- if (!rhsIsParam && !rhsIsStringLiteral && !rhsIsColumn)
630
- continue;
631
- const rhsIsQualified = !rhsIsColumn || rhsStartPos > 0 && scrubbedOnClause[rhsStartPos - 1] === ".";
632
- if (lhsIsQualified || rhsIsQualified)
633
- continue;
634
- const lhsIdent = extractQuotedIdentifier(originalOnClause, lhsStartPos);
635
- if (!lhsIdent)
636
- continue;
637
- let rhsIdent = null;
638
- let rhsValue = "";
639
- let rhsEnd = rhsStartPos;
640
- if (rhsIsParam) {
641
- let paramEnd = rhsStartPos + 1;
642
- while (paramEnd < originalOnClause.length && /\d/.test(originalOnClause[paramEnd])) {
643
- paramEnd++;
644
- }
645
- rhsValue = originalOnClause.slice(rhsStartPos, paramEnd);
646
- rhsEnd = paramEnd;
647
- } else if (rhsIsStringLiteral) {
648
- let literalEnd = rhsStartPos + 1;
649
- while (literalEnd < originalOnClause.length) {
650
- if (originalOnClause[literalEnd] === "'") {
651
- if (originalOnClause[literalEnd + 1] === "'") {
652
- literalEnd += 2;
653
- continue;
654
- }
655
- break;
656
- }
657
- literalEnd++;
658
- }
659
- rhsValue = originalOnClause.slice(rhsStartPos, literalEnd + 1);
660
- rhsEnd = literalEnd + 1;
661
- } else if (rhsIsColumn) {
662
- rhsIdent = extractQuotedIdentifier(originalOnClause, rhsStartPos);
663
- if (rhsIdent) {
664
- if (rhsIdent.end < scrubbedOnClause.length && scrubbedOnClause[rhsIdent.end] === ".") {
665
- continue;
666
- }
667
- rhsValue = `"${rhsIdent.name}"`;
668
- rhsEnd = rhsIdent.end;
669
- }
670
- }
671
- if (!rhsValue)
672
- continue;
673
- if (!rhsIsColumn || !rhsIdent || lhsIdent.name !== rhsIdent.name) {
674
- continue;
675
- }
676
- const lhsOriginal = `"${lhsIdent.name}"`;
677
- let newLhs = lhsOriginal;
678
- let newRhs = rhsValue;
679
- if (!lhsIsQualified && join.leftSource) {
680
- newLhs = `"${join.leftSource}"."${lhsIdent.name}"`;
681
- }
682
- if (!rhsIsQualified && rhsIsColumn && rhsIdent && join.rightSource) {
683
- newRhs = `"${join.rightSource}"."${rhsIdent.name}"`;
684
- }
685
- if (newLhs !== lhsOriginal || newRhs !== rhsValue) {
686
- const opStart = lhsIdent.end;
687
- let opEnd = opStart;
688
- while (opEnd < rhsEnd && (isWhitespace(originalOnClause[opEnd]) || originalOnClause[opEnd] === "=")) {
689
- opEnd++;
690
- }
691
- const operator = originalOnClause.slice(opStart, opEnd);
692
- const newExpr = `${newLhs}${operator}${newRhs}`;
693
- const oldExprLength = rhsEnd - lhsStartPos;
694
- clauseResult = clauseResult.slice(0, lhsStartPos + clauseOffset) + newExpr + clauseResult.slice(lhsStartPos + oldExprLength + clauseOffset);
695
- clauseOffset += newExpr.length - oldExprLength;
696
- }
697
- }
698
- if (clauseResult !== originalOnClause) {
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
- }
772
- }
773
- }
774
- return result;
775
- }
776
-
777
18
  // src/sql/result-mapper.ts
778
19
  import {
779
20
  Column,
@@ -1409,24 +650,6 @@ function isSavepointSyntaxError(error) {
1409
650
  }
1410
651
  return error.message.toLowerCase().includes("savepoint") && error.message.toLowerCase().includes("syntax error");
1411
652
  }
1412
- function rewriteQuery(mode, query) {
1413
- if (mode === "never") {
1414
- return { sql: query, rewritten: false };
1415
- }
1416
- let result = query;
1417
- let wasRewritten = false;
1418
- const arrayRewritten = adaptArrayOperators(result);
1419
- if (arrayRewritten !== result) {
1420
- result = arrayRewritten;
1421
- wasRewritten = true;
1422
- }
1423
- const joinQualified = qualifyJoinColumns(result);
1424
- if (joinQualified !== result) {
1425
- result = joinQualified;
1426
- wasRewritten = true;
1427
- }
1428
- return { sql: result, rewritten: wasRewritten };
1429
- }
1430
653
 
1431
654
  class DuckDBPreparedQuery extends PgPreparedQuery {
1432
655
  client;
@@ -1437,12 +660,11 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
1437
660
  fields;
1438
661
  _isResponseInArrayMode;
1439
662
  customResultMapper;
1440
- rewriteArraysMode;
1441
663
  rejectStringArrayLiterals;
1442
664
  prepareCache;
1443
665
  warnOnStringArrayLiteral;
1444
666
  static [entityKind] = "DuckDBPreparedQuery";
1445
- constructor(client, dialect, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper, rewriteArraysMode, rejectStringArrayLiterals, prepareCache, warnOnStringArrayLiteral) {
667
+ constructor(client, dialect, queryString, params, logger, fields, _isResponseInArrayMode, customResultMapper, rejectStringArrayLiterals, prepareCache, warnOnStringArrayLiteral) {
1446
668
  super({ sql: queryString, params });
1447
669
  this.client = client;
1448
670
  this.dialect = dialect;
@@ -1452,7 +674,6 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
1452
674
  this.fields = fields;
1453
675
  this._isResponseInArrayMode = _isResponseInArrayMode;
1454
676
  this.customResultMapper = customResultMapper;
1455
- this.rewriteArraysMode = rewriteArraysMode;
1456
677
  this.rejectStringArrayLiterals = rejectStringArrayLiterals;
1457
678
  this.prepareCache = prepareCache;
1458
679
  this.warnOnStringArrayLiteral = warnOnStringArrayLiteral;
@@ -1463,20 +684,16 @@ class DuckDBPreparedQuery extends PgPreparedQuery {
1463
684
  rejectStringArrayLiterals: this.rejectStringArrayLiterals,
1464
685
  warnOnStringArrayLiteral: this.warnOnStringArrayLiteral ? () => this.warnOnStringArrayLiteral?.(this.queryString) : undefined
1465
686
  });
1466
- const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, this.queryString);
1467
- if (didRewrite) {
1468
- this.logger.logQuery(`[duckdb] original query before array rewrite: ${this.queryString}`, params);
1469
- }
1470
- this.logger.logQuery(rewrittenQuery, params);
687
+ this.logger.logQuery(this.queryString, params);
1471
688
  const { fields, joinsNotNullableMap, customResultMapper } = this;
1472
689
  if (fields) {
1473
- const { rows: rows2 } = await executeArraysOnClient(this.client, rewrittenQuery, params, { prepareCache: this.prepareCache });
690
+ const { rows: rows2 } = await executeArraysOnClient(this.client, this.queryString, params, { prepareCache: this.prepareCache });
1474
691
  if (rows2.length === 0) {
1475
692
  return [];
1476
693
  }
1477
694
  return customResultMapper ? customResultMapper(rows2) : rows2.map((row) => mapResultRow(fields, row, joinsNotNullableMap));
1478
695
  }
1479
- const rows = await executeOnClient(this.client, rewrittenQuery, params, {
696
+ const rows = await executeOnClient(this.client, this.queryString, params, {
1480
697
  prepareCache: this.prepareCache
1481
698
  });
1482
699
  return rows;
@@ -1496,7 +713,6 @@ class DuckDBSession extends PgSession {
1496
713
  static [entityKind] = "DuckDBSession";
1497
714
  dialect;
1498
715
  logger;
1499
- rewriteArraysMode;
1500
716
  rejectStringArrayLiterals;
1501
717
  prepareCache;
1502
718
  hasWarnedArrayLiteral = false;
@@ -1508,17 +724,15 @@ class DuckDBSession extends PgSession {
1508
724
  this.options = options;
1509
725
  this.dialect = dialect;
1510
726
  this.logger = options.logger ?? new NoopLogger;
1511
- this.rewriteArraysMode = options.rewriteArrays ?? "auto";
1512
727
  this.rejectStringArrayLiterals = options.rejectStringArrayLiterals ?? false;
1513
728
  this.prepareCache = options.prepareCache;
1514
729
  this.options = {
1515
730
  ...options,
1516
- rewriteArrays: this.rewriteArraysMode,
1517
731
  prepareCache: this.prepareCache
1518
732
  };
1519
733
  }
1520
734
  prepareQuery(query, fields, name, isResponseInArrayMode, customResultMapper) {
1521
- 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);
735
+ return new DuckDBPreparedQuery(this.client, this.dialect, query.sql, query.params, this.logger, fields, isResponseInArrayMode, customResultMapper, this.rejectStringArrayLiterals, this.prepareCache, this.rejectStringArrayLiterals ? undefined : this.warnOnStringArrayLiteral);
1522
736
  }
1523
737
  execute(query) {
1524
738
  this.dialect.resetPgJsonFlag();
@@ -1578,12 +792,8 @@ query: ${query}`, []);
1578
792
  rejectStringArrayLiterals: this.rejectStringArrayLiterals,
1579
793
  warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
1580
794
  });
1581
- const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
1582
- if (didRewrite) {
1583
- this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
1584
- }
1585
- this.logger.logQuery(rewrittenQuery, params);
1586
- return executeInBatches(this.client, rewrittenQuery, params, options);
795
+ this.logger.logQuery(builtQuery.sql, params);
796
+ return executeInBatches(this.client, builtQuery.sql, params, options);
1587
797
  }
1588
798
  executeBatchesRaw(query, options = {}) {
1589
799
  this.dialect.resetPgJsonFlag();
@@ -1593,12 +803,8 @@ query: ${query}`, []);
1593
803
  rejectStringArrayLiterals: this.rejectStringArrayLiterals,
1594
804
  warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
1595
805
  });
1596
- const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
1597
- if (didRewrite) {
1598
- this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
1599
- }
1600
- this.logger.logQuery(rewrittenQuery, params);
1601
- return executeInBatchesRaw(this.client, rewrittenQuery, params, options);
806
+ this.logger.logQuery(builtQuery.sql, params);
807
+ return executeInBatchesRaw(this.client, builtQuery.sql, params, options);
1602
808
  }
1603
809
  async executeArrow(query) {
1604
810
  this.dialect.resetPgJsonFlag();
@@ -1608,12 +814,8 @@ query: ${query}`, []);
1608
814
  rejectStringArrayLiterals: this.rejectStringArrayLiterals,
1609
815
  warnOnStringArrayLiteral: this.rejectStringArrayLiterals ? undefined : () => this.warnOnStringArrayLiteral(builtQuery.sql)
1610
816
  });
1611
- const { sql: rewrittenQuery, rewritten: didRewrite } = rewriteQuery(this.rewriteArraysMode, builtQuery.sql);
1612
- if (didRewrite) {
1613
- this.logger.logQuery(`[duckdb] original query before array rewrite: ${builtQuery.sql}`, params);
1614
- }
1615
- this.logger.logQuery(rewrittenQuery, params);
1616
- return executeArrowOnClient(this.client, rewrittenQuery, params);
817
+ this.logger.logQuery(builtQuery.sql, params);
818
+ return executeArrowOnClient(this.client, builtQuery.sql, params);
1617
819
  }
1618
820
  markRollbackOnly() {
1619
821
  this.rollbackOnly = true;
@@ -1715,6 +917,335 @@ import {
1715
917
  import {
1716
918
  sql as sql2
1717
919
  } from "drizzle-orm";
920
+
921
+ // src/sql/ast-transformer.ts
922
+ import nodeSqlParser from "node-sql-parser";
923
+
924
+ // src/sql/visitors/array-operators.ts
925
+ var OPERATOR_MAP = {
926
+ "@>": { fn: "array_has_all" },
927
+ "<@": { fn: "array_has_all", swap: true },
928
+ "&&": { fn: "array_has_any" }
929
+ };
930
+ function walkExpression(expr, parent, key) {
931
+ if (!expr || typeof expr !== "object")
932
+ return false;
933
+ let transformed = false;
934
+ const exprObj = expr;
935
+ if ("type" in expr && exprObj.type === "binary_expr") {
936
+ const binary = expr;
937
+ const mapping = OPERATOR_MAP[binary.operator];
938
+ if (mapping) {
939
+ const fnExpr = {
940
+ type: "function",
941
+ name: { name: [{ type: "default", value: mapping.fn }] },
942
+ args: {
943
+ type: "expr_list",
944
+ value: mapping.swap ? [binary.right, binary.left] : [binary.left, binary.right]
945
+ }
946
+ };
947
+ if (parent && key) {
948
+ parent[key] = fnExpr;
949
+ }
950
+ transformed = true;
951
+ } else {
952
+ transformed = walkExpression(binary.left, binary, "left") || transformed;
953
+ transformed = walkExpression(binary.right, binary, "right") || transformed;
954
+ }
955
+ }
956
+ if ("type" in expr && exprObj.type === "unary_expr") {
957
+ if ("expr" in exprObj) {
958
+ transformed = walkExpression(exprObj.expr, exprObj, "expr") || transformed;
959
+ }
960
+ }
961
+ if ("type" in expr && exprObj.type === "case") {
962
+ if ("expr" in exprObj && exprObj.expr) {
963
+ transformed = walkExpression(exprObj.expr, exprObj, "expr") || transformed;
964
+ }
965
+ if ("args" in exprObj && Array.isArray(exprObj.args)) {
966
+ for (let i = 0;i < exprObj.args.length; i++) {
967
+ const whenClause = exprObj.args[i];
968
+ if (whenClause.cond) {
969
+ transformed = walkExpression(whenClause.cond, whenClause, "cond") || transformed;
970
+ }
971
+ if (whenClause.result) {
972
+ transformed = walkExpression(whenClause.result, whenClause, "result") || transformed;
973
+ }
974
+ }
975
+ }
976
+ }
977
+ if ("args" in expr && exprObj.args) {
978
+ const args = exprObj.args;
979
+ if ("value" in args && Array.isArray(args.value)) {
980
+ for (let i = 0;i < args.value.length; i++) {
981
+ transformed = walkExpression(args.value[i], args.value, String(i)) || transformed;
982
+ }
983
+ } else if ("expr" in args) {
984
+ transformed = walkExpression(args.expr, args, "expr") || transformed;
985
+ }
986
+ }
987
+ if ("ast" in exprObj && exprObj.ast) {
988
+ const subAst = exprObj.ast;
989
+ if (subAst.type === "select") {
990
+ transformed = walkSelectImpl(subAst) || transformed;
991
+ }
992
+ }
993
+ if ("type" in expr && exprObj.type === "expr_list") {
994
+ if ("value" in exprObj && Array.isArray(exprObj.value)) {
995
+ for (let i = 0;i < exprObj.value.length; i++) {
996
+ transformed = walkExpression(exprObj.value[i], exprObj.value, String(i)) || transformed;
997
+ }
998
+ }
999
+ }
1000
+ return transformed;
1001
+ }
1002
+ function walkFrom(from) {
1003
+ if (!from || !Array.isArray(from))
1004
+ return false;
1005
+ let transformed = false;
1006
+ for (const f of from) {
1007
+ if ("join" in f) {
1008
+ const join = f;
1009
+ transformed = walkExpression(join.on, join, "on") || transformed;
1010
+ }
1011
+ if ("expr" in f && f.expr && "ast" in f.expr) {
1012
+ transformed = walkSelectImpl(f.expr.ast) || transformed;
1013
+ }
1014
+ }
1015
+ return transformed;
1016
+ }
1017
+ function walkSelectImpl(select) {
1018
+ let transformed = false;
1019
+ if (select.with) {
1020
+ for (const cte of select.with) {
1021
+ const cteSelect = cte.stmt?.ast ?? cte.stmt;
1022
+ if (cteSelect && cteSelect.type === "select") {
1023
+ transformed = walkSelectImpl(cteSelect) || transformed;
1024
+ }
1025
+ }
1026
+ }
1027
+ if (Array.isArray(select.from)) {
1028
+ transformed = walkFrom(select.from) || transformed;
1029
+ }
1030
+ transformed = walkExpression(select.where, select, "where") || transformed;
1031
+ if (select.having) {
1032
+ if (Array.isArray(select.having)) {
1033
+ for (let i = 0;i < select.having.length; i++) {
1034
+ transformed = walkExpression(select.having[i], select.having, String(i)) || transformed;
1035
+ }
1036
+ } else {
1037
+ transformed = walkExpression(select.having, select, "having") || transformed;
1038
+ }
1039
+ }
1040
+ if (Array.isArray(select.columns)) {
1041
+ for (const col of select.columns) {
1042
+ if ("expr" in col) {
1043
+ transformed = walkExpression(col.expr, col, "expr") || transformed;
1044
+ }
1045
+ }
1046
+ }
1047
+ if (select._next) {
1048
+ transformed = walkSelectImpl(select._next) || transformed;
1049
+ }
1050
+ return transformed;
1051
+ }
1052
+ function transformArrayOperators(ast) {
1053
+ const statements = Array.isArray(ast) ? ast : [ast];
1054
+ let transformed = false;
1055
+ for (const stmt of statements) {
1056
+ if (stmt.type === "select") {
1057
+ transformed = walkSelectImpl(stmt) || transformed;
1058
+ }
1059
+ }
1060
+ return transformed;
1061
+ }
1062
+
1063
+ // src/sql/visitors/column-qualifier.ts
1064
+ function getTableSource(from) {
1065
+ if ("table" in from && from.table) {
1066
+ return {
1067
+ name: from.table,
1068
+ alias: from.as ?? null
1069
+ };
1070
+ }
1071
+ if ("expr" in from && from.as) {
1072
+ return {
1073
+ name: from.as,
1074
+ alias: from.as
1075
+ };
1076
+ }
1077
+ return null;
1078
+ }
1079
+ function getQualifier(source) {
1080
+ return source.alias ?? source.name;
1081
+ }
1082
+ function isUnqualifiedColumnRef(expr) {
1083
+ return typeof expr === "object" && expr !== null && "type" in expr && expr.type === "column_ref" && !(("table" in expr) && expr.table);
1084
+ }
1085
+ function getColumnName(col) {
1086
+ if (typeof col.column === "string") {
1087
+ return col.column;
1088
+ }
1089
+ if (col.column && "expr" in col.column && col.column.expr?.value) {
1090
+ return String(col.column.expr.value);
1091
+ }
1092
+ return null;
1093
+ }
1094
+ function walkOnClause(expr, leftSource, rightSource, ambiguousColumns) {
1095
+ if (!expr || typeof expr !== "object")
1096
+ return false;
1097
+ let transformed = false;
1098
+ if (expr.type === "binary_expr") {
1099
+ if (expr.operator === "=") {
1100
+ const left = expr.left;
1101
+ const right = expr.right;
1102
+ if (isUnqualifiedColumnRef(left) && isUnqualifiedColumnRef(right)) {
1103
+ const leftColName = getColumnName(left);
1104
+ const rightColName = getColumnName(right);
1105
+ if (leftColName && rightColName && leftColName === rightColName) {
1106
+ left.table = leftSource;
1107
+ right.table = rightSource;
1108
+ ambiguousColumns.add(leftColName);
1109
+ transformed = true;
1110
+ }
1111
+ }
1112
+ }
1113
+ if (expr.operator === "AND" || expr.operator === "OR") {
1114
+ transformed = walkOnClause(expr.left, leftSource, rightSource, ambiguousColumns) || transformed;
1115
+ transformed = walkOnClause(expr.right, leftSource, rightSource, ambiguousColumns) || transformed;
1116
+ }
1117
+ }
1118
+ return transformed;
1119
+ }
1120
+ function qualifyAmbiguousInExpression(expr, defaultQualifier, ambiguousColumns) {
1121
+ if (!expr || typeof expr !== "object")
1122
+ return false;
1123
+ let transformed = false;
1124
+ if (isUnqualifiedColumnRef(expr)) {
1125
+ const colName = getColumnName(expr);
1126
+ if (colName && ambiguousColumns.has(colName)) {
1127
+ expr.table = defaultQualifier;
1128
+ transformed = true;
1129
+ }
1130
+ return transformed;
1131
+ }
1132
+ if ("type" in expr && expr.type === "binary_expr") {
1133
+ const binary = expr;
1134
+ transformed = qualifyAmbiguousInExpression(binary.left, defaultQualifier, ambiguousColumns) || transformed;
1135
+ transformed = qualifyAmbiguousInExpression(binary.right, defaultQualifier, ambiguousColumns) || transformed;
1136
+ return transformed;
1137
+ }
1138
+ if ("args" in expr && expr.args) {
1139
+ const args = expr.args;
1140
+ if (args.value && Array.isArray(args.value)) {
1141
+ for (const arg of args.value) {
1142
+ transformed = qualifyAmbiguousInExpression(arg, defaultQualifier, ambiguousColumns) || transformed;
1143
+ }
1144
+ }
1145
+ if (args.expr) {
1146
+ transformed = qualifyAmbiguousInExpression(args.expr, defaultQualifier, ambiguousColumns) || transformed;
1147
+ }
1148
+ }
1149
+ return transformed;
1150
+ }
1151
+ function walkSelect(select) {
1152
+ let transformed = false;
1153
+ const ambiguousColumns = new Set;
1154
+ if (Array.isArray(select.from) && select.from.length >= 2) {
1155
+ const firstSource = getTableSource(select.from[0]);
1156
+ const defaultQualifier = firstSource ? getQualifier(firstSource) : "";
1157
+ let prevSource = firstSource;
1158
+ for (const from of select.from) {
1159
+ if ("join" in from) {
1160
+ const join = from;
1161
+ const currentSource = getTableSource(join);
1162
+ if (join.on && prevSource && currentSource) {
1163
+ const leftQualifier = getQualifier(prevSource);
1164
+ const rightQualifier = getQualifier(currentSource);
1165
+ transformed = walkOnClause(join.on, leftQualifier, rightQualifier, ambiguousColumns) || transformed;
1166
+ }
1167
+ prevSource = currentSource;
1168
+ } else {
1169
+ const source = getTableSource(from);
1170
+ if (source) {
1171
+ prevSource = source;
1172
+ }
1173
+ }
1174
+ if ("expr" in from && from.expr && "ast" in from.expr) {
1175
+ transformed = walkSelect(from.expr.ast) || transformed;
1176
+ }
1177
+ }
1178
+ if (ambiguousColumns.size > 0 && defaultQualifier) {
1179
+ if (Array.isArray(select.columns)) {
1180
+ for (const col of select.columns) {
1181
+ if ("expr" in col) {
1182
+ transformed = qualifyAmbiguousInExpression(col.expr, defaultQualifier, ambiguousColumns) || transformed;
1183
+ }
1184
+ }
1185
+ }
1186
+ transformed = qualifyAmbiguousInExpression(select.where, defaultQualifier, ambiguousColumns) || transformed;
1187
+ if (Array.isArray(select.orderby)) {
1188
+ for (const order of select.orderby) {
1189
+ if (order.expr) {
1190
+ transformed = qualifyAmbiguousInExpression(order.expr, defaultQualifier, ambiguousColumns) || transformed;
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ if (select.with) {
1197
+ for (const cte of select.with) {
1198
+ const cteSelect = cte.stmt?.ast ?? cte.stmt;
1199
+ if (cteSelect && cteSelect.type === "select") {
1200
+ transformed = walkSelect(cteSelect) || transformed;
1201
+ }
1202
+ }
1203
+ }
1204
+ if (select._next) {
1205
+ transformed = walkSelect(select._next) || transformed;
1206
+ }
1207
+ return transformed;
1208
+ }
1209
+ function qualifyJoinColumns(ast) {
1210
+ const statements = Array.isArray(ast) ? ast : [ast];
1211
+ let transformed = false;
1212
+ for (const stmt of statements) {
1213
+ if (stmt.type === "select") {
1214
+ transformed = walkSelect(stmt) || transformed;
1215
+ }
1216
+ }
1217
+ return transformed;
1218
+ }
1219
+
1220
+ // src/sql/ast-transformer.ts
1221
+ var { Parser } = nodeSqlParser;
1222
+ var parser = new Parser;
1223
+ function transformSQL(query) {
1224
+ const needsArrayTransform = query.includes("@>") || query.includes("<@") || query.includes("&&");
1225
+ const needsJoinTransform = query.toLowerCase().includes("join");
1226
+ if (!needsArrayTransform && !needsJoinTransform) {
1227
+ return { sql: query, transformed: false };
1228
+ }
1229
+ try {
1230
+ const ast = parser.astify(query, { database: "PostgreSQL" });
1231
+ let transformed = false;
1232
+ if (needsArrayTransform) {
1233
+ transformed = transformArrayOperators(ast) || transformed;
1234
+ }
1235
+ if (needsJoinTransform) {
1236
+ transformed = qualifyJoinColumns(ast) || transformed;
1237
+ }
1238
+ if (!transformed) {
1239
+ return { sql: query, transformed: false };
1240
+ }
1241
+ const transformedSql = parser.sqlify(ast, { database: "PostgreSQL" });
1242
+ return { sql: transformedSql, transformed: true };
1243
+ } catch {
1244
+ return { sql: query, transformed: false };
1245
+ }
1246
+ }
1247
+
1248
+ // src/dialect.ts
1718
1249
  class DuckDBDialect extends PgDialect {
1719
1250
  static [entityKind2] = "DuckDBPgDialect";
1720
1251
  hasPgJsonColumn = false;
@@ -1791,6 +1322,14 @@ class DuckDBDialect extends PgDialect {
1791
1322
  return "none";
1792
1323
  }
1793
1324
  }
1325
+ sqlToQuery(sqlObj, invokeSource) {
1326
+ const result = super.sqlToQuery(sqlObj, invokeSource);
1327
+ const transformed = transformSQL(result.sql);
1328
+ return {
1329
+ ...result,
1330
+ sql: transformed.sql
1331
+ };
1332
+ }
1794
1333
  }
1795
1334
 
1796
1335
  // src/select-builder.ts
@@ -1801,10 +1340,10 @@ import {
1801
1340
  } from "drizzle-orm/pg-core/query-builders";
1802
1341
  import { Subquery, ViewBaseConfig } from "drizzle-orm";
1803
1342
  import { PgViewBase } from "drizzle-orm/pg-core/view-base";
1804
- import { SQL as SQL4 } from "drizzle-orm/sql/sql";
1343
+ import { SQL as SQL5 } from "drizzle-orm/sql/sql";
1805
1344
 
1806
1345
  // src/sql/selection.ts
1807
- import { Column as Column2, SQL as SQL3, getTableName as getTableName2, is as is3, sql as sql3 } from "drizzle-orm";
1346
+ import { Column as Column2, SQL as SQL4, getTableName as getTableName2, is as is3, sql as sql3 } from "drizzle-orm";
1808
1347
  function mapEntries(obj, prefix, fullJoin = false) {
1809
1348
  return Object.fromEntries(Object.entries(obj).filter(([key]) => key !== "enableRLS").map(([key, value]) => {
1810
1349
  const qualified = prefix ? `${prefix}.${key}` : key;
@@ -1814,16 +1353,16 @@ function mapEntries(obj, prefix, fullJoin = false) {
1814
1353
  sql3`${value}`.mapWith(value).as(`${getTableName2(value.table)}.${value.name}`)
1815
1354
  ];
1816
1355
  }
1817
- if (fullJoin && is3(value, SQL3)) {
1356
+ if (fullJoin && is3(value, SQL4)) {
1818
1357
  const col = value.getSQL().queryChunks.find((chunk) => is3(chunk, Column2));
1819
1358
  const tableName = col?.table && getTableName2(col?.table);
1820
1359
  return [key, value.as(tableName ? `${tableName}.${key}` : key)];
1821
1360
  }
1822
- if (is3(value, SQL3) || is3(value, Column2)) {
1823
- const aliased = is3(value, SQL3) ? value : sql3`${value}`.mapWith(value);
1361
+ if (is3(value, SQL4) || is3(value, Column2)) {
1362
+ const aliased = is3(value, SQL4) ? value : sql3`${value}`.mapWith(value);
1824
1363
  return [key, aliased.as(qualified)];
1825
1364
  }
1826
- if (is3(value, SQL3.Aliased)) {
1365
+ if (is3(value, SQL4.Aliased)) {
1827
1366
  return [key, value];
1828
1367
  }
1829
1368
  if (typeof value === "object" && value !== null) {
@@ -1871,7 +1410,7 @@ class DuckDBSelectBuilder extends PgSelectBuilder {
1871
1410
  ]));
1872
1411
  } else if (is4(src, PgViewBase)) {
1873
1412
  fields = src[ViewBaseConfig]?.selectedFields;
1874
- } else if (is4(src, SQL4)) {
1413
+ } else if (is4(src, SQL5)) {
1875
1414
  fields = {};
1876
1415
  } else {
1877
1416
  fields = aliasFields(getTableColumns(src), !isPartialSelect);
@@ -2062,16 +1601,6 @@ function createDuckDBConnectionPool(instance, options = {}) {
2062
1601
  }
2063
1602
 
2064
1603
  // src/options.ts
2065
- var DEFAULT_REWRITE_ARRAYS_MODE = "auto";
2066
- function resolveRewriteArraysOption(value) {
2067
- if (value === undefined)
2068
- return DEFAULT_REWRITE_ARRAYS_MODE;
2069
- if (value === true)
2070
- return "auto";
2071
- if (value === false)
2072
- return "never";
2073
- return value;
2074
- }
2075
1604
  var DEFAULT_PREPARED_CACHE_SIZE = 32;
2076
1605
  function resolvePrepareCacheOption(option) {
2077
1606
  if (!option)
@@ -2101,7 +1630,6 @@ class DuckDBDriver {
2101
1630
  createSession(schema) {
2102
1631
  return new DuckDBSession(this.client, this.dialect, schema, {
2103
1632
  logger: this.options.logger,
2104
- rewriteArrays: this.options.rewriteArrays ?? "auto",
2105
1633
  rejectStringArrayLiterals: this.options.rejectStringArrayLiterals,
2106
1634
  prepareCache: this.options.prepareCache
2107
1635
  });
@@ -2116,7 +1644,6 @@ function isConfigObject(data) {
2116
1644
  }
2117
1645
  function createFromClient(client, config = {}, instance) {
2118
1646
  const dialect = new DuckDBDialect;
2119
- const rewriteArraysMode = resolveRewriteArraysOption(config.rewriteArrays);
2120
1647
  const prepareCache = resolvePrepareCacheOption(config.prepareCache);
2121
1648
  const logger = config.logger === true ? new DefaultLogger : config.logger || undefined;
2122
1649
  let schema;
@@ -2130,7 +1657,6 @@ function createFromClient(client, config = {}, instance) {
2130
1657
  }
2131
1658
  const driver = new DuckDBDriver(client, dialect, {
2132
1659
  logger,
2133
- rewriteArrays: rewriteArraysMode,
2134
1660
  rejectStringArrayLiterals: config.rejectStringArrayLiterals,
2135
1661
  prepareCache
2136
1662
  });
@@ -3090,7 +2616,7 @@ function renderImports(imports, importBasePath) {
3090
2616
  // src/olap.ts
3091
2617
  import { is as is5 } from "drizzle-orm/entity";
3092
2618
  import { sql as sql6 } from "drizzle-orm";
3093
- import { SQL as SQL5 } from "drizzle-orm/sql/sql";
2619
+ import { SQL as SQL6 } from "drizzle-orm/sql/sql";
3094
2620
  import { Column as Column3, getTableName as getTableName3 } from "drizzle-orm";
3095
2621
  var countN = (expr = sql6`*`) => sql6`count(${expr})`.mapWith(Number);
3096
2622
  var sumN = (expr) => sql6`sum(${expr})`.mapWith(Number);
@@ -3125,7 +2651,7 @@ var denseRank = (options) => sql6`dense_rank() ${overClause(options)}`.mapWith(N
3125
2651
  var lag = (expr, offset = 1, defaultValue, options) => defaultValue ? sql6`lag(${expr}, ${offset}, ${defaultValue}) ${overClause(options)}` : sql6`lag(${expr}, ${offset}) ${overClause(options)}`;
3126
2652
  var lead = (expr, offset = 1, defaultValue, options) => defaultValue ? sql6`lead(${expr}, ${offset}, ${defaultValue}) ${overClause(options)}` : sql6`lead(${expr}, ${offset}) ${overClause(options)}`;
3127
2653
  function keyAlias(key, fallback) {
3128
- if (is5(key, SQL5.Aliased)) {
2654
+ if (is5(key, SQL6.Aliased)) {
3129
2655
  return key.fieldAlias ?? fallback;
3130
2656
  }
3131
2657
  if (is5(key, Column3)) {
@@ -3196,6 +2722,17 @@ class OlapBuilder {
3196
2722
  }
3197
2723
  }
3198
2724
  var olap = (db) => new OlapBuilder(db);
2725
+ // src/operators.ts
2726
+ import { sql as sql7 } from "drizzle-orm";
2727
+ function arrayHasAll(column, values) {
2728
+ return sql7`array_has_all(${column}, ${values})`;
2729
+ }
2730
+ function arrayHasAny(column, values) {
2731
+ return sql7`array_has_any(${column}, ${values})`;
2732
+ }
2733
+ function arrayContainedBy(column, values) {
2734
+ return sql7`array_has_all(${values}, ${column})`;
2735
+ }
3199
2736
  export {
3200
2737
  wrapperToNodeApiValue,
3201
2738
  wrapTimestamp,
@@ -3210,7 +2747,6 @@ export {
3210
2747
  sumDistinctN,
3211
2748
  splitTopLevel,
3212
2749
  rowNumber,
3213
- resolveRewriteArraysOption,
3214
2750
  resolvePrepareCacheOption,
3215
2751
  resolvePoolSize,
3216
2752
  rank,
@@ -3257,6 +2793,9 @@ export {
3257
2793
  buildListLiteral,
3258
2794
  buildDefault,
3259
2795
  avgN,
2796
+ arrayHasAny,
2797
+ arrayHasAll,
2798
+ arrayContainedBy,
3260
2799
  anyValue,
3261
2800
  POOL_PRESETS,
3262
2801
  OlapBuilder,