@leonardovida-md/drizzle-neo-duckdb 1.1.4 → 1.2.1
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 +2 -3
- package/dist/dialect.d.ts +3 -1
- package/dist/driver.d.ts +1 -3
- package/dist/duckdb-introspect.mjs +552 -837
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +560 -832
- package/dist/operators.d.ts +8 -0
- package/dist/options.d.ts +0 -3
- package/dist/session.d.ts +2 -5
- package/dist/sql/ast-transformer.d.ts +31 -0
- package/dist/sql/visitors/array-operators.d.ts +5 -0
- package/dist/sql/visitors/column-qualifier.d.ts +10 -0
- package/dist/utils.d.ts +0 -1
- package/package.json +4 -3
- package/src/dialect.ts +20 -0
- package/src/driver.ts +0 -8
- package/src/index.ts +1 -0
- package/src/operators.ts +27 -0
- package/src/options.ts +0 -15
- package/src/session.ts +10 -96
- package/src/sql/ast-transformer.ts +144 -0
- package/src/sql/visitors/array-operators.ts +214 -0
- package/src/sql/visitors/column-qualifier.ts +565 -0
- package/src/utils.ts +0 -1
- package/dist/sql/query-rewriters.d.ts +0 -15
- package/src/sql/query-rewriters.ts +0 -1161
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST visitor to qualify unqualified column references in JOIN ON clauses.
|
|
3
|
+
*
|
|
4
|
+
* Performance optimizations:
|
|
5
|
+
* - Early exit when no unqualified columns found in ON clause
|
|
6
|
+
* - Skip processing if all columns are already qualified
|
|
7
|
+
* - Minimal tree traversal when possible
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
AST,
|
|
12
|
+
Binary,
|
|
13
|
+
ColumnRefItem,
|
|
14
|
+
ExpressionValue,
|
|
15
|
+
Select,
|
|
16
|
+
From,
|
|
17
|
+
Join,
|
|
18
|
+
OrderBy,
|
|
19
|
+
Column,
|
|
20
|
+
} from 'node-sql-parser';
|
|
21
|
+
|
|
22
|
+
type TableSource = {
|
|
23
|
+
name: string;
|
|
24
|
+
alias: string | null;
|
|
25
|
+
schema: string | null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type Qualifier = {
|
|
29
|
+
table: string;
|
|
30
|
+
schema: string | null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function getTableSource(from: From): TableSource | null {
|
|
34
|
+
if ('table' in from && from.table) {
|
|
35
|
+
return {
|
|
36
|
+
name: from.table,
|
|
37
|
+
alias: from.as ?? null,
|
|
38
|
+
schema: 'db' in from ? (from.db ?? null) : null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if ('expr' in from && from.as) {
|
|
42
|
+
return {
|
|
43
|
+
name: from.as,
|
|
44
|
+
alias: from.as,
|
|
45
|
+
schema: null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getQualifier(source: TableSource): Qualifier {
|
|
52
|
+
return {
|
|
53
|
+
table: source.alias ?? source.name,
|
|
54
|
+
schema: source.schema,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isUnqualifiedColumnRef(expr: ExpressionValue): expr is ColumnRefItem {
|
|
59
|
+
return (
|
|
60
|
+
typeof expr === 'object' &&
|
|
61
|
+
expr !== null &&
|
|
62
|
+
'type' in expr &&
|
|
63
|
+
expr.type === 'column_ref' &&
|
|
64
|
+
(!('table' in expr) || !expr.table)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isQualifiedColumnRef(expr: ExpressionValue): expr is ColumnRefItem {
|
|
69
|
+
return (
|
|
70
|
+
typeof expr === 'object' &&
|
|
71
|
+
expr !== null &&
|
|
72
|
+
'type' in expr &&
|
|
73
|
+
expr.type === 'column_ref' &&
|
|
74
|
+
'table' in expr &&
|
|
75
|
+
!!expr.table
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getColumnName(col: ColumnRefItem): string | null {
|
|
80
|
+
if (typeof col.column === 'string') {
|
|
81
|
+
return col.column;
|
|
82
|
+
}
|
|
83
|
+
if (col.column && 'expr' in col.column && col.column.expr?.value) {
|
|
84
|
+
return String(col.column.expr.value);
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function applyQualifier(col: ColumnRefItem, qualifier: Qualifier): void {
|
|
90
|
+
col.table = qualifier.table;
|
|
91
|
+
if (!('schema' in col) || !col.schema) {
|
|
92
|
+
(col as ColumnRefItem & { schema?: string | null }).schema =
|
|
93
|
+
qualifier.schema;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function unwrapColumnRef(
|
|
98
|
+
expr: ExpressionValue | undefined
|
|
99
|
+
): ColumnRefItem | null {
|
|
100
|
+
if (!expr || typeof expr !== 'object') return null;
|
|
101
|
+
if ('type' in expr && expr.type === 'column_ref') {
|
|
102
|
+
return expr as ColumnRefItem;
|
|
103
|
+
}
|
|
104
|
+
if ('expr' in expr && expr.expr) {
|
|
105
|
+
return unwrapColumnRef(expr.expr as ExpressionValue);
|
|
106
|
+
}
|
|
107
|
+
if ('ast' in expr && expr.ast && typeof expr.ast === 'object') {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if ('args' in expr && expr.args) {
|
|
111
|
+
const args = expr.args as {
|
|
112
|
+
value?: ExpressionValue[];
|
|
113
|
+
expr?: ExpressionValue;
|
|
114
|
+
};
|
|
115
|
+
if (args.expr) {
|
|
116
|
+
return unwrapColumnRef(args.expr as ExpressionValue);
|
|
117
|
+
}
|
|
118
|
+
if (args.value && args.value.length === 1) {
|
|
119
|
+
return unwrapColumnRef(args.value[0] as ExpressionValue);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isBinaryExpr(
|
|
126
|
+
expr: ExpressionValue | Binary | null | undefined
|
|
127
|
+
): expr is Binary {
|
|
128
|
+
return (
|
|
129
|
+
!!expr &&
|
|
130
|
+
typeof expr === 'object' &&
|
|
131
|
+
'type' in expr &&
|
|
132
|
+
(expr as { type?: string }).type === 'binary_expr'
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function walkOnClause(
|
|
137
|
+
expr: Binary | ExpressionValue | null | undefined,
|
|
138
|
+
leftQualifier: Qualifier,
|
|
139
|
+
rightQualifier: Qualifier,
|
|
140
|
+
ambiguousColumns: Set<string>
|
|
141
|
+
): boolean {
|
|
142
|
+
if (!expr || typeof expr !== 'object') return false;
|
|
143
|
+
|
|
144
|
+
let transformed = false;
|
|
145
|
+
|
|
146
|
+
if (isBinaryExpr(expr)) {
|
|
147
|
+
const left = expr.left as ExpressionValue;
|
|
148
|
+
const right = expr.right as ExpressionValue;
|
|
149
|
+
|
|
150
|
+
const leftCol = unwrapColumnRef(left);
|
|
151
|
+
const rightCol = unwrapColumnRef(right);
|
|
152
|
+
|
|
153
|
+
const leftUnqualified = leftCol ? isUnqualifiedColumnRef(leftCol) : false;
|
|
154
|
+
const rightUnqualified = rightCol
|
|
155
|
+
? isUnqualifiedColumnRef(rightCol)
|
|
156
|
+
: false;
|
|
157
|
+
const leftQualified = leftCol ? isQualifiedColumnRef(leftCol) : false;
|
|
158
|
+
const rightQualified = rightCol ? isQualifiedColumnRef(rightCol) : false;
|
|
159
|
+
const leftColName = leftCol ? getColumnName(leftCol) : null;
|
|
160
|
+
const rightColName = rightCol ? getColumnName(rightCol) : null;
|
|
161
|
+
|
|
162
|
+
if (
|
|
163
|
+
expr.operator === '=' &&
|
|
164
|
+
leftColName &&
|
|
165
|
+
rightColName &&
|
|
166
|
+
leftColName === rightColName
|
|
167
|
+
) {
|
|
168
|
+
if (leftUnqualified && rightUnqualified) {
|
|
169
|
+
applyQualifier(leftCol!, leftQualifier);
|
|
170
|
+
applyQualifier(rightCol!, rightQualifier);
|
|
171
|
+
ambiguousColumns.add(leftColName);
|
|
172
|
+
transformed = true;
|
|
173
|
+
} else if (leftQualified && rightUnqualified) {
|
|
174
|
+
applyQualifier(rightCol!, rightQualifier);
|
|
175
|
+
ambiguousColumns.add(rightColName);
|
|
176
|
+
transformed = true;
|
|
177
|
+
} else if (leftUnqualified && rightQualified) {
|
|
178
|
+
applyQualifier(leftCol!, leftQualifier);
|
|
179
|
+
ambiguousColumns.add(leftColName);
|
|
180
|
+
transformed = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
transformed =
|
|
185
|
+
walkOnClause(
|
|
186
|
+
isBinaryExpr(expr.left as Binary)
|
|
187
|
+
? (expr.left as Binary)
|
|
188
|
+
: (expr.left as ExpressionValue),
|
|
189
|
+
leftQualifier,
|
|
190
|
+
rightQualifier,
|
|
191
|
+
ambiguousColumns
|
|
192
|
+
) || transformed;
|
|
193
|
+
transformed =
|
|
194
|
+
walkOnClause(
|
|
195
|
+
isBinaryExpr(expr.right as Binary)
|
|
196
|
+
? (expr.right as Binary)
|
|
197
|
+
: (expr.right as ExpressionValue),
|
|
198
|
+
leftQualifier,
|
|
199
|
+
rightQualifier,
|
|
200
|
+
ambiguousColumns
|
|
201
|
+
) || transformed;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return transformed;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function qualifyAmbiguousInExpression(
|
|
208
|
+
expr: ExpressionValue | null | undefined,
|
|
209
|
+
defaultQualifier: Qualifier,
|
|
210
|
+
ambiguousColumns: Set<string>
|
|
211
|
+
): boolean {
|
|
212
|
+
if (!expr || typeof expr !== 'object') return false;
|
|
213
|
+
|
|
214
|
+
let transformed = false;
|
|
215
|
+
|
|
216
|
+
if (isUnqualifiedColumnRef(expr)) {
|
|
217
|
+
const colName = getColumnName(expr);
|
|
218
|
+
if (colName && ambiguousColumns.has(colName)) {
|
|
219
|
+
applyQualifier(expr, defaultQualifier);
|
|
220
|
+
transformed = true;
|
|
221
|
+
}
|
|
222
|
+
return transformed;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (isBinaryExpr(expr)) {
|
|
226
|
+
const binary = expr as Binary;
|
|
227
|
+
transformed =
|
|
228
|
+
qualifyAmbiguousInExpression(
|
|
229
|
+
binary.left as ExpressionValue,
|
|
230
|
+
defaultQualifier,
|
|
231
|
+
ambiguousColumns
|
|
232
|
+
) || transformed;
|
|
233
|
+
transformed =
|
|
234
|
+
qualifyAmbiguousInExpression(
|
|
235
|
+
binary.right as ExpressionValue,
|
|
236
|
+
defaultQualifier,
|
|
237
|
+
ambiguousColumns
|
|
238
|
+
) || transformed;
|
|
239
|
+
return transformed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if ('args' in expr && expr.args) {
|
|
243
|
+
const args = expr.args as {
|
|
244
|
+
value?: ExpressionValue[];
|
|
245
|
+
expr?: ExpressionValue;
|
|
246
|
+
};
|
|
247
|
+
if (args.value && Array.isArray(args.value)) {
|
|
248
|
+
for (const arg of args.value) {
|
|
249
|
+
transformed =
|
|
250
|
+
qualifyAmbiguousInExpression(
|
|
251
|
+
arg,
|
|
252
|
+
defaultQualifier,
|
|
253
|
+
ambiguousColumns
|
|
254
|
+
) || transformed;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (args.expr) {
|
|
258
|
+
transformed =
|
|
259
|
+
qualifyAmbiguousInExpression(
|
|
260
|
+
args.expr,
|
|
261
|
+
defaultQualifier,
|
|
262
|
+
ambiguousColumns
|
|
263
|
+
) || transformed;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if ('over' in expr && expr.over && typeof expr.over === 'object') {
|
|
268
|
+
const over = expr.over as {
|
|
269
|
+
partition?: ExpressionValue[];
|
|
270
|
+
orderby?: ExpressionValue[];
|
|
271
|
+
};
|
|
272
|
+
if (Array.isArray(over.partition)) {
|
|
273
|
+
for (const part of over.partition) {
|
|
274
|
+
transformed =
|
|
275
|
+
qualifyAmbiguousInExpression(
|
|
276
|
+
part,
|
|
277
|
+
defaultQualifier,
|
|
278
|
+
ambiguousColumns
|
|
279
|
+
) || transformed;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (Array.isArray(over.orderby)) {
|
|
283
|
+
for (const order of over.orderby) {
|
|
284
|
+
transformed =
|
|
285
|
+
qualifyAmbiguousInExpression(
|
|
286
|
+
order,
|
|
287
|
+
defaultQualifier,
|
|
288
|
+
ambiguousColumns
|
|
289
|
+
) || transformed;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return transformed;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Quick check if an ON clause has any unqualified column references.
|
|
299
|
+
* Used for early exit optimization.
|
|
300
|
+
*/
|
|
301
|
+
function hasUnqualifiedColumns(expr: Binary | null | undefined): boolean {
|
|
302
|
+
if (!expr || typeof expr !== 'object') return false;
|
|
303
|
+
|
|
304
|
+
if ('type' in expr && expr.type === 'binary_expr') {
|
|
305
|
+
const left = expr.left as ExpressionValue;
|
|
306
|
+
const right = expr.right as ExpressionValue;
|
|
307
|
+
const leftCol = unwrapColumnRef(left);
|
|
308
|
+
const rightCol = unwrapColumnRef(right);
|
|
309
|
+
if (
|
|
310
|
+
isUnqualifiedColumnRef(left) ||
|
|
311
|
+
isUnqualifiedColumnRef(right) ||
|
|
312
|
+
(leftCol && isUnqualifiedColumnRef(leftCol)) ||
|
|
313
|
+
(rightCol && isUnqualifiedColumnRef(rightCol))
|
|
314
|
+
) {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
if (
|
|
318
|
+
isBinaryExpr(expr.left as Binary) &&
|
|
319
|
+
hasUnqualifiedColumns(expr.left as Binary)
|
|
320
|
+
)
|
|
321
|
+
return true;
|
|
322
|
+
if (
|
|
323
|
+
isBinaryExpr(expr.right as Binary) &&
|
|
324
|
+
hasUnqualifiedColumns(expr.right as Binary)
|
|
325
|
+
)
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if ('args' in expr && expr.args) {
|
|
330
|
+
const args = expr.args as {
|
|
331
|
+
value?: ExpressionValue[];
|
|
332
|
+
expr?: ExpressionValue;
|
|
333
|
+
};
|
|
334
|
+
if (args.expr && isUnqualifiedColumnRef(args.expr as ExpressionValue))
|
|
335
|
+
return true;
|
|
336
|
+
if (args.value) {
|
|
337
|
+
for (const arg of args.value) {
|
|
338
|
+
if (isUnqualifiedColumnRef(arg)) return true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function walkSelect(select: Select): boolean {
|
|
347
|
+
let transformed = false;
|
|
348
|
+
const ambiguousColumns = new Set<string>();
|
|
349
|
+
|
|
350
|
+
if (Array.isArray(select.from) && select.from.length >= 2) {
|
|
351
|
+
const firstSource = getTableSource(select.from[0]);
|
|
352
|
+
const defaultQualifier = firstSource ? getQualifier(firstSource) : null;
|
|
353
|
+
let prevSource = firstSource;
|
|
354
|
+
|
|
355
|
+
let hasAnyUnqualified = false;
|
|
356
|
+
for (const from of select.from) {
|
|
357
|
+
if ('join' in from) {
|
|
358
|
+
const join = from as Join;
|
|
359
|
+
if (join.on && hasUnqualifiedColumns(join.on)) {
|
|
360
|
+
hasAnyUnqualified = true;
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (!hasAnyUnqualified) {
|
|
367
|
+
for (const from of select.from) {
|
|
368
|
+
if ('expr' in from && from.expr && 'ast' in from.expr) {
|
|
369
|
+
transformed = walkSelect(from.expr.ast) || transformed;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
for (const from of select.from) {
|
|
374
|
+
if ('join' in from) {
|
|
375
|
+
const join = from as Join;
|
|
376
|
+
const currentSource = getTableSource(join);
|
|
377
|
+
|
|
378
|
+
if (join.on && prevSource && currentSource) {
|
|
379
|
+
const leftQualifier = getQualifier(prevSource);
|
|
380
|
+
const rightQualifier = getQualifier(currentSource);
|
|
381
|
+
|
|
382
|
+
transformed =
|
|
383
|
+
walkOnClause(
|
|
384
|
+
join.on,
|
|
385
|
+
leftQualifier,
|
|
386
|
+
rightQualifier,
|
|
387
|
+
ambiguousColumns
|
|
388
|
+
) || transformed;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (join.using && prevSource && currentSource) {
|
|
392
|
+
for (const usingCol of join.using) {
|
|
393
|
+
if (typeof usingCol === 'string') {
|
|
394
|
+
ambiguousColumns.add(usingCol);
|
|
395
|
+
} else if ('value' in usingCol) {
|
|
396
|
+
ambiguousColumns.add(
|
|
397
|
+
String((usingCol as { value: unknown }).value)
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
prevSource = currentSource;
|
|
404
|
+
} else {
|
|
405
|
+
const source = getTableSource(from);
|
|
406
|
+
if (source) {
|
|
407
|
+
prevSource = source;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if ('expr' in from && from.expr && 'ast' in from.expr) {
|
|
412
|
+
transformed = walkSelect(from.expr.ast) || transformed;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (ambiguousColumns.size > 0 && defaultQualifier) {
|
|
417
|
+
if (Array.isArray(select.columns)) {
|
|
418
|
+
for (const col of select.columns as Column[]) {
|
|
419
|
+
if ('expr' in col) {
|
|
420
|
+
transformed =
|
|
421
|
+
qualifyAmbiguousInExpression(
|
|
422
|
+
col.expr,
|
|
423
|
+
defaultQualifier,
|
|
424
|
+
ambiguousColumns
|
|
425
|
+
) || transformed;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
transformed =
|
|
431
|
+
qualifyAmbiguousInExpression(
|
|
432
|
+
select.where,
|
|
433
|
+
defaultQualifier,
|
|
434
|
+
ambiguousColumns
|
|
435
|
+
) || transformed;
|
|
436
|
+
|
|
437
|
+
if (Array.isArray(select.orderby)) {
|
|
438
|
+
for (const order of select.orderby as OrderBy[]) {
|
|
439
|
+
if (order.expr) {
|
|
440
|
+
transformed =
|
|
441
|
+
qualifyAmbiguousInExpression(
|
|
442
|
+
order.expr,
|
|
443
|
+
defaultQualifier,
|
|
444
|
+
ambiguousColumns
|
|
445
|
+
) || transformed;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (select.with) {
|
|
454
|
+
for (const cte of select.with) {
|
|
455
|
+
const cteSelect = cte.stmt?.ast ?? cte.stmt;
|
|
456
|
+
if (cteSelect && cteSelect.type === 'select') {
|
|
457
|
+
transformed = walkSelect(cteSelect as Select) || transformed;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (select._next) {
|
|
463
|
+
transformed = walkSelect(select._next) || transformed;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return transformed;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export function qualifyJoinColumns(ast: AST | AST[]): boolean {
|
|
470
|
+
const statements = Array.isArray(ast) ? ast : [ast];
|
|
471
|
+
let transformed = false;
|
|
472
|
+
|
|
473
|
+
for (const stmt of statements) {
|
|
474
|
+
if (stmt.type === 'select') {
|
|
475
|
+
transformed = walkSelect(stmt as Select) || transformed;
|
|
476
|
+
} else if (stmt.type === 'insert') {
|
|
477
|
+
const insert = stmt as unknown as { values?: unknown };
|
|
478
|
+
if (
|
|
479
|
+
insert.values &&
|
|
480
|
+
typeof insert.values === 'object' &&
|
|
481
|
+
'type' in insert.values &&
|
|
482
|
+
(insert.values as { type: string }).type === 'select'
|
|
483
|
+
) {
|
|
484
|
+
transformed =
|
|
485
|
+
walkSelect(insert.values as unknown as Select) || transformed;
|
|
486
|
+
}
|
|
487
|
+
} else if (stmt.type === 'update') {
|
|
488
|
+
const update = stmt as unknown as {
|
|
489
|
+
table?: From[];
|
|
490
|
+
from?: From[];
|
|
491
|
+
where?: ExpressionValue;
|
|
492
|
+
returning?: ExpressionValue | ExpressionValue[];
|
|
493
|
+
};
|
|
494
|
+
const mainSource = update.table?.[0]
|
|
495
|
+
? getTableSource(update.table[0] as From)
|
|
496
|
+
: null;
|
|
497
|
+
const defaultQualifier = mainSource ? getQualifier(mainSource) : null;
|
|
498
|
+
const fromSources = update.from ?? [];
|
|
499
|
+
const firstFrom = fromSources[0] ? getTableSource(fromSources[0]) : null;
|
|
500
|
+
if (update.where && defaultQualifier && firstFrom) {
|
|
501
|
+
const ambiguous = new Set<string>();
|
|
502
|
+
transformed =
|
|
503
|
+
walkOnClause(
|
|
504
|
+
update.where as Binary,
|
|
505
|
+
defaultQualifier,
|
|
506
|
+
getQualifier(firstFrom),
|
|
507
|
+
ambiguous
|
|
508
|
+
) || transformed;
|
|
509
|
+
transformed =
|
|
510
|
+
qualifyAmbiguousInExpression(
|
|
511
|
+
update.where,
|
|
512
|
+
defaultQualifier,
|
|
513
|
+
ambiguous
|
|
514
|
+
) || transformed;
|
|
515
|
+
}
|
|
516
|
+
if (Array.isArray(update.returning) && defaultQualifier) {
|
|
517
|
+
for (const ret of update.returning) {
|
|
518
|
+
transformed =
|
|
519
|
+
qualifyAmbiguousInExpression(
|
|
520
|
+
ret,
|
|
521
|
+
defaultQualifier,
|
|
522
|
+
new Set<string>()
|
|
523
|
+
) || transformed;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} else if (stmt.type === 'delete') {
|
|
527
|
+
const del = stmt as unknown as {
|
|
528
|
+
table?: From[];
|
|
529
|
+
from?: From[];
|
|
530
|
+
where?: ExpressionValue;
|
|
531
|
+
};
|
|
532
|
+
const mainSource = del.table?.[0]
|
|
533
|
+
? getTableSource(del.table[0] as From)
|
|
534
|
+
: null;
|
|
535
|
+
const defaultQualifier = mainSource ? getQualifier(mainSource) : null;
|
|
536
|
+
const fromSources = del.from ?? [];
|
|
537
|
+
const firstFrom = fromSources[0] ? getTableSource(fromSources[0]) : null;
|
|
538
|
+
if (del.where && defaultQualifier && firstFrom) {
|
|
539
|
+
const ambiguous = new Set<string>();
|
|
540
|
+
transformed =
|
|
541
|
+
walkOnClause(
|
|
542
|
+
del.where as Binary,
|
|
543
|
+
defaultQualifier,
|
|
544
|
+
getQualifier(firstFrom),
|
|
545
|
+
ambiguous
|
|
546
|
+
) || transformed;
|
|
547
|
+
transformed =
|
|
548
|
+
qualifyAmbiguousInExpression(
|
|
549
|
+
del.where,
|
|
550
|
+
defaultQualifier,
|
|
551
|
+
ambiguous
|
|
552
|
+
) || transformed;
|
|
553
|
+
} else if (del.where && defaultQualifier) {
|
|
554
|
+
transformed =
|
|
555
|
+
qualifyAmbiguousInExpression(
|
|
556
|
+
del.where,
|
|
557
|
+
defaultQualifier,
|
|
558
|
+
new Set<string>()
|
|
559
|
+
) || transformed;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return transformed;
|
|
565
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare function scrubForRewrite(query: string): string;
|
|
2
|
-
export declare function adaptArrayOperators(query: string): string;
|
|
3
|
-
/**
|
|
4
|
-
* Qualifies unqualified column references in JOIN ON clauses, SELECT, WHERE,
|
|
5
|
-
* and ORDER BY clauses.
|
|
6
|
-
*
|
|
7
|
-
* Transforms patterns like:
|
|
8
|
-
* `select "col" from "a" left join "b" on "col" = "col" where "col" in (...)`
|
|
9
|
-
* To:
|
|
10
|
-
* `select "a"."col" from "a" left join "b" on "a"."col" = "b"."col" where "a"."col" in (...)`
|
|
11
|
-
*
|
|
12
|
-
* This fixes the issue where drizzle-orm generates unqualified column
|
|
13
|
-
* references when joining CTEs with eq().
|
|
14
|
-
*/
|
|
15
|
-
export declare function qualifyJoinColumns(query: string): string;
|