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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@
4
4
  import { DuckDBInstance as DuckDBInstance3 } from "@duckdb/node-api";
5
5
  import { mkdir, writeFile } from "node:fs/promises";
6
6
  import path from "node:path";
7
- import process from "node:process";
7
+ import process2 from "node:process";
8
8
 
9
9
  // src/driver.ts
10
10
  import { DuckDBInstance as DuckDBInstance2 } from "@duckdb/node-api";
@@ -1014,22 +1014,30 @@ function getTableSource(from) {
1014
1014
  if ("table" in from && from.table) {
1015
1015
  return {
1016
1016
  name: from.table,
1017
- alias: from.as ?? null
1017
+ alias: from.as ?? null,
1018
+ schema: "db" in from ? from.db ?? null : null
1018
1019
  };
1019
1020
  }
1020
1021
  if ("expr" in from && from.as) {
1021
1022
  return {
1022
1023
  name: from.as,
1023
- alias: from.as
1024
+ alias: from.as,
1025
+ schema: null
1024
1026
  };
1025
1027
  }
1026
1028
  return null;
1027
1029
  }
1028
1030
  function getQualifier(source) {
1029
- return source.alias ?? source.name;
1031
+ return {
1032
+ table: source.alias ?? source.name,
1033
+ schema: source.schema
1034
+ };
1030
1035
  }
1031
1036
  function isUnqualifiedColumnRef(expr) {
1032
- return typeof expr === "object" && expr !== null && "type" in expr && expr.type === "column_ref" && !(("table" in expr) && expr.table);
1037
+ return typeof expr === "object" && expr !== null && "type" in expr && expr.type === "column_ref" && (!("table" in expr) || !expr.table);
1038
+ }
1039
+ function isQualifiedColumnRef(expr) {
1040
+ return typeof expr === "object" && expr !== null && "type" in expr && expr.type === "column_ref" && "table" in expr && !!expr.table;
1033
1041
  }
1034
1042
  function getColumnName(col) {
1035
1043
  if (typeof col.column === "string") {
@@ -1040,29 +1048,80 @@ function getColumnName(col) {
1040
1048
  }
1041
1049
  return null;
1042
1050
  }
1043
- function walkOnClause(expr, leftSource, rightSource, ambiguousColumns) {
1051
+ function applyQualifier(col, qualifier) {
1052
+ col.table = qualifier.table;
1053
+ if (!("schema" in col) || !col.schema) {
1054
+ col.schema = qualifier.schema;
1055
+ }
1056
+ }
1057
+ function unwrapColumnRef(expr) {
1058
+ if (!expr || typeof expr !== "object")
1059
+ return null;
1060
+ if ("type" in expr && expr.type === "column_ref") {
1061
+ return expr;
1062
+ }
1063
+ if ("expr" in expr && expr.expr) {
1064
+ return unwrapColumnRef(expr.expr);
1065
+ }
1066
+ if ("ast" in expr && expr.ast && typeof expr.ast === "object") {
1067
+ return null;
1068
+ }
1069
+ if ("args" in expr && expr.args) {
1070
+ const args = expr.args;
1071
+ if (args.expr) {
1072
+ return unwrapColumnRef(args.expr);
1073
+ }
1074
+ if (args.value && args.value.length === 1) {
1075
+ return unwrapColumnRef(args.value[0]);
1076
+ }
1077
+ }
1078
+ return null;
1079
+ }
1080
+ function isBinaryExpr(expr) {
1081
+ return !!expr && typeof expr === "object" && "type" in expr && expr.type === "binary_expr";
1082
+ }
1083
+ function walkOnClause(expr, leftQualifier, rightQualifier, ambiguousColumns) {
1044
1084
  if (!expr || typeof expr !== "object")
1045
1085
  return false;
1046
1086
  let transformed = false;
1047
- if (expr.type === "binary_expr") {
1048
- if (expr.operator === "=") {
1049
- const left = expr.left;
1050
- const right = expr.right;
1051
- if (isUnqualifiedColumnRef(left) && isUnqualifiedColumnRef(right)) {
1052
- const leftColName = getColumnName(left);
1053
- const rightColName = getColumnName(right);
1054
- if (leftColName && rightColName && leftColName === rightColName) {
1055
- left.table = leftSource;
1056
- right.table = rightSource;
1057
- ambiguousColumns.add(leftColName);
1058
- transformed = true;
1059
- }
1087
+ if (isBinaryExpr(expr)) {
1088
+ const left = expr.left;
1089
+ const right = expr.right;
1090
+ const leftCol = unwrapColumnRef(left);
1091
+ const rightCol = unwrapColumnRef(right);
1092
+ const leftUnqualified = leftCol ? isUnqualifiedColumnRef(leftCol) : false;
1093
+ const rightUnqualified = rightCol ? isUnqualifiedColumnRef(rightCol) : false;
1094
+ const leftQualified = leftCol ? isQualifiedColumnRef(leftCol) : false;
1095
+ const rightQualified = rightCol ? isQualifiedColumnRef(rightCol) : false;
1096
+ const leftColName = leftCol ? getColumnName(leftCol) : null;
1097
+ const rightColName = rightCol ? getColumnName(rightCol) : null;
1098
+ if (expr.operator === "=" && leftColName && rightColName && leftColName === rightColName) {
1099
+ if (leftUnqualified && rightUnqualified) {
1100
+ applyQualifier(leftCol, leftQualifier);
1101
+ applyQualifier(rightCol, rightQualifier);
1102
+ ambiguousColumns.add(leftColName);
1103
+ transformed = true;
1104
+ } else if (leftQualified && rightUnqualified) {
1105
+ applyQualifier(rightCol, rightQualifier);
1106
+ ambiguousColumns.add(rightColName);
1107
+ transformed = true;
1108
+ } else if (leftUnqualified && rightQualified) {
1109
+ applyQualifier(leftCol, leftQualifier);
1110
+ ambiguousColumns.add(leftColName);
1111
+ transformed = true;
1060
1112
  }
1061
1113
  }
1062
- if (expr.operator === "AND" || expr.operator === "OR") {
1063
- transformed = walkOnClause(expr.left, leftSource, rightSource, ambiguousColumns) || transformed;
1064
- transformed = walkOnClause(expr.right, leftSource, rightSource, ambiguousColumns) || transformed;
1114
+ if (expr.operator === "=" && leftCol && rightCol && leftColName && rightColName && leftColName !== rightColName) {
1115
+ if (leftQualified && rightUnqualified && !rightColName.includes(".")) {
1116
+ applyQualifier(rightCol, rightQualifier);
1117
+ transformed = true;
1118
+ } else if (leftUnqualified && rightQualified && !leftColName.includes(".")) {
1119
+ applyQualifier(leftCol, leftQualifier);
1120
+ transformed = true;
1121
+ }
1065
1122
  }
1123
+ transformed = walkOnClause(isBinaryExpr(expr.left) ? expr.left : expr.left, leftQualifier, rightQualifier, ambiguousColumns) || transformed;
1124
+ transformed = walkOnClause(isBinaryExpr(expr.right) ? expr.right : expr.right, leftQualifier, rightQualifier, ambiguousColumns) || transformed;
1066
1125
  }
1067
1126
  return transformed;
1068
1127
  }
@@ -1073,12 +1132,12 @@ function qualifyAmbiguousInExpression(expr, defaultQualifier, ambiguousColumns)
1073
1132
  if (isUnqualifiedColumnRef(expr)) {
1074
1133
  const colName = getColumnName(expr);
1075
1134
  if (colName && ambiguousColumns.has(colName)) {
1076
- expr.table = defaultQualifier;
1135
+ applyQualifier(expr, defaultQualifier);
1077
1136
  transformed = true;
1078
1137
  }
1079
1138
  return transformed;
1080
1139
  }
1081
- if ("type" in expr && expr.type === "binary_expr") {
1140
+ if (isBinaryExpr(expr)) {
1082
1141
  const binary = expr;
1083
1142
  transformed = qualifyAmbiguousInExpression(binary.left, defaultQualifier, ambiguousColumns) || transformed;
1084
1143
  transformed = qualifyAmbiguousInExpression(binary.right, defaultQualifier, ambiguousColumns) || transformed;
@@ -1095,48 +1154,117 @@ function qualifyAmbiguousInExpression(expr, defaultQualifier, ambiguousColumns)
1095
1154
  transformed = qualifyAmbiguousInExpression(args.expr, defaultQualifier, ambiguousColumns) || transformed;
1096
1155
  }
1097
1156
  }
1157
+ if ("over" in expr && expr.over && typeof expr.over === "object") {
1158
+ const over = expr.over;
1159
+ if (Array.isArray(over.partition)) {
1160
+ for (const part of over.partition) {
1161
+ transformed = qualifyAmbiguousInExpression(part, defaultQualifier, ambiguousColumns) || transformed;
1162
+ }
1163
+ }
1164
+ if (Array.isArray(over.orderby)) {
1165
+ for (const order of over.orderby) {
1166
+ transformed = qualifyAmbiguousInExpression(order, defaultQualifier, ambiguousColumns) || transformed;
1167
+ }
1168
+ }
1169
+ }
1098
1170
  return transformed;
1099
1171
  }
1172
+ function hasUnqualifiedColumns(expr) {
1173
+ if (!expr || typeof expr !== "object")
1174
+ return false;
1175
+ if ("type" in expr && expr.type === "binary_expr") {
1176
+ const left = expr.left;
1177
+ const right = expr.right;
1178
+ const leftCol = unwrapColumnRef(left);
1179
+ const rightCol = unwrapColumnRef(right);
1180
+ if (isUnqualifiedColumnRef(left) || isUnqualifiedColumnRef(right) || leftCol && isUnqualifiedColumnRef(leftCol) || rightCol && isUnqualifiedColumnRef(rightCol)) {
1181
+ return true;
1182
+ }
1183
+ if (isBinaryExpr(expr.left) && hasUnqualifiedColumns(expr.left))
1184
+ return true;
1185
+ if (isBinaryExpr(expr.right) && hasUnqualifiedColumns(expr.right))
1186
+ return true;
1187
+ }
1188
+ if ("args" in expr && expr.args) {
1189
+ const args = expr.args;
1190
+ if (args.expr && isUnqualifiedColumnRef(args.expr))
1191
+ return true;
1192
+ if (args.value) {
1193
+ for (const arg of args.value) {
1194
+ if (isUnqualifiedColumnRef(arg))
1195
+ return true;
1196
+ }
1197
+ }
1198
+ }
1199
+ return false;
1200
+ }
1100
1201
  function walkSelect(select) {
1101
1202
  let transformed = false;
1102
1203
  const ambiguousColumns = new Set;
1103
1204
  if (Array.isArray(select.from) && select.from.length >= 2) {
1104
1205
  const firstSource = getTableSource(select.from[0]);
1105
- const defaultQualifier = firstSource ? getQualifier(firstSource) : "";
1206
+ const defaultQualifier = firstSource ? getQualifier(firstSource) : null;
1106
1207
  let prevSource = firstSource;
1208
+ let hasAnyUnqualified = false;
1107
1209
  for (const from of select.from) {
1108
1210
  if ("join" in from) {
1109
1211
  const join = from;
1110
- const currentSource = getTableSource(join);
1111
- if (join.on && prevSource && currentSource) {
1112
- const leftQualifier = getQualifier(prevSource);
1113
- const rightQualifier = getQualifier(currentSource);
1114
- transformed = walkOnClause(join.on, leftQualifier, rightQualifier, ambiguousColumns) || transformed;
1115
- }
1116
- prevSource = currentSource;
1117
- } else {
1118
- const source = getTableSource(from);
1119
- if (source) {
1120
- prevSource = source;
1212
+ if (join.on && hasUnqualifiedColumns(join.on)) {
1213
+ hasAnyUnqualified = true;
1214
+ break;
1121
1215
  }
1122
1216
  }
1123
- if ("expr" in from && from.expr && "ast" in from.expr) {
1124
- transformed = walkSelect(from.expr.ast) || transformed;
1125
- }
1126
1217
  }
1127
- if (ambiguousColumns.size > 0 && defaultQualifier) {
1128
- if (Array.isArray(select.columns)) {
1129
- for (const col of select.columns) {
1130
- if ("expr" in col) {
1131
- transformed = qualifyAmbiguousInExpression(col.expr, defaultQualifier, ambiguousColumns) || transformed;
1218
+ if (!hasAnyUnqualified) {
1219
+ for (const from of select.from) {
1220
+ if ("expr" in from && from.expr && "ast" in from.expr) {
1221
+ transformed = walkSelect(from.expr.ast) || transformed;
1222
+ }
1223
+ }
1224
+ } else {
1225
+ for (const from of select.from) {
1226
+ if ("join" in from) {
1227
+ const join = from;
1228
+ const currentSource = getTableSource(join);
1229
+ if (join.on && prevSource && currentSource) {
1230
+ const leftQualifier = getQualifier(prevSource);
1231
+ const rightQualifier = getQualifier(currentSource);
1232
+ transformed = walkOnClause(join.on, leftQualifier, rightQualifier, ambiguousColumns) || transformed;
1233
+ }
1234
+ if (join.using && prevSource && currentSource) {
1235
+ for (const usingCol of join.using) {
1236
+ if (typeof usingCol === "string") {
1237
+ ambiguousColumns.add(usingCol);
1238
+ } else if ("value" in usingCol) {
1239
+ ambiguousColumns.add(String(usingCol.value));
1240
+ }
1241
+ }
1242
+ }
1243
+ prevSource = currentSource;
1244
+ } else {
1245
+ const source = getTableSource(from);
1246
+ if (source) {
1247
+ prevSource = source;
1132
1248
  }
1133
1249
  }
1250
+ if ("expr" in from && from.expr && "ast" in from.expr) {
1251
+ transformed = walkSelect(from.expr.ast) || transformed;
1252
+ }
1134
1253
  }
1135
- transformed = qualifyAmbiguousInExpression(select.where, defaultQualifier, ambiguousColumns) || transformed;
1136
- if (Array.isArray(select.orderby)) {
1137
- for (const order of select.orderby) {
1138
- if (order.expr) {
1139
- transformed = qualifyAmbiguousInExpression(order.expr, defaultQualifier, ambiguousColumns) || transformed;
1254
+ if (ambiguousColumns.size > 0 && defaultQualifier) {
1255
+ if (Array.isArray(select.columns)) {
1256
+ for (const col of select.columns) {
1257
+ if ("expr" in col) {
1258
+ transformed = qualifyAmbiguousInExpression(col.expr, defaultQualifier, ambiguousColumns) || transformed;
1259
+ }
1260
+ }
1261
+ }
1262
+ transformed = qualifyAmbiguousInExpression(select.where, defaultQualifier, ambiguousColumns) || transformed;
1263
+ if (Array.isArray(select.orderby)) {
1264
+ for (const order of select.orderby) {
1265
+ if (order.expr) {
1266
+ transformed = qualifyAmbiguousInExpression(order.expr, defaultQualifier, ambiguousColumns) || transformed;
1267
+ }
1140
1268
  }
1141
1269
  }
1142
1270
  }
@@ -1161,6 +1289,323 @@ function qualifyJoinColumns(ast) {
1161
1289
  for (const stmt of statements) {
1162
1290
  if (stmt.type === "select") {
1163
1291
  transformed = walkSelect(stmt) || transformed;
1292
+ } else if (stmt.type === "insert") {
1293
+ const insert = stmt;
1294
+ if (insert.values && typeof insert.values === "object" && "type" in insert.values && insert.values.type === "select") {
1295
+ transformed = walkSelect(insert.values) || transformed;
1296
+ }
1297
+ } else if (stmt.type === "update") {
1298
+ const update = stmt;
1299
+ const mainSource = update.table?.[0] ? getTableSource(update.table[0]) : null;
1300
+ const defaultQualifier = mainSource ? getQualifier(mainSource) : null;
1301
+ const fromSources = update.from ?? [];
1302
+ const firstFrom = fromSources[0] ? getTableSource(fromSources[0]) : null;
1303
+ if (update.where && defaultQualifier && firstFrom) {
1304
+ const ambiguous = new Set;
1305
+ transformed = walkOnClause(update.where, defaultQualifier, getQualifier(firstFrom), ambiguous) || transformed;
1306
+ transformed = qualifyAmbiguousInExpression(update.where, defaultQualifier, ambiguous) || transformed;
1307
+ }
1308
+ if (Array.isArray(update.returning) && defaultQualifier) {
1309
+ for (const ret of update.returning) {
1310
+ transformed = qualifyAmbiguousInExpression(ret, defaultQualifier, new Set) || transformed;
1311
+ }
1312
+ }
1313
+ } else if (stmt.type === "delete") {
1314
+ const del = stmt;
1315
+ const mainSource = del.table?.[0] ? getTableSource(del.table[0]) : null;
1316
+ const defaultQualifier = mainSource ? getQualifier(mainSource) : null;
1317
+ const fromSources = del.from ?? [];
1318
+ const firstFrom = fromSources[0] ? getTableSource(fromSources[0]) : null;
1319
+ if (del.where && defaultQualifier && firstFrom) {
1320
+ const ambiguous = new Set;
1321
+ transformed = walkOnClause(del.where, defaultQualifier, getQualifier(firstFrom), ambiguous) || transformed;
1322
+ transformed = qualifyAmbiguousInExpression(del.where, defaultQualifier, ambiguous) || transformed;
1323
+ } else if (del.where && defaultQualifier) {
1324
+ transformed = qualifyAmbiguousInExpression(del.where, defaultQualifier, new Set) || transformed;
1325
+ }
1326
+ }
1327
+ }
1328
+ return transformed;
1329
+ }
1330
+
1331
+ // src/sql/visitors/generate-series-alias.ts
1332
+ function getColumnName2(col) {
1333
+ if (typeof col.column === "string") {
1334
+ return col.column;
1335
+ }
1336
+ if (col.column && "expr" in col.column && col.column.expr?.value) {
1337
+ return String(col.column.expr.value);
1338
+ }
1339
+ return null;
1340
+ }
1341
+ function isColumnRef(expr) {
1342
+ return typeof expr === "object" && expr !== null && "type" in expr && expr.type === "column_ref";
1343
+ }
1344
+ function isBinaryExpr2(expr) {
1345
+ return !!expr && typeof expr === "object" && "type" in expr && expr.type === "binary_expr";
1346
+ }
1347
+ function getGenerateSeriesAliases(from) {
1348
+ const aliases = new Set;
1349
+ if (!from || !Array.isArray(from))
1350
+ return aliases;
1351
+ for (const f of from) {
1352
+ if ("expr" in f && f.expr && typeof f.expr === "object") {
1353
+ const exprObj = f.expr;
1354
+ if (exprObj.type === "function" && "name" in exprObj) {
1355
+ const nameObj = exprObj.name;
1356
+ const nameParts = nameObj?.name;
1357
+ const fnName = nameParts?.[0]?.value;
1358
+ if (typeof fnName === "string" && fnName.toLowerCase() === "generate_series") {
1359
+ const alias = typeof f.as === "string" ? f.as : null;
1360
+ if (alias && !alias.includes("(")) {
1361
+ aliases.add(alias);
1362
+ }
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+ return aliases;
1368
+ }
1369
+ function rewriteAliasColumnRef(col, alias) {
1370
+ col.table = alias;
1371
+ col.column = { expr: { type: "default", value: "generate_series" } };
1372
+ }
1373
+ function walkExpression2(expr, aliases) {
1374
+ if (!expr || typeof expr !== "object")
1375
+ return false;
1376
+ let transformed = false;
1377
+ const exprObj = expr;
1378
+ if (isColumnRef(expr)) {
1379
+ if (!("table" in expr) || !expr.table) {
1380
+ const colName = getColumnName2(expr);
1381
+ if (colName && aliases.has(colName)) {
1382
+ rewriteAliasColumnRef(expr, colName);
1383
+ transformed = true;
1384
+ }
1385
+ }
1386
+ return transformed;
1387
+ }
1388
+ if (isBinaryExpr2(expr)) {
1389
+ const binary = expr;
1390
+ transformed = walkExpression2(binary.left, aliases) || transformed;
1391
+ transformed = walkExpression2(binary.right, aliases) || transformed;
1392
+ return transformed;
1393
+ }
1394
+ if (exprObj.type === "unary_expr" && exprObj.expr) {
1395
+ transformed = walkExpression2(exprObj.expr, aliases) || transformed;
1396
+ }
1397
+ if (exprObj.type === "cast" && exprObj.expr) {
1398
+ transformed = walkExpression2(exprObj.expr, aliases) || transformed;
1399
+ }
1400
+ if (exprObj.type === "case") {
1401
+ if (exprObj.expr) {
1402
+ transformed = walkExpression2(exprObj.expr, aliases) || transformed;
1403
+ }
1404
+ if (Array.isArray(exprObj.args)) {
1405
+ for (const whenClause of exprObj.args) {
1406
+ if (whenClause.cond) {
1407
+ transformed = walkExpression2(whenClause.cond, aliases) || transformed;
1408
+ }
1409
+ if (whenClause.result) {
1410
+ transformed = walkExpression2(whenClause.result, aliases) || transformed;
1411
+ }
1412
+ }
1413
+ }
1414
+ }
1415
+ if ("args" in exprObj && exprObj.args) {
1416
+ const args = exprObj.args;
1417
+ if (Array.isArray(args.value)) {
1418
+ for (const arg of args.value) {
1419
+ transformed = walkExpression2(arg, aliases) || transformed;
1420
+ }
1421
+ } else if (args.expr) {
1422
+ transformed = walkExpression2(args.expr, aliases) || transformed;
1423
+ }
1424
+ }
1425
+ if ("over" in exprObj && exprObj.over && typeof exprObj.over === "object") {
1426
+ const over = exprObj.over;
1427
+ if (Array.isArray(over.partition)) {
1428
+ for (const part of over.partition) {
1429
+ transformed = walkExpression2(part, aliases) || transformed;
1430
+ }
1431
+ }
1432
+ if (Array.isArray(over.orderby)) {
1433
+ for (const order of over.orderby) {
1434
+ transformed = walkExpression2(order, aliases) || transformed;
1435
+ }
1436
+ }
1437
+ }
1438
+ if ("ast" in exprObj && exprObj.ast) {
1439
+ const subAst = exprObj.ast;
1440
+ if (subAst.type === "select") {
1441
+ transformed = walkSelect2(subAst) || transformed;
1442
+ }
1443
+ }
1444
+ if (exprObj.type === "expr_list" && Array.isArray(exprObj.value)) {
1445
+ for (const item of exprObj.value) {
1446
+ transformed = walkExpression2(item, aliases) || transformed;
1447
+ }
1448
+ }
1449
+ return transformed;
1450
+ }
1451
+ function walkFrom2(from, aliases) {
1452
+ if (!from || !Array.isArray(from))
1453
+ return false;
1454
+ let transformed = false;
1455
+ for (const f of from) {
1456
+ if ("join" in f) {
1457
+ const join = f;
1458
+ transformed = walkExpression2(join.on, aliases) || transformed;
1459
+ }
1460
+ if ("expr" in f && f.expr && "ast" in f.expr) {
1461
+ transformed = walkSelect2(f.expr.ast) || transformed;
1462
+ }
1463
+ }
1464
+ return transformed;
1465
+ }
1466
+ function walkSelect2(select) {
1467
+ let transformed = false;
1468
+ const aliases = getGenerateSeriesAliases(select.from);
1469
+ if (select.with) {
1470
+ for (const cte of select.with) {
1471
+ const cteSelect = cte.stmt?.ast ?? cte.stmt;
1472
+ if (cteSelect && cteSelect.type === "select") {
1473
+ transformed = walkSelect2(cteSelect) || transformed;
1474
+ }
1475
+ }
1476
+ }
1477
+ transformed = walkFrom2(select.from, aliases) || transformed;
1478
+ transformed = walkExpression2(select.where, aliases) || transformed;
1479
+ if (select.having) {
1480
+ if (Array.isArray(select.having)) {
1481
+ for (const h of select.having) {
1482
+ transformed = walkExpression2(h, aliases) || transformed;
1483
+ }
1484
+ } else {
1485
+ transformed = walkExpression2(select.having, aliases) || transformed;
1486
+ }
1487
+ }
1488
+ if (Array.isArray(select.columns)) {
1489
+ for (const col of select.columns) {
1490
+ if ("expr" in col) {
1491
+ transformed = walkExpression2(col.expr, aliases) || transformed;
1492
+ }
1493
+ }
1494
+ }
1495
+ if (Array.isArray(select.groupby)) {
1496
+ for (const g of select.groupby) {
1497
+ transformed = walkExpression2(g, aliases) || transformed;
1498
+ }
1499
+ }
1500
+ if (Array.isArray(select.orderby)) {
1501
+ for (const order of select.orderby) {
1502
+ if (order.expr) {
1503
+ transformed = walkExpression2(order.expr, aliases) || transformed;
1504
+ }
1505
+ }
1506
+ }
1507
+ if (select._orderby) {
1508
+ for (const order of select._orderby) {
1509
+ if (order.expr) {
1510
+ transformed = walkExpression2(order.expr, aliases) || transformed;
1511
+ }
1512
+ }
1513
+ }
1514
+ if (select._next) {
1515
+ transformed = walkSelect2(select._next) || transformed;
1516
+ }
1517
+ return transformed;
1518
+ }
1519
+ function rewriteGenerateSeriesAliases(ast) {
1520
+ const statements = Array.isArray(ast) ? ast : [ast];
1521
+ let transformed = false;
1522
+ for (const stmt of statements) {
1523
+ if (stmt.type === "select") {
1524
+ transformed = walkSelect2(stmt) || transformed;
1525
+ }
1526
+ }
1527
+ return transformed;
1528
+ }
1529
+
1530
+ // src/sql/visitors/union-with-hoister.ts
1531
+ function getCteName(cte) {
1532
+ const nameObj = cte.name;
1533
+ if (!nameObj)
1534
+ return null;
1535
+ const value = nameObj.value;
1536
+ if (typeof value === "string")
1537
+ return value;
1538
+ return null;
1539
+ }
1540
+ function hoistWithInSelect(select) {
1541
+ if (!select.set_op || !select._next)
1542
+ return false;
1543
+ const arms = [];
1544
+ let current = select;
1545
+ while (current && current.type === "select") {
1546
+ arms.push(current);
1547
+ current = current._next;
1548
+ }
1549
+ const mergedWith = [];
1550
+ const seen = new Set;
1551
+ let hasWithBeyondFirst = false;
1552
+ for (const arm of arms) {
1553
+ if (arm.with && arm.with.length > 0) {
1554
+ if (arm !== arms[0]) {
1555
+ hasWithBeyondFirst = true;
1556
+ }
1557
+ for (const cte of arm.with) {
1558
+ const cteName = getCteName(cte);
1559
+ if (!cteName)
1560
+ return false;
1561
+ if (seen.has(cteName)) {
1562
+ return false;
1563
+ }
1564
+ seen.add(cteName);
1565
+ mergedWith.push(cte);
1566
+ }
1567
+ }
1568
+ }
1569
+ if (!hasWithBeyondFirst)
1570
+ return false;
1571
+ arms[0].with = mergedWith;
1572
+ if ("parentheses_symbol" in arms[0]) {
1573
+ arms[0].parentheses_symbol = false;
1574
+ }
1575
+ for (let i = 1;i < arms.length; i++) {
1576
+ arms[i].with = null;
1577
+ }
1578
+ return true;
1579
+ }
1580
+ function walkSelect3(select) {
1581
+ let transformed = false;
1582
+ if (select.with) {
1583
+ for (const cte of select.with) {
1584
+ const cteSelect = cte.stmt?.ast ?? cte.stmt;
1585
+ if (cteSelect && cteSelect.type === "select") {
1586
+ transformed = walkSelect3(cteSelect) || transformed;
1587
+ }
1588
+ }
1589
+ }
1590
+ if (Array.isArray(select.from)) {
1591
+ for (const from of select.from) {
1592
+ if ("expr" in from && from.expr && "ast" in from.expr) {
1593
+ transformed = walkSelect3(from.expr.ast) || transformed;
1594
+ }
1595
+ }
1596
+ }
1597
+ transformed = hoistWithInSelect(select) || transformed;
1598
+ if (select._next) {
1599
+ transformed = walkSelect3(select._next) || transformed;
1600
+ }
1601
+ return transformed;
1602
+ }
1603
+ function hoistUnionWith(ast) {
1604
+ const statements = Array.isArray(ast) ? ast : [ast];
1605
+ let transformed = false;
1606
+ for (const stmt of statements) {
1607
+ if (stmt.type === "select") {
1608
+ transformed = walkSelect3(stmt) || transformed;
1164
1609
  }
1165
1610
  }
1166
1611
  return transformed;
@@ -1169,29 +1614,73 @@ function qualifyJoinColumns(ast) {
1169
1614
  // src/sql/ast-transformer.ts
1170
1615
  var { Parser } = nodeSqlParser;
1171
1616
  var parser = new Parser;
1617
+ var CACHE_SIZE = 500;
1618
+ var transformCache = new Map;
1619
+ function getCachedOrTransform(query, transform) {
1620
+ const cached = transformCache.get(query);
1621
+ if (cached) {
1622
+ transformCache.delete(query);
1623
+ transformCache.set(query, cached);
1624
+ return cached;
1625
+ }
1626
+ const result = transform();
1627
+ if (transformCache.size >= CACHE_SIZE) {
1628
+ const oldestKey = transformCache.keys().next().value;
1629
+ if (oldestKey) {
1630
+ transformCache.delete(oldestKey);
1631
+ }
1632
+ }
1633
+ transformCache.set(query, result);
1634
+ return result;
1635
+ }
1636
+ var DEBUG_ENV = "DRIZZLE_DUCKDB_DEBUG_AST";
1637
+ function hasJoin(query) {
1638
+ return /\bjoin\b/i.test(query);
1639
+ }
1640
+ function debugLog(message, payload) {
1641
+ if (process?.env?.[DEBUG_ENV]) {
1642
+ console.debug("[duckdb-ast]", message, payload ?? "");
1643
+ }
1644
+ }
1172
1645
  function transformSQL(query) {
1173
1646
  const needsArrayTransform = query.includes("@>") || query.includes("<@") || query.includes("&&");
1174
- const needsJoinTransform = query.toLowerCase().includes("join");
1175
- if (!needsArrayTransform && !needsJoinTransform) {
1647
+ const needsJoinTransform = hasJoin(query) || /\bupdate\b/i.test(query) || /\bdelete\b/i.test(query);
1648
+ const needsUnionTransform = /\bunion\b/i.test(query) || /\bintersect\b/i.test(query) || /\bexcept\b/i.test(query);
1649
+ const needsGenerateSeriesTransform = /\bgenerate_series\b/i.test(query);
1650
+ if (!needsArrayTransform && !needsJoinTransform && !needsUnionTransform && !needsGenerateSeriesTransform) {
1176
1651
  return { sql: query, transformed: false };
1177
1652
  }
1178
- try {
1179
- const ast = parser.astify(query, { database: "PostgreSQL" });
1180
- let transformed = false;
1181
- if (needsArrayTransform) {
1182
- transformed = transformArrayOperators(ast) || transformed;
1183
- }
1184
- if (needsJoinTransform) {
1185
- transformed = qualifyJoinColumns(ast) || transformed;
1186
- }
1187
- if (!transformed) {
1653
+ return getCachedOrTransform(query, () => {
1654
+ try {
1655
+ const ast = parser.astify(query, { database: "PostgreSQL" });
1656
+ let transformed = false;
1657
+ if (needsArrayTransform) {
1658
+ transformed = transformArrayOperators(ast) || transformed;
1659
+ }
1660
+ if (needsJoinTransform) {
1661
+ transformed = qualifyJoinColumns(ast) || transformed;
1662
+ }
1663
+ if (needsGenerateSeriesTransform) {
1664
+ transformed = rewriteGenerateSeriesAliases(ast) || transformed;
1665
+ }
1666
+ if (needsUnionTransform) {
1667
+ transformed = hoistUnionWith(ast) || transformed;
1668
+ }
1669
+ if (!transformed) {
1670
+ debugLog("AST parsed but no transformation applied", {
1671
+ join: needsJoinTransform
1672
+ });
1673
+ return { sql: query, transformed: false };
1674
+ }
1675
+ const transformedSql = parser.sqlify(ast, { database: "PostgreSQL" });
1676
+ return { sql: transformedSql, transformed: true };
1677
+ } catch (err) {
1678
+ debugLog("AST transform failed; returning original SQL", {
1679
+ error: err.message
1680
+ });
1188
1681
  return { sql: query, transformed: false };
1189
1682
  }
1190
- const transformedSql = parser.sqlify(ast, { database: "PostgreSQL" });
1191
- return { sql: transformedSql, transformed: true };
1192
- } catch {
1193
- return { sql: query, transformed: false };
1194
- }
1683
+ });
1195
1684
  }
1196
1685
 
1197
1686
  // src/dialect.ts
@@ -2269,7 +2758,7 @@ function renderImports(imports, importBasePath) {
2269
2758
  // src/bin/duckdb-introspect.ts
2270
2759
  function parseArgs(argv) {
2271
2760
  const options = {
2272
- outFile: path.resolve(process.cwd(), "drizzle/schema.ts"),
2761
+ outFile: path.resolve(process2.cwd(), "drizzle/schema.ts"),
2273
2762
  outMeta: undefined,
2274
2763
  allDatabases: false,
2275
2764
  includeViews: false,
@@ -2294,12 +2783,12 @@ function parseArgs(argv) {
2294
2783
  break;
2295
2784
  case "--out":
2296
2785
  case "--outFile":
2297
- options.outFile = path.resolve(process.cwd(), argv[++i] ?? "drizzle/schema.ts");
2786
+ options.outFile = path.resolve(process2.cwd(), argv[++i] ?? "drizzle/schema.ts");
2298
2787
  break;
2299
2788
  case "--out-json":
2300
2789
  case "--outJson":
2301
2790
  case "--json":
2302
- options.outMeta = path.resolve(process.cwd(), argv[++i] ?? "drizzle/schema.meta.json");
2791
+ options.outMeta = path.resolve(process2.cwd(), argv[++i] ?? "drizzle/schema.meta.json");
2303
2792
  break;
2304
2793
  case "--include-views":
2305
2794
  case "--includeViews":
@@ -2314,7 +2803,7 @@ function parseArgs(argv) {
2314
2803
  case "--help":
2315
2804
  case "-h":
2316
2805
  printHelp();
2317
- process.exit(0);
2806
+ process2.exit(0);
2318
2807
  default:
2319
2808
  if (arg.startsWith("-")) {
2320
2809
  console.warn(`Unknown option ${arg}`);
@@ -2356,12 +2845,12 @@ Examples:
2356
2845
  `);
2357
2846
  }
2358
2847
  async function main() {
2359
- const options = parseArgs(process.argv.slice(2));
2848
+ const options = parseArgs(process2.argv.slice(2));
2360
2849
  if (!options.url) {
2361
2850
  printHelp();
2362
2851
  throw new Error("Missing required --url");
2363
2852
  }
2364
- const instanceOptions = options.url.startsWith("md:") && process.env.MOTHERDUCK_TOKEN ? { motherduck_token: process.env.MOTHERDUCK_TOKEN } : undefined;
2853
+ const instanceOptions = options.url.startsWith("md:") && process2.env.MOTHERDUCK_TOKEN ? { motherduck_token: process2.env.MOTHERDUCK_TOKEN } : undefined;
2365
2854
  const instance = await DuckDBInstance3.create(options.url, instanceOptions);
2366
2855
  const connection = await instance.connect();
2367
2856
  const db = drizzle(connection);
@@ -2397,5 +2886,5 @@ async function main() {
2397
2886
  }
2398
2887
  main().catch((err) => {
2399
2888
  console.error(err instanceof Error ? err.message : err);
2400
- process.exit(1);
2889
+ process2.exit(1);
2401
2890
  });