prisma-sql 1.48.0 → 1.49.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.cjs CHANGED
@@ -43,6 +43,7 @@ var __async = (__this, __arguments, generator) => {
43
43
  };
44
44
 
45
45
  // src/builder/shared/constants.ts
46
+ var IS_PRODUCTION = process.env.NODE_ENV === "production";
46
47
  var SQL_SEPARATORS = Object.freeze({
47
48
  FIELD_LIST: ", ",
48
49
  CONDITION_AND: " AND ",
@@ -485,6 +486,15 @@ function createError(message, ctx, code = "VALIDATION_ERROR") {
485
486
 
486
487
  // src/builder/shared/model-field-cache.ts
487
488
  var MODEL_CACHE = /* @__PURE__ */ new WeakMap();
489
+ function quote(id) {
490
+ const needsQuoting2 = !/^[a-z_][a-z0-9_]*$/.test(id) || /^(select|from|where|having|order|group|limit|offset|join|inner|left|right|outer|cross|full|and|or|not|by|as|on|union|intersect|except|case|when|then|else|end|user|users|table|column|index|values|in|like|between|is|exists|null|true|false|all|any|some|update|insert|delete|create|drop|alter|truncate|grant|revoke|exec|execute)$/i.test(
491
+ id
492
+ );
493
+ if (needsQuoting2) {
494
+ return `"${id.replace(/"/g, '""')}"`;
495
+ }
496
+ return id;
497
+ }
488
498
  function ensureFullCache(model) {
489
499
  let cache = MODEL_CACHE.get(model);
490
500
  if (!cache) {
@@ -492,6 +502,8 @@ function ensureFullCache(model) {
492
502
  const scalarFields = /* @__PURE__ */ new Set();
493
503
  const relationFields = /* @__PURE__ */ new Set();
494
504
  const columnMap = /* @__PURE__ */ new Map();
505
+ const fieldByName = /* @__PURE__ */ new Map();
506
+ const quotedColumns = /* @__PURE__ */ new Map();
495
507
  for (const f of model.fields) {
496
508
  const info = {
497
509
  name: f.name,
@@ -501,14 +513,24 @@ function ensureFullCache(model) {
501
513
  isRequired: !!f.isRequired
502
514
  };
503
515
  fieldInfo.set(f.name, info);
516
+ fieldByName.set(f.name, f);
504
517
  if (info.isRelation) {
505
518
  relationFields.add(f.name);
506
519
  } else {
507
520
  scalarFields.add(f.name);
508
- columnMap.set(f.name, info.dbName);
521
+ const dbName = info.dbName;
522
+ columnMap.set(f.name, dbName);
523
+ quotedColumns.set(f.name, quote(dbName));
509
524
  }
510
525
  }
511
- cache = { fieldInfo, scalarFields, relationFields, columnMap };
526
+ cache = {
527
+ fieldInfo,
528
+ scalarFields,
529
+ relationFields,
530
+ columnMap,
531
+ fieldByName,
532
+ quotedColumns
533
+ };
512
534
  MODEL_CACHE.set(model, cache);
513
535
  }
514
536
  return cache;
@@ -525,6 +547,9 @@ function getRelationFieldSet(model) {
525
547
  function getColumnMap(model) {
526
548
  return ensureFullCache(model).columnMap;
527
549
  }
550
+ function getQuotedColumn(model, fieldName) {
551
+ return ensureFullCache(model).quotedColumns.get(fieldName);
552
+ }
528
553
 
529
554
  // src/builder/shared/validators/sql-validators.ts
530
555
  function isValidWhereClause(clause) {
@@ -540,6 +565,7 @@ function sqlPreview(sql) {
540
565
  return `${s.slice(0, 160)}...`;
541
566
  }
542
567
  function validateSelectQuery(sql) {
568
+ if (IS_PRODUCTION) return;
543
569
  if (!hasValidContent(sql)) {
544
570
  throw new Error("CRITICAL: Generated empty SQL query");
545
571
  }
@@ -598,6 +624,7 @@ function assertNoGapsDollar(scan, rangeMin, rangeMax, sql) {
598
624
  }
599
625
  }
600
626
  function validateParamConsistency(sql, params) {
627
+ if (IS_PRODUCTION) return;
601
628
  const paramLen = params.length;
602
629
  const scan = scanDollarPlaceholders(sql, paramLen);
603
630
  if (paramLen === 0) {
@@ -634,6 +661,7 @@ function countQuestionMarkPlaceholders(sql) {
634
661
  return count;
635
662
  }
636
663
  function validateQuestionMarkConsistency(sql, params) {
664
+ if (IS_PRODUCTION) return;
637
665
  const expected = params.length;
638
666
  const found = countQuestionMarkPlaceholders(sql);
639
667
  if (expected !== found) {
@@ -643,6 +671,7 @@ function validateQuestionMarkConsistency(sql, params) {
643
671
  }
644
672
  }
645
673
  function validateParamConsistencyByDialect(sql, params, dialect) {
674
+ if (IS_PRODUCTION) return;
646
675
  if (dialect === "postgres") {
647
676
  validateParamConsistency(sql, params);
648
677
  return;
@@ -804,7 +833,7 @@ function assertSafeQualifiedName(tableRef) {
804
833
  }
805
834
  }
806
835
  }
807
- function quote(id) {
836
+ function quote2(id) {
808
837
  if (isEmptyString(id)) {
809
838
  throw new Error("quote: identifier is required and cannot be empty");
810
839
  }
@@ -824,17 +853,14 @@ function resolveColumnName(model, fieldName) {
824
853
  return columnMap.get(fieldName) || fieldName;
825
854
  }
826
855
  function quoteColumn(model, fieldName) {
827
- return quote(resolveColumnName(model, fieldName));
856
+ if (!model) return quote2(fieldName);
857
+ const cached = getQuotedColumn(model, fieldName);
858
+ return cached || quote2(fieldName);
828
859
  }
829
860
  function col(alias, field, model) {
830
- if (isEmptyString(alias)) {
831
- throw new Error("col: alias is required and cannot be empty");
832
- }
833
- if (isEmptyString(field)) {
834
- throw new Error("col: field is required and cannot be empty");
835
- }
836
- const columnName = resolveColumnName(model, field);
837
- return `${alias}.${quote(columnName)}`;
861
+ const columnName = model ? getColumnMap(model).get(field) || field : field;
862
+ const quoted = model ? getQuotedColumn(model, field) || quote2(columnName) : quote2(columnName);
863
+ return alias + "." + quoted;
838
864
  }
839
865
  function colWithAlias(alias, field, model) {
840
866
  if (isEmptyString(alias)) {
@@ -844,9 +870,9 @@ function colWithAlias(alias, field, model) {
844
870
  throw new Error("colWithAlias: field is required and cannot be empty");
845
871
  }
846
872
  const columnName = resolveColumnName(model, field);
847
- const columnRef = `${alias}.${quote(columnName)}`;
873
+ const columnRef = alias + "." + (model ? getQuotedColumn(model, field) || quote2(columnName) : quote2(columnName));
848
874
  if (columnName !== field) {
849
- return `${columnRef} AS ${quote(field)}`;
875
+ return columnRef + " AS " + quote2(field);
850
876
  }
851
877
  return columnRef;
852
878
  }
@@ -869,7 +895,7 @@ function buildTableReference(schemaName, tableName, dialect) {
869
895
  }
870
896
  const d = dialect != null ? dialect : "postgres";
871
897
  if (d === "sqlite") {
872
- return quote(tableName);
898
+ return quote2(tableName);
873
899
  }
874
900
  if (isEmptyString(schemaName)) {
875
901
  throw new Error(
@@ -1197,6 +1223,7 @@ function assertNumericField(model, fieldName, context) {
1197
1223
 
1198
1224
  // src/builder/pagination.ts
1199
1225
  var MAX_LIMIT_OFFSET = 2147483647;
1226
+ var ORDER_BY_ALLOWED_KEYS = /* @__PURE__ */ new Set(["sort", "nulls"]);
1200
1227
  function parseDirectionRaw(raw, errorLabel) {
1201
1228
  const s = String(raw).toLowerCase();
1202
1229
  if (s === "asc" || s === "desc") return s;
@@ -1215,9 +1242,8 @@ function requireOrderByObject(v, errorPrefix) {
1215
1242
  return v;
1216
1243
  }
1217
1244
  function assertAllowedOrderByKeys(obj, fieldName) {
1218
- const allowed = /* @__PURE__ */ new Set(["sort", "nulls"]);
1219
1245
  for (const k of Object.keys(obj)) {
1220
- if (!allowed.has(k)) {
1246
+ if (!ORDER_BY_ALLOWED_KEYS.has(k)) {
1221
1247
  throw new Error(
1222
1248
  fieldName ? `Unsupported orderBy key '${k}' for field '${fieldName}'` : `Unsupported orderBy key '${k}'`
1223
1249
  );
@@ -1284,17 +1310,17 @@ function buildOrderByFragment(entries, alias, dialect, model) {
1284
1310
  const c = col(alias, e.field, model);
1285
1311
  if (dialect === "postgres") {
1286
1312
  const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
1287
- out.push(`${c} ${dir}${nulls}`);
1313
+ out.push(c + " " + dir + nulls);
1288
1314
  continue;
1289
1315
  }
1290
1316
  if (isNotNullish(e.nulls)) {
1291
1317
  const isNullExpr = `(${c} IS NULL)`;
1292
1318
  const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
1293
- out.push(`${isNullExpr} ${nullRankDir}`);
1294
- out.push(`${c} ${dir}`);
1319
+ out.push(isNullExpr + " " + nullRankDir);
1320
+ out.push(c + " " + dir);
1295
1321
  continue;
1296
1322
  }
1297
- out.push(`${c} ${dir}`);
1323
+ out.push(c + " " + dir);
1298
1324
  }
1299
1325
  return out.join(SQL_SEPARATORS.ORDER_BY);
1300
1326
  }
@@ -1303,79 +1329,47 @@ function defaultNullsFor(dialect, direction) {
1303
1329
  return direction === "asc" ? "first" : "last";
1304
1330
  }
1305
1331
  function ensureCursorFieldsInOrder(orderEntries, cursorEntries) {
1306
- const existing = /* @__PURE__ */ new Map();
1307
- for (const e of orderEntries) existing.set(e.field, e);
1308
- const out = [...orderEntries];
1309
- for (const [field] of cursorEntries) {
1332
+ if (cursorEntries.length === 0) return orderEntries;
1333
+ const existing = /* @__PURE__ */ new Set();
1334
+ for (let i = 0; i < orderEntries.length; i++)
1335
+ existing.add(orderEntries[i].field);
1336
+ let out = null;
1337
+ for (let i = 0; i < cursorEntries.length; i++) {
1338
+ const field = cursorEntries[i][0];
1310
1339
  if (!existing.has(field)) {
1340
+ if (!out) out = orderEntries.slice();
1311
1341
  out.push({ field, direction: "asc" });
1312
- existing.set(field, out[out.length - 1]);
1342
+ existing.add(field);
1313
1343
  }
1314
1344
  }
1315
- return out;
1345
+ return out != null ? out : orderEntries;
1316
1346
  }
1317
1347
  function buildCursorFilterParts(cursor, cursorAlias, params, model) {
1318
- const entries = Object.entries(cursor);
1319
- if (entries.length === 0)
1320
- throw new Error("cursor must have at least one field");
1321
- const placeholdersByField = /* @__PURE__ */ new Map();
1322
1348
  const parts = [];
1323
- for (const [field, value] of entries) {
1324
- const c = `${cursorAlias}.${quoteColumn(model, field)}`;
1349
+ for (const field in cursor) {
1350
+ if (!Object.prototype.hasOwnProperty.call(cursor, field)) continue;
1351
+ const value = cursor[field];
1352
+ const c = cursorAlias + "." + quoteColumn(model, field);
1325
1353
  if (value === null) {
1326
- parts.push(`${c} IS NULL`);
1354
+ parts.push(c + " IS NULL");
1327
1355
  continue;
1328
1356
  }
1329
1357
  const ph = addAutoScoped(params, value, `cursor.filter.${field}`);
1330
- placeholdersByField.set(field, ph);
1331
- parts.push(`${c} = ${ph}`);
1358
+ parts.push(c + " = " + ph);
1332
1359
  }
1333
1360
  return {
1334
- whereSql: parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`,
1335
- placeholdersByField
1361
+ whereSql: parts.length === 1 ? parts[0] : "(" + parts.join(" AND ") + ")"
1336
1362
  };
1337
1363
  }
1338
- function buildCursorEqualityExpr(columnExpr, valueExpr) {
1339
- return `((${valueExpr} IS NULL AND ${columnExpr} IS NULL) OR (${valueExpr} IS NOT NULL AND ${columnExpr} = ${valueExpr}))`;
1364
+ function buildCursorEqualityExpr(columnExpr, cursorField) {
1365
+ return `((${cursorField} IS NULL AND ${columnExpr} IS NULL) OR (${cursorField} IS NOT NULL AND ${columnExpr} = ${cursorField}))`;
1340
1366
  }
1341
- function buildCursorInequalityExpr(columnExpr, direction, nulls, valueExpr) {
1367
+ function buildCursorInequalityExpr(columnExpr, direction, nulls, cursorField) {
1342
1368
  const op = direction === "asc" ? ">" : "<";
1343
1369
  if (nulls === "first") {
1344
- return `(CASE WHEN ${valueExpr} IS NULL THEN (${columnExpr} IS NOT NULL) ELSE (${columnExpr} ${op} ${valueExpr}) END)`;
1345
- }
1346
- return `(CASE WHEN ${valueExpr} IS NULL THEN 0=1 ELSE ((${columnExpr} ${op} ${valueExpr}) OR (${columnExpr} IS NULL)) END)`;
1347
- }
1348
- function buildOuterCursorMatch(cursor, outerAlias, placeholdersByField, params, model) {
1349
- const parts = [];
1350
- for (const [field, value] of Object.entries(cursor)) {
1351
- const c = col(outerAlias, field, model);
1352
- if (value === null) {
1353
- parts.push(`${c} IS NULL`);
1354
- continue;
1355
- }
1356
- const existing = placeholdersByField.get(field);
1357
- if (typeof existing === "string" && existing.length > 0) {
1358
- parts.push(`${c} = ${existing}`);
1359
- continue;
1360
- }
1361
- const ph = addAutoScoped(params, value, `cursor.outerMatch.${field}`);
1362
- parts.push(`${c} = ${ph}`);
1363
- }
1364
- return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
1365
- }
1366
- function buildOrderEntries(orderBy) {
1367
- const normalized = normalizeOrderByInput(orderBy, parseOrderByValue);
1368
- const entries = [];
1369
- for (const item of normalized) {
1370
- for (const [field, value] of Object.entries(item)) {
1371
- if (typeof value === "string") {
1372
- entries.push({ field, direction: value });
1373
- } else {
1374
- entries.push({ field, direction: value.direction, nulls: value.nulls });
1375
- }
1376
- }
1370
+ return `(CASE WHEN ${cursorField} IS NULL THEN (${columnExpr} IS NOT NULL) ELSE (${columnExpr} ${op} ${cursorField}) END)`;
1377
1371
  }
1378
- return entries;
1372
+ return `(CASE WHEN ${cursorField} IS NULL THEN 0=1 ELSE ((${columnExpr} ${op} ${cursorField}) OR (${columnExpr} IS NULL)) END)`;
1379
1373
  }
1380
1374
  function buildCursorCteSelectList(cursorEntries, orderEntries, model) {
1381
1375
  const seen = /* @__PURE__ */ new Set();
@@ -1397,8 +1391,7 @@ function buildCursorCteSelectList(cursorEntries, orderEntries, model) {
1397
1391
  }
1398
1392
  function truncateIdent(name, maxLen) {
1399
1393
  const s = String(name);
1400
- if (s.length <= maxLen) return s;
1401
- return s.slice(0, maxLen);
1394
+ return s.length <= maxLen ? s : s.slice(0, maxLen);
1402
1395
  }
1403
1396
  function buildCursorNames(outerAlias) {
1404
1397
  const maxLen = 63;
@@ -1415,15 +1408,25 @@ function buildCursorNames(outerAlias) {
1415
1408
  }
1416
1409
  function assertCursorAndOrderFieldsScalar(model, cursor, orderEntries) {
1417
1410
  if (!model) return;
1418
- for (const k of Object.keys(cursor)) assertScalarField(model, k, "cursor");
1419
- for (const e of orderEntries) assertScalarField(model, e.field, "orderBy");
1411
+ for (const k in cursor) {
1412
+ if (!Object.prototype.hasOwnProperty.call(cursor, k)) continue;
1413
+ assertScalarField(model, k, "cursor");
1414
+ }
1415
+ for (const e of orderEntries) {
1416
+ assertScalarField(model, e.field, "orderBy");
1417
+ }
1420
1418
  }
1421
1419
  function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
1422
1420
  var _a;
1423
1421
  assertSafeTableRef(tableName);
1424
1422
  assertSafeAlias(alias);
1425
1423
  const d = dialect != null ? dialect : getGlobalDialect();
1426
- const cursorEntries = Object.entries(cursor);
1424
+ const cursorEntries = [];
1425
+ for (const k in cursor) {
1426
+ if (Object.prototype.hasOwnProperty.call(cursor, k)) {
1427
+ cursorEntries.push([k, cursor[k]]);
1428
+ }
1429
+ }
1427
1430
  if (cursorEntries.length === 0)
1428
1431
  throw new Error("cursor must have at least one field");
1429
1432
  const { cteName, srcAlias } = buildCursorNames(alias);
@@ -1444,48 +1447,51 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
1444
1447
  orderEntries = ensureCursorFieldsInOrder(orderEntries, cursorEntries);
1445
1448
  }
1446
1449
  assertCursorAndOrderFieldsScalar(model, cursor, orderEntries);
1447
- const { whereSql: cursorWhereSql, placeholdersByField } = buildCursorFilterParts(cursor, srcAlias, params, model);
1450
+ const { whereSql: cursorWhereSql } = buildCursorFilterParts(
1451
+ cursor,
1452
+ srcAlias,
1453
+ params,
1454
+ model
1455
+ );
1448
1456
  const cursorOrderBy = orderEntries.map(
1449
- (e) => `${srcAlias}.${quoteColumn(model, e.field)} ${e.direction.toUpperCase()}`
1457
+ (e) => srcAlias + "." + quoteColumn(model, e.field) + " " + e.direction.toUpperCase()
1450
1458
  ).join(", ");
1451
1459
  const selectList = buildCursorCteSelectList(
1452
1460
  cursorEntries,
1453
1461
  orderEntries,
1454
1462
  model
1455
1463
  );
1456
- const cte = `${cteName} AS (
1457
- SELECT ${selectList} FROM ${tableName} ${srcAlias}
1458
- WHERE ${cursorWhereSql}
1459
- ORDER BY ${cursorOrderBy}
1460
- LIMIT 1
1461
- )`;
1462
- const existsExpr = `EXISTS (SELECT 1 FROM ${cteName})`;
1463
- const outerCursorMatch = buildOuterCursorMatch(
1464
- cursor,
1465
- alias,
1466
- placeholdersByField,
1467
- params,
1468
- model
1469
- );
1470
- const getValueExpr = (field) => `(SELECT ${quoteColumn(model, field)} FROM ${cteName})`;
1464
+ const cte = cteName + " AS (\n SELECT " + selectList + " FROM " + tableName + " " + srcAlias + "\n WHERE " + cursorWhereSql + "\n ORDER BY " + cursorOrderBy + "\n LIMIT 1\n )";
1465
+ const existsExpr = "EXISTS (SELECT 1 FROM " + cteName + ")";
1471
1466
  const orClauses = [];
1472
1467
  for (let level = 0; level < orderEntries.length; level++) {
1473
1468
  const andParts = [];
1474
1469
  for (let i = 0; i < level; i++) {
1475
1470
  const e2 = orderEntries[i];
1476
1471
  const c2 = col(alias, e2.field, model);
1477
- const v2 = getValueExpr(e2.field);
1478
- andParts.push(buildCursorEqualityExpr(c2, v2));
1472
+ const cursorField2 = cteName + "." + quoteColumn(model, e2.field);
1473
+ andParts.push(buildCursorEqualityExpr(c2, cursorField2));
1479
1474
  }
1480
1475
  const e = orderEntries[level];
1481
1476
  const c = col(alias, e.field, model);
1482
- const v = getValueExpr(e.field);
1477
+ const cursorField = cteName + "." + quoteColumn(model, e.field);
1483
1478
  const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
1484
- andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, v));
1485
- orClauses.push(`(${andParts.join(SQL_SEPARATORS.CONDITION_AND)})`);
1479
+ andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, cursorField));
1480
+ orClauses.push("(" + andParts.join(SQL_SEPARATORS.CONDITION_AND) + ")");
1486
1481
  }
1487
1482
  const exclusive = orClauses.join(SQL_SEPARATORS.CONDITION_OR);
1488
- const condition = `(${existsExpr} ${SQL_SEPARATORS.CONDITION_AND} ((${exclusive})${SQL_SEPARATORS.CONDITION_OR}(${outerCursorMatch})))`;
1483
+ const outerMatchParts = [];
1484
+ for (const [field, value] of cursorEntries) {
1485
+ const c = col(alias, field, model);
1486
+ if (value === null) {
1487
+ outerMatchParts.push(c + " IS NULL");
1488
+ continue;
1489
+ }
1490
+ const ph = addAutoScoped(params, value, `cursor.outerMatch.${field}`);
1491
+ outerMatchParts.push(c + " = " + ph);
1492
+ }
1493
+ const outerCursorMatch = outerMatchParts.length === 1 ? outerMatchParts[0] : "(" + outerMatchParts.join(SQL_SEPARATORS.CONDITION_AND) + ")";
1494
+ const condition = "(" + existsExpr + SQL_SEPARATORS.CONDITION_AND + "((" + exclusive + ")" + SQL_SEPARATORS.CONDITION_OR + "(" + outerCursorMatch + ")))";
1489
1495
  return { cte, condition };
1490
1496
  }
1491
1497
  function buildOrderBy(orderBy, alias, dialect, model) {
@@ -1538,6 +1544,22 @@ function getPaginationParams(method, args) {
1538
1544
  }
1539
1545
  return {};
1540
1546
  }
1547
+ function buildOrderEntries(orderBy) {
1548
+ const normalized = normalizeOrderByInput(orderBy, parseOrderByValue);
1549
+ const entries = [];
1550
+ for (const item of normalized) {
1551
+ for (const field in item) {
1552
+ if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
1553
+ const value = item[field];
1554
+ if (typeof value === "string") {
1555
+ entries.push({ field, direction: value });
1556
+ } else {
1557
+ entries.push({ field, direction: value.direction, nulls: value.nulls });
1558
+ }
1559
+ }
1560
+ }
1561
+ return entries;
1562
+ }
1541
1563
  function buildNotComposite(expr, val, params, dialect, buildOp, separator) {
1542
1564
  const entries = Object.entries(val).filter(
1543
1565
  ([k, v]) => k !== "mode" && v !== void 0
@@ -2008,7 +2030,7 @@ function buildListRelationFilters(args) {
2008
2030
  ) || relModel.fields.find((f) => !f.isRelation && f.name === "id");
2009
2031
  if (checkField) {
2010
2032
  const leftJoinSql = `LEFT JOIN ${relTable} ${relAlias} ON ${join}`;
2011
- const whereClause = `${relAlias}.${quote(checkField.name)} IS NULL`;
2033
+ const whereClause = `${relAlias}.${quote2(checkField.name)} IS NULL`;
2012
2034
  return Object.freeze({
2013
2035
  clause: whereClause,
2014
2036
  joins: freezeJoins([leftJoinSql])
@@ -2459,11 +2481,24 @@ function buildOperator(expr, op, val, ctx, mode, fieldType) {
2459
2481
  // src/builder/shared/alias-generator.ts
2460
2482
  function toSafeSqlIdentifier(input) {
2461
2483
  const raw = String(input);
2462
- const cleaned = raw.replace(/\W/g, "_");
2463
- const startsOk = /^[a-zA-Z_]/.test(cleaned);
2464
- const base = startsOk ? cleaned : `_${cleaned}`;
2465
- const fallback = base.length > 0 ? base : "_t";
2466
- const lowered = fallback.toLowerCase();
2484
+ const n = raw.length;
2485
+ let out = "";
2486
+ for (let i = 0; i < n; i++) {
2487
+ const c = raw.charCodeAt(i);
2488
+ const isAZ = c >= 65 && c <= 90 || c >= 97 && c <= 122;
2489
+ const is09 = c >= 48 && c <= 57;
2490
+ const isUnderscore = c === 95;
2491
+ if (isAZ || is09 || isUnderscore) {
2492
+ out += raw[i];
2493
+ } else {
2494
+ out += "_";
2495
+ }
2496
+ }
2497
+ if (out.length === 0) out = "_t";
2498
+ const c0 = out.charCodeAt(0);
2499
+ const startsOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95;
2500
+ if (!startsOk) out = `_${out}`;
2501
+ const lowered = out.toLowerCase();
2467
2502
  return ALIAS_FORBIDDEN_KEYWORDS.has(lowered) ? `_${lowered}` : lowered;
2468
2503
  }
2469
2504
  function createAliasGenerator(maxAliases = 1e4) {
@@ -2566,14 +2601,16 @@ function validateState(params, mappings, index) {
2566
2601
  }
2567
2602
  function createStoreInternal(startIndex, initialParams = [], initialMappings = []) {
2568
2603
  let index = startIndex;
2569
- const params = [...initialParams];
2570
- const mappings = [...initialMappings];
2604
+ const params = initialParams.length > 0 ? [...initialParams] : [];
2605
+ const mappings = initialMappings.length > 0 ? [...initialMappings] : [];
2571
2606
  const dynamicNameToIndex = /* @__PURE__ */ new Map();
2572
- for (const m of initialMappings) {
2607
+ for (const m of mappings) {
2573
2608
  if (typeof m.dynamicName === "string") {
2574
2609
  dynamicNameToIndex.set(m.dynamicName.trim(), m.index);
2575
2610
  }
2576
2611
  }
2612
+ let dirty = true;
2613
+ let cachedSnapshot = null;
2577
2614
  function assertCanAdd() {
2578
2615
  if (index > MAX_PARAM_INDEX) {
2579
2616
  throw new Error(
@@ -2581,6 +2618,9 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2581
2618
  );
2582
2619
  }
2583
2620
  }
2621
+ function format(position) {
2622
+ return `$${position}`;
2623
+ }
2584
2624
  function normalizeDynamicName(dynamicName) {
2585
2625
  const dn = dynamicName.trim();
2586
2626
  if (dn.length === 0) {
@@ -2588,20 +2628,16 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2588
2628
  }
2589
2629
  return dn;
2590
2630
  }
2591
- function format(position) {
2592
- return `$${position}`;
2593
- }
2594
2631
  function addDynamic(dynamicName) {
2595
2632
  const dn = normalizeDynamicName(dynamicName);
2596
2633
  const existing = dynamicNameToIndex.get(dn);
2597
- if (existing !== void 0) {
2598
- return format(existing);
2599
- }
2634
+ if (existing !== void 0) return format(existing);
2600
2635
  const position = index;
2601
2636
  dynamicNameToIndex.set(dn, position);
2602
2637
  params.push(void 0);
2603
2638
  mappings.push({ index: position, dynamicName: dn });
2604
2639
  index++;
2640
+ dirty = true;
2605
2641
  return format(position);
2606
2642
  }
2607
2643
  function addStatic(value) {
@@ -2610,6 +2646,7 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2610
2646
  params.push(normalizedValue);
2611
2647
  mappings.push({ index: position, value: normalizedValue });
2612
2648
  index++;
2649
+ dirty = true;
2613
2650
  return format(position);
2614
2651
  }
2615
2652
  function add(value, dynamicName) {
@@ -2624,11 +2661,15 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2624
2661
  return add(value);
2625
2662
  }
2626
2663
  function snapshot() {
2627
- return Object.freeze({
2664
+ if (!dirty && cachedSnapshot) return cachedSnapshot;
2665
+ const snap = {
2628
2666
  index,
2629
- params: Object.freeze([...params]),
2630
- mappings: Object.freeze([...mappings])
2631
- });
2667
+ params,
2668
+ mappings
2669
+ };
2670
+ cachedSnapshot = snap;
2671
+ dirty = false;
2672
+ return snap;
2632
2673
  }
2633
2674
  return {
2634
2675
  add,
@@ -2837,7 +2878,7 @@ function getRelationTableReference(relModel, dialect) {
2837
2878
  dialect
2838
2879
  );
2839
2880
  }
2840
- function resolveRelationOrThrow(model, schemas, relName) {
2881
+ function resolveRelationOrThrow(model, schemas, schemaByName, relName) {
2841
2882
  const field = model.fields.find((f) => f.name === relName);
2842
2883
  if (!isNotNullish(field)) {
2843
2884
  throw new Error(
@@ -2849,10 +2890,16 @@ function resolveRelationOrThrow(model, schemas, relName) {
2849
2890
  `Invalid relation metadata for '${relName}' on model ${model.name}. This usually indicates a schema parsing error (missing foreignKey/references).`
2850
2891
  );
2851
2892
  }
2852
- const relModel = schemas.find((m) => m.name === field.relatedModel);
2893
+ const relatedModelName = field.relatedModel;
2894
+ if (!isNotNullish(relatedModelName) || String(relatedModelName).trim().length === 0) {
2895
+ throw new Error(
2896
+ `Relation '${relName}' on model ${model.name} is missing relatedModel metadata.`
2897
+ );
2898
+ }
2899
+ const relModel = schemaByName.get(relatedModelName);
2853
2900
  if (!isNotNullish(relModel)) {
2854
2901
  throw new Error(
2855
- `Relation '${relName}' on model ${model.name} references missing model '${field.relatedModel}'.`
2902
+ `Relation '${relName}' on model ${model.name} references missing model '${relatedModelName}'.`
2856
2903
  );
2857
2904
  }
2858
2905
  return { field, relModel };
@@ -2971,6 +3018,7 @@ function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
2971
3018
  relArgs,
2972
3019
  relModel,
2973
3020
  ctx.schemas,
3021
+ ctx.schemaByName,
2974
3022
  relAlias,
2975
3023
  ctx.aliasGen,
2976
3024
  ctx.params,
@@ -3159,7 +3207,7 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3159
3207
  ctx
3160
3208
  });
3161
3209
  }
3162
- function buildIncludeSqlInternal(args, model, schemas, parentAlias, aliasGen, params, dialect, visitPath = [], depth = 0, stats) {
3210
+ function buildIncludeSqlInternal(args, model, schemas, schemaByName, parentAlias, aliasGen, params, dialect, visitPath = [], depth = 0, stats) {
3163
3211
  if (!stats) stats = { totalIncludes: 0, totalSubqueries: 0, maxDepth: 0 };
3164
3212
  if (depth > MAX_INCLUDE_DEPTH) {
3165
3213
  throw new Error(
@@ -3183,7 +3231,12 @@ function buildIncludeSqlInternal(args, model, schemas, parentAlias, aliasGen, pa
3183
3231
  `Query complexity limit exceeded: ${stats.totalSubqueries} subqueries generated. Maximum allowed: ${MAX_TOTAL_SUBQUERIES}. This indicates exponential include nesting. Stats: depth=${stats.maxDepth}, includes=${stats.totalIncludes}. Path: ${visitPath.join(" -> ")}. Simplify your include structure or split into multiple queries.`
3184
3232
  );
3185
3233
  }
3186
- const resolved = resolveRelationOrThrow(model, schemas, relName);
3234
+ const resolved = resolveRelationOrThrow(
3235
+ model,
3236
+ schemas,
3237
+ schemaByName,
3238
+ relName
3239
+ );
3187
3240
  const relationPath = `${model.name}.${relName}`;
3188
3241
  const currentPath = [...visitPath, relationPath];
3189
3242
  if (visitPath.includes(relationPath)) {
@@ -3203,6 +3256,7 @@ function buildIncludeSqlInternal(args, model, schemas, parentAlias, aliasGen, pa
3203
3256
  buildSingleInclude(relName, relArgs, resolved.field, resolved.relModel, {
3204
3257
  model,
3205
3258
  schemas,
3259
+ schemaByName,
3206
3260
  parentAlias,
3207
3261
  aliasGen,
3208
3262
  dialect,
@@ -3222,10 +3276,13 @@ function buildIncludeSql(args, model, schemas, parentAlias, params, dialect) {
3222
3276
  totalSubqueries: 0,
3223
3277
  maxDepth: 0
3224
3278
  };
3279
+ const schemaByName = /* @__PURE__ */ new Map();
3280
+ for (const m of schemas) schemaByName.set(m.name, m);
3225
3281
  return buildIncludeSqlInternal(
3226
3282
  args,
3227
3283
  model,
3228
3284
  schemas,
3285
+ schemaByName,
3229
3286
  parentAlias,
3230
3287
  aliasGen,
3231
3288
  params,
@@ -3235,7 +3292,7 @@ function buildIncludeSql(args, model, schemas, parentAlias, params, dialect) {
3235
3292
  stats
3236
3293
  );
3237
3294
  }
3238
- function resolveCountRelationOrThrow(relName, model, schemas) {
3295
+ function resolveCountRelationOrThrow(relName, model, schemas, schemaByName) {
3239
3296
  const relationSet = getRelationFieldSet(model);
3240
3297
  if (!relationSet.has(relName)) {
3241
3298
  throw new Error(
@@ -3252,10 +3309,16 @@ function resolveCountRelationOrThrow(relName, model, schemas) {
3252
3309
  `_count.${relName} has invalid relation metadata on model ${model.name}`
3253
3310
  );
3254
3311
  }
3255
- const relModel = schemas.find((m) => m.name === field.relatedModel);
3312
+ const relatedModelName = field.relatedModel;
3313
+ if (!isNotNullish(relatedModelName) || String(relatedModelName).trim().length === 0) {
3314
+ throw new Error(
3315
+ `_count.${relName} is missing relatedModel metadata on model ${model.name}`
3316
+ );
3317
+ }
3318
+ const relModel = schemaByName.get(relatedModelName);
3256
3319
  if (!relModel) {
3257
3320
  throw new Error(
3258
- `Related model '${field.relatedModel}' not found for _count.${relName}`
3321
+ `Related model '${relatedModelName}' not found for _count.${relName}`
3259
3322
  );
3260
3323
  }
3261
3324
  return { field, relModel };
@@ -3341,9 +3404,16 @@ function buildRelationCountSql(countSelect, model, schemas, parentAlias, _params
3341
3404
  const joins = [];
3342
3405
  const pairs = [];
3343
3406
  const aliasGen = createAliasGenerator();
3407
+ const schemaByName = /* @__PURE__ */ new Map();
3408
+ for (const m of schemas) schemaByName.set(m.name, m);
3344
3409
  for (const [relName, shouldCount] of Object.entries(countSelect)) {
3345
3410
  if (!shouldCount) continue;
3346
- const resolved = resolveCountRelationOrThrow(relName, model, schemas);
3411
+ const resolved = resolveCountRelationOrThrow(
3412
+ relName,
3413
+ model,
3414
+ schemas,
3415
+ schemaByName
3416
+ );
3347
3417
  const built = buildCountJoinAndPair({
3348
3418
  relName,
3349
3419
  field: resolved.field,
@@ -3359,35 +3429,36 @@ function buildRelationCountSql(countSelect, model, schemas, parentAlias, _params
3359
3429
  return { joins, jsonPairs: pairs.join(SQL_SEPARATORS.FIELD_LIST) };
3360
3430
  }
3361
3431
 
3362
- // src/builder/select/assembly.ts
3363
- var ALIAS_CAPTURE = "([A-Za-z_][A-Za-z0-9_]*)";
3364
- var COLUMN_PART = '(?:"([^"]+)"|([a-z_][a-z0-9_]*))';
3365
- var AS_PART = `(?:\\s+AS\\s+${COLUMN_PART})?`;
3366
- var SIMPLE_COLUMN_PATTERN = `^${ALIAS_CAPTURE}\\.${COLUMN_PART}${AS_PART}$`;
3367
- var SIMPLE_COLUMN_RE = new RegExp(SIMPLE_COLUMN_PATTERN, "i");
3432
+ // src/builder/shared/string-builder.ts
3368
3433
  function joinNonEmpty(parts, sep) {
3369
- return parts.filter((s) => s.trim().length > 0).join(sep);
3434
+ let result = "";
3435
+ for (const p of parts) {
3436
+ if (p) {
3437
+ if (result) result += sep;
3438
+ result += p;
3439
+ }
3440
+ }
3441
+ return result;
3370
3442
  }
3371
3443
  function buildWhereSql(conditions) {
3372
3444
  if (!isNonEmptyArray(conditions)) return "";
3373
- const parts = [
3374
- SQL_TEMPLATES.WHERE,
3375
- conditions.join(SQL_SEPARATORS.CONDITION_AND)
3376
- ];
3377
- return ` ${parts.join(" ")}`;
3445
+ return " " + SQL_TEMPLATES.WHERE + " " + conditions.join(SQL_SEPARATORS.CONDITION_AND);
3378
3446
  }
3379
3447
  function buildJoinsSql(...joinGroups) {
3380
3448
  const all = [];
3381
3449
  for (const g of joinGroups) {
3382
- if (isNonEmptyArray(g)) all.push(...g);
3450
+ if (isNonEmptyArray(g)) {
3451
+ for (const j of g) all.push(j);
3452
+ }
3383
3453
  }
3384
- return all.length > 0 ? ` ${all.join(" ")}` : "";
3454
+ return all.length > 0 ? " " + all.join(" ") : "";
3385
3455
  }
3386
3456
  function buildSelectList(baseSelect, extraCols) {
3387
3457
  const base = baseSelect.trim();
3388
3458
  const extra = extraCols.trim();
3389
- if (base && extra) return `${base}${SQL_SEPARATORS.FIELD_LIST}${extra}`;
3390
- return base || extra;
3459
+ if (!base) return extra;
3460
+ if (!extra) return base;
3461
+ return base + SQL_SEPARATORS.FIELD_LIST + extra;
3391
3462
  }
3392
3463
  function finalizeSql(sql, params, dialect) {
3393
3464
  const snapshot = params.snapshot();
@@ -3397,38 +3468,128 @@ function finalizeSql(sql, params, dialect) {
3397
3468
  snapshot.params,
3398
3469
  dialect === "sqlite" ? "postgres" : dialect
3399
3470
  );
3400
- return Object.freeze({
3471
+ return {
3401
3472
  sql,
3402
3473
  params: snapshot.params,
3403
- paramMappings: Object.freeze(snapshot.mappings)
3404
- });
3474
+ paramMappings: snapshot.mappings
3475
+ };
3405
3476
  }
3406
3477
  function parseSimpleScalarSelect(select, fromAlias) {
3407
- var _a, _b, _c, _d;
3408
3478
  const raw = select.trim();
3409
3479
  if (raw.length === 0) return [];
3480
+ const fromLower = fromAlias.toLowerCase();
3410
3481
  const parts = raw.split(SQL_SEPARATORS.FIELD_LIST);
3411
3482
  const names = [];
3412
- for (const part of parts) {
3413
- const p = part.trim();
3414
- const m = p.match(SIMPLE_COLUMN_RE);
3415
- if (!m) {
3483
+ const isIdent = (s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s);
3484
+ const readIdentOrQuoted = (s, start) => {
3485
+ const n = s.length;
3486
+ if (start >= n) return { text: "", next: start, quoted: false };
3487
+ if (s.charCodeAt(start) === 34) {
3488
+ let i2 = start + 1;
3489
+ let out = "";
3490
+ let saw = false;
3491
+ while (i2 < n) {
3492
+ const c = s.charCodeAt(i2);
3493
+ if (c === 34) {
3494
+ const next = i2 + 1;
3495
+ if (next < n && s.charCodeAt(next) === 34) {
3496
+ out += '"';
3497
+ saw = true;
3498
+ i2 += 2;
3499
+ continue;
3500
+ }
3501
+ if (!saw)
3502
+ throw new Error(
3503
+ `sqlite distinct emulation: empty quoted identifier in: ${s}`
3504
+ );
3505
+ return { text: out, next: i2 + 1, quoted: true };
3506
+ }
3507
+ out += s[i2];
3508
+ saw = true;
3509
+ i2++;
3510
+ }
3416
3511
  throw new Error(
3417
- `sqlite distinct emulation requires scalar select fields to be simple columns (optionally with AS). Got: ${p}`
3512
+ `sqlite distinct emulation: unterminated quoted identifier in: ${s}`
3418
3513
  );
3419
3514
  }
3420
- const actualAlias = m[1];
3421
- if (actualAlias.toLowerCase() !== fromAlias.toLowerCase()) {
3515
+ let i = start;
3516
+ while (i < n) {
3517
+ const c = s.charCodeAt(i);
3518
+ if (c === 32 || c === 9) break;
3519
+ if (c === 46) break;
3520
+ i++;
3521
+ }
3522
+ return { text: s.slice(start, i), next: i, quoted: false };
3523
+ };
3524
+ const skipSpaces = (s, i) => {
3525
+ while (i < s.length) {
3526
+ const c = s.charCodeAt(i);
3527
+ if (c !== 32 && c !== 9) break;
3528
+ i++;
3529
+ }
3530
+ return i;
3531
+ };
3532
+ for (let idx = 0; idx < parts.length; idx++) {
3533
+ const p = parts[idx].trim();
3534
+ if (p.length === 0) continue;
3535
+ let i = 0;
3536
+ i = skipSpaces(p, i);
3537
+ const a = readIdentOrQuoted(p, i);
3538
+ const actualAlias = a.text.toLowerCase();
3539
+ if (!isIdent(a.text)) {
3422
3540
  throw new Error(
3423
- `Expected alias '${fromAlias}', got '${actualAlias}' in: ${p}`
3541
+ `sqlite distinct emulation requires scalar select fields to be simple columns (alias.column). Got: ${p}`
3424
3542
  );
3425
3543
  }
3426
- const columnName = ((_b = (_a = m[2]) != null ? _a : m[3]) != null ? _b : "").trim();
3427
- const outAlias = ((_d = (_c = m[4]) != null ? _c : m[5]) != null ? _d : "").trim();
3428
- const name = outAlias.length > 0 ? outAlias : columnName;
3429
- if (name.length === 0) {
3544
+ if (actualAlias !== fromLower) {
3545
+ throw new Error(`Expected alias '${fromAlias}', got '${a.text}' in: ${p}`);
3546
+ }
3547
+ i = a.next;
3548
+ if (i >= p.length || p.charCodeAt(i) !== 46) {
3549
+ throw new Error(
3550
+ `sqlite distinct emulation requires scalar select fields to be simple columns (alias.column). Got: ${p}`
3551
+ );
3552
+ }
3553
+ i++;
3554
+ i = skipSpaces(p, i);
3555
+ const colPart = readIdentOrQuoted(p, i);
3556
+ const columnName = colPart.text.trim();
3557
+ if (columnName.length === 0) {
3430
3558
  throw new Error(`Failed to parse selected column name from: ${p}`);
3431
3559
  }
3560
+ i = colPart.next;
3561
+ i = skipSpaces(p, i);
3562
+ let outAlias = "";
3563
+ if (i < p.length) {
3564
+ const rest = p.slice(i).trim();
3565
+ if (rest.length > 0) {
3566
+ const m = rest.match(/^AS\s+/i);
3567
+ if (!m) {
3568
+ throw new Error(
3569
+ `sqlite distinct emulation requires scalar select fields to be simple columns (optionally with AS). Got: ${p}`
3570
+ );
3571
+ }
3572
+ let j = i;
3573
+ j = skipSpaces(p, j);
3574
+ if (!/^AS\b/i.test(p.slice(j))) {
3575
+ throw new Error(`Failed to parse AS in: ${p}`);
3576
+ }
3577
+ j += 2;
3578
+ j = skipSpaces(p, j);
3579
+ const out = readIdentOrQuoted(p, j);
3580
+ outAlias = out.text.trim();
3581
+ if (outAlias.length === 0) {
3582
+ throw new Error(`Failed to parse output alias from: ${p}`);
3583
+ }
3584
+ j = skipSpaces(p, out.next);
3585
+ if (j !== p.length) {
3586
+ throw new Error(
3587
+ `sqlite distinct emulation requires scalar select fields to be simple columns (optionally with AS). Got: ${p}`
3588
+ );
3589
+ }
3590
+ }
3591
+ }
3592
+ const name = outAlias.length > 0 ? outAlias : columnName;
3432
3593
  names.push(name);
3433
3594
  }
3434
3595
  return names;
@@ -3438,15 +3599,14 @@ function replaceOrderByAlias(orderBy, fromAlias, outerAlias) {
3438
3599
  if (src.length === 0) return orderBy;
3439
3600
  const escaped = src.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3440
3601
  const re = new RegExp(`\\b${escaped}\\.`, "gi");
3441
- return orderBy.replace(re, `${outerAlias}.`);
3602
+ return orderBy.replace(re, outerAlias + ".");
3442
3603
  }
3443
3604
  function buildDistinctColumns(distinct, fromAlias, model) {
3444
3605
  return distinct.map((f) => col(fromAlias, f, model)).join(SQL_SEPARATORS.FIELD_LIST);
3445
3606
  }
3446
3607
  function buildOutputColumns(scalarNames, includeNames, hasCount) {
3447
- const outputCols = [...scalarNames, ...includeNames];
3448
- if (hasCount) outputCols.push("_count");
3449
- const formatted = outputCols.map((n) => quote(n)).join(SQL_SEPARATORS.FIELD_LIST);
3608
+ const outputCols = hasCount ? [...scalarNames, ...includeNames, "_count"] : [...scalarNames, ...includeNames];
3609
+ const formatted = outputCols.map((n) => quote2(n)).join(SQL_SEPARATORS.FIELD_LIST);
3450
3610
  if (!isNonEmptyString(formatted)) {
3451
3611
  throw new Error("distinct emulation requires at least one output column");
3452
3612
  }
@@ -3457,11 +3617,11 @@ function buildWindowOrder(args) {
3457
3617
  const fromLower = String(fromAlias).toLowerCase();
3458
3618
  const orderFields = baseOrder.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim().toLowerCase());
3459
3619
  const hasIdInOrder = orderFields.some(
3460
- (f) => f.startsWith(`${fromLower}.id `) || f.startsWith(`${fromLower}."id" `)
3620
+ (f) => f.startsWith(fromLower + ".id ") || f.startsWith(fromLower + '."id" ')
3461
3621
  );
3462
3622
  if (hasIdInOrder) return baseOrder;
3463
- const idTiebreaker = idField ? `, ${col(fromAlias, "id", model)} ASC` : "";
3464
- return `${baseOrder}${idTiebreaker}`;
3623
+ const idTiebreaker = idField ? ", " + col(fromAlias, "id", model) + " ASC" : "";
3624
+ return baseOrder + idTiebreaker;
3465
3625
  }
3466
3626
  function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3467
3627
  var _a, _b;
@@ -3478,7 +3638,7 @@ function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3478
3638
  hasCount
3479
3639
  );
3480
3640
  const distinctCols = buildDistinctColumns([...distinct], from.alias, model);
3481
- const fallbackOrder = [...distinct].map((f) => `${col(from.alias, f, model)} ASC`).join(SQL_SEPARATORS.FIELD_LIST);
3641
+ const fallbackOrder = [...distinct].map((f) => col(from.alias, f, model) + " ASC").join(SQL_SEPARATORS.FIELD_LIST);
3482
3642
  const idField = model.fields.find(
3483
3643
  (f) => f.name === "id" && !f.isRelation
3484
3644
  );
@@ -3489,7 +3649,7 @@ function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3489
3649
  fromAlias: from.alias,
3490
3650
  model
3491
3651
  });
3492
- const outerOrder = isNonEmptyString(orderBy) ? replaceOrderByAlias(orderBy, from.alias, `"__tp_distinct"`) : replaceOrderByAlias(fallbackOrder, from.alias, `"__tp_distinct"`);
3652
+ const outerOrder = isNonEmptyString(orderBy) ? replaceOrderByAlias(orderBy, from.alias, '"__tp_distinct"') : replaceOrderByAlias(fallbackOrder, from.alias, '"__tp_distinct"');
3493
3653
  const joins = buildJoinsSql(whereJoins, countJoins);
3494
3654
  const conditions = [];
3495
3655
  if (whereClause && whereClause !== "1=1") conditions.push(whereClause);
@@ -3499,7 +3659,7 @@ function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3499
3659
  const innerParts = [
3500
3660
  SQL_TEMPLATES.SELECT,
3501
3661
  innerSelectList + innerComma,
3502
- `ROW_NUMBER() OVER (PARTITION BY ${distinctCols} ORDER BY ${windowOrder})`,
3662
+ "ROW_NUMBER() OVER (PARTITION BY " + distinctCols + " ORDER BY " + windowOrder + ")",
3503
3663
  SQL_TEMPLATES.AS,
3504
3664
  '"__tp_rn"',
3505
3665
  SQL_TEMPLATES.FROM,
@@ -3508,12 +3668,12 @@ function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3508
3668
  ];
3509
3669
  if (joins) innerParts.push(joins);
3510
3670
  if (whereSql) innerParts.push(whereSql);
3511
- const inner = innerParts.filter(Boolean).join(" ");
3671
+ const inner = innerParts.join(" ");
3512
3672
  const outerParts = [
3513
3673
  SQL_TEMPLATES.SELECT,
3514
3674
  outerSelectCols,
3515
3675
  SQL_TEMPLATES.FROM,
3516
- `(${inner})`,
3676
+ "(" + inner + ")",
3517
3677
  SQL_TEMPLATES.AS,
3518
3678
  '"__tp_distinct"',
3519
3679
  SQL_TEMPLATES.WHERE,
@@ -3522,7 +3682,7 @@ function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
3522
3682
  if (isNonEmptyString(outerOrder)) {
3523
3683
  outerParts.push(SQL_TEMPLATES.ORDER_BY, outerOrder);
3524
3684
  }
3525
- return outerParts.filter(Boolean).join(" ");
3685
+ return outerParts.join(" ");
3526
3686
  }
3527
3687
  function buildIncludeColumns(spec) {
3528
3688
  var _a, _b;
@@ -3542,7 +3702,7 @@ function buildIncludeColumns(spec) {
3542
3702
  dialect
3543
3703
  );
3544
3704
  if (countBuild.jsonPairs) {
3545
- countCols = `${jsonBuildObject(countBuild.jsonPairs, dialect)} ${SQL_TEMPLATES.AS} ${quote("_count")}`;
3705
+ countCols = jsonBuildObject(countBuild.jsonPairs, dialect) + " " + SQL_TEMPLATES.AS + " " + quote2("_count");
3546
3706
  }
3547
3707
  countJoins = countBuild.joins;
3548
3708
  }
@@ -3554,8 +3714,8 @@ function buildIncludeColumns(spec) {
3554
3714
  }
3555
3715
  const emptyJson = dialect === "postgres" ? `'[]'::json` : `json('[]')`;
3556
3716
  const includeCols = hasIncludes ? includes.map((inc) => {
3557
- const expr = inc.isOneToOne ? `(${inc.sql})` : `COALESCE((${inc.sql}), ${emptyJson})`;
3558
- return `${expr} ${SQL_TEMPLATES.AS} ${quote(inc.name)}`;
3717
+ const expr = inc.isOneToOne ? "(" + inc.sql + ")" : "COALESCE((" + inc.sql + "), " + emptyJson + ")";
3718
+ return expr + " " + SQL_TEMPLATES.AS + " " + quote2(inc.name);
3559
3719
  }).join(SQL_SEPARATORS.FIELD_LIST) : "";
3560
3720
  const allCols = joinNonEmpty(
3561
3721
  [includeCols, countCols],
@@ -3623,7 +3783,7 @@ function withCountJoins(spec, countJoins, whereJoins) {
3623
3783
  function buildPostgresDistinctOnClause(fromAlias, distinct, model) {
3624
3784
  if (!isNonEmptyArray(distinct)) return null;
3625
3785
  const distinctCols = buildDistinctColumns([...distinct], fromAlias, model);
3626
- return `${SQL_TEMPLATES.DISTINCT_ON} (${distinctCols})`;
3786
+ return SQL_TEMPLATES.DISTINCT_ON + " (" + distinctCols + ")";
3627
3787
  }
3628
3788
  function pushJoinGroups(parts, ...groups) {
3629
3789
  for (const g of groups) {
@@ -3668,9 +3828,7 @@ function constructFinalSql(spec) {
3668
3828
  return finalizeSql(sql2, params, dialect);
3669
3829
  }
3670
3830
  const parts = [];
3671
- if (cursorCte) {
3672
- parts.push(`WITH ${cursorCte}`);
3673
- }
3831
+ if (cursorCte) parts.push("WITH " + cursorCte);
3674
3832
  parts.push(SQL_TEMPLATES.SELECT);
3675
3833
  const distinctOn = dialect === "postgres" ? buildPostgresDistinctOnClause(from.alias, distinct, model) : null;
3676
3834
  if (distinctOn) parts.push(distinctOn);
@@ -3681,6 +3839,10 @@ function constructFinalSql(spec) {
3681
3839
  }
3682
3840
  parts.push(fullSelectList);
3683
3841
  parts.push(SQL_TEMPLATES.FROM, from.table, from.alias);
3842
+ if (cursorCte) {
3843
+ const cteName = cursorCte.split(" AS ")[0].trim();
3844
+ parts.push("CROSS JOIN", cteName);
3845
+ }
3684
3846
  pushJoinGroups(parts, whereJoins, countJoins);
3685
3847
  const conditions = buildConditions(whereClause, cursorClause);
3686
3848
  pushWhere(parts, conditions);
@@ -3903,14 +4065,16 @@ function buildSelectSql(input) {
3903
4065
  }
3904
4066
 
3905
4067
  // src/builder/shared/comparison-builder.ts
3906
- function buildComparisons(expr, filter, params, dialect, builder, excludeKeys = /* @__PURE__ */ new Set(["mode"])) {
4068
+ var DEFAULT_EXCLUDE_KEYS = /* @__PURE__ */ new Set(["mode"]);
4069
+ function buildComparisons(expr, filter, params, dialect, builder, excludeKeys = DEFAULT_EXCLUDE_KEYS) {
3907
4070
  const out = [];
3908
- for (const [op, val] of Object.entries(filter)) {
3909
- if (excludeKeys.has(op) || val === void 0) continue;
4071
+ for (const op in filter) {
4072
+ if (!Object.prototype.hasOwnProperty.call(filter, op)) continue;
4073
+ if (excludeKeys.has(op)) continue;
4074
+ const val = filter[op];
4075
+ if (val === void 0) continue;
3910
4076
  const built = builder(expr, op, val, params, dialect);
3911
- if (built && built.trim().length > 0) {
3912
- out.push(built);
3913
- }
4077
+ if (built && built.trim().length > 0) out.push(built);
3914
4078
  }
3915
4079
  return out;
3916
4080
  }
@@ -3940,6 +4104,13 @@ var HAVING_ALLOWED_OPS = /* @__PURE__ */ new Set([
3940
4104
  Ops.IN,
3941
4105
  Ops.NOT_IN
3942
4106
  ]);
4107
+ var HAVING_FIELD_FIRST_AGG_KEYS = Object.freeze([
4108
+ "_count",
4109
+ "_sum",
4110
+ "_avg",
4111
+ "_min",
4112
+ "_max"
4113
+ ]);
3943
4114
  function isTruthySelection(v) {
3944
4115
  return v === true;
3945
4116
  }
@@ -3958,15 +4129,15 @@ function assertHavingOp(op) {
3958
4129
  }
3959
4130
  function aggExprForField(aggKey, field, alias, model) {
3960
4131
  if (aggKey === "_count") {
3961
- return field === "_all" ? `COUNT(*)` : `COUNT(${col(alias, field, model)})`;
4132
+ return field === "_all" ? "COUNT(*)" : "COUNT(" + col(alias, field, model) + ")";
3962
4133
  }
3963
4134
  if (field === "_all") {
3964
4135
  throw new Error(`'${aggKey}' does not support '_all'`);
3965
4136
  }
3966
- if (aggKey === "_sum") return `SUM(${col(alias, field, model)})`;
3967
- if (aggKey === "_avg") return `AVG(${col(alias, field, model)})`;
3968
- if (aggKey === "_min") return `MIN(${col(alias, field, model)})`;
3969
- return `MAX(${col(alias, field, model)})`;
4137
+ if (aggKey === "_sum") return "SUM(" + col(alias, field, model) + ")";
4138
+ if (aggKey === "_avg") return "AVG(" + col(alias, field, model) + ")";
4139
+ if (aggKey === "_min") return "MIN(" + col(alias, field, model) + ")";
4140
+ return "MAX(" + col(alias, field, model) + ")";
3970
4141
  }
3971
4142
  function buildComparisonOp(op) {
3972
4143
  const sqlOp = COMPARISON_OPS[op];
@@ -3993,8 +4164,8 @@ function normalizeLogicalValue2(operator, value) {
3993
4164
  throw new Error(`${operator} must be an object or array of objects in HAVING`);
3994
4165
  }
3995
4166
  function buildNullComparison(expr, op) {
3996
- if (op === Ops.EQUALS) return `${expr} ${SQL_TEMPLATES.IS_NULL}`;
3997
- if (op === Ops.NOT) return `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
4167
+ if (op === Ops.EQUALS) return expr + " " + SQL_TEMPLATES.IS_NULL;
4168
+ if (op === Ops.NOT) return expr + " " + SQL_TEMPLATES.IS_NOT_NULL;
3998
4169
  throw new Error(`Operator '${op}' doesn't support null in HAVING`);
3999
4170
  }
4000
4171
  function buildInComparison(expr, op, val, params, dialect) {
@@ -4015,7 +4186,7 @@ function buildInComparison(expr, op, val, params, dialect) {
4015
4186
  function buildBinaryComparison(expr, op, val, params) {
4016
4187
  const sqlOp = buildComparisonOp(op);
4017
4188
  const placeholder = addHavingParam(params, op, val);
4018
- return `${expr} ${sqlOp} ${placeholder}`;
4189
+ return expr + " " + sqlOp + " " + placeholder;
4019
4190
  }
4020
4191
  function buildSimpleComparison(expr, op, val, params, dialect) {
4021
4192
  assertHavingOp(op);
@@ -4036,20 +4207,21 @@ function buildSimpleComparison(expr, op, val, params, dialect) {
4036
4207
  return buildBinaryComparison(expr, op, val, params);
4037
4208
  }
4038
4209
  function negateClauses(subClauses) {
4039
- if (subClauses.length === 1) return `${SQL_TEMPLATES.NOT} ${subClauses[0]}`;
4040
- return `${SQL_TEMPLATES.NOT} (${subClauses.join(SQL_SEPARATORS.CONDITION_AND)})`;
4210
+ if (subClauses.length === 1) return SQL_TEMPLATES.NOT + " " + subClauses[0];
4211
+ return SQL_TEMPLATES.NOT + " (" + subClauses.join(SQL_SEPARATORS.CONDITION_AND) + ")";
4041
4212
  }
4042
4213
  function combineLogical(key, subClauses) {
4043
4214
  if (key === LogicalOps.NOT) return negateClauses(subClauses);
4044
- return subClauses.join(` ${key} `);
4215
+ return subClauses.join(" " + key + " ");
4045
4216
  }
4046
4217
  function buildHavingNode(node, alias, params, dialect, model) {
4047
4218
  const clauses = [];
4048
- const entries = Object.entries(node);
4049
- for (const [key, value] of entries) {
4219
+ for (const key in node) {
4220
+ if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
4221
+ const value = node[key];
4050
4222
  const built = buildHavingEntry(key, value, alias, params, dialect, model);
4051
4223
  for (const c of built) {
4052
- if (c && c.trim().length > 0) clauses.push(c);
4224
+ if (c && c.length > 0) clauses.push(c);
4053
4225
  }
4054
4226
  }
4055
4227
  return clauses.join(SQL_SEPARATORS.CONDITION_AND);
@@ -4059,7 +4231,7 @@ function buildLogicalClause2(key, value, alias, params, dialect, model) {
4059
4231
  const subClauses = [];
4060
4232
  for (const it of items) {
4061
4233
  const c = buildHavingNode(it, alias, params, dialect, model);
4062
- if (c && c.trim().length > 0) subClauses.push(`(${c})`);
4234
+ if (c && c.length > 0) subClauses.push("(" + c + ")");
4063
4235
  }
4064
4236
  if (subClauses.length === 0) return "";
4065
4237
  return combineLogical(key, subClauses);
@@ -4084,11 +4256,23 @@ function buildHavingForAggregateFirstShape(aggKey, target, alias, params, dialec
4084
4256
  throw new Error(`HAVING '${aggKey}' must be an object`);
4085
4257
  }
4086
4258
  const out = [];
4087
- for (const [field, filter] of Object.entries(target)) {
4259
+ const targetObj = target;
4260
+ for (const field in targetObj) {
4261
+ if (!Object.prototype.hasOwnProperty.call(targetObj, field)) continue;
4088
4262
  assertHavingAggTarget(aggKey, field, model);
4089
- if (!isPlainObject(filter) || Object.keys(filter).length === 0) continue;
4263
+ const filter = targetObj[field];
4264
+ if (!isPlainObject(filter)) continue;
4265
+ const filterObj = filter;
4266
+ let hasAny = false;
4267
+ for (const k in filterObj) {
4268
+ if (Object.prototype.hasOwnProperty.call(filterObj, k)) {
4269
+ hasAny = true;
4270
+ break;
4271
+ }
4272
+ }
4273
+ if (!hasAny) continue;
4090
4274
  const expr = aggExprForField(aggKey, field, alias, model);
4091
- out.push(...buildHavingOpsForExpr(expr, filter, params, dialect));
4275
+ out.push(...buildHavingOpsForExpr(expr, filterObj, params, dialect));
4092
4276
  }
4093
4277
  return out;
4094
4278
  }
@@ -4099,16 +4283,23 @@ function buildHavingForFieldFirstShape(fieldName, target, alias, params, dialect
4099
4283
  assertScalarField(model, fieldName, "HAVING");
4100
4284
  const out = [];
4101
4285
  const obj = target;
4102
- const keys = ["_count", "_sum", "_avg", "_min", "_max"];
4103
- for (const aggKey of keys) {
4286
+ for (const aggKey of HAVING_FIELD_FIRST_AGG_KEYS) {
4104
4287
  const aggFilter = obj[aggKey];
4105
4288
  if (!isPlainObject(aggFilter)) continue;
4106
- if (Object.keys(aggFilter).length === 0) continue;
4289
+ const aggFilterObj = aggFilter;
4290
+ let hasAny = false;
4291
+ for (const k in aggFilterObj) {
4292
+ if (Object.prototype.hasOwnProperty.call(aggFilterObj, k)) {
4293
+ hasAny = true;
4294
+ break;
4295
+ }
4296
+ }
4297
+ if (!hasAny) continue;
4107
4298
  if (aggKey === "_sum" || aggKey === "_avg") {
4108
4299
  assertNumericField(model, fieldName, "HAVING");
4109
4300
  }
4110
4301
  const expr = aggExprForField(aggKey, fieldName, alias, model);
4111
- out.push(...buildHavingOpsForExpr(expr, aggFilter, params, dialect));
4302
+ out.push(...buildHavingOpsForExpr(expr, aggFilterObj, params, dialect));
4112
4303
  }
4113
4304
  return out;
4114
4305
  }
@@ -4157,13 +4348,13 @@ function normalizeCountArg(v) {
4157
4348
  }
4158
4349
  function pushCountAllField(fields) {
4159
4350
  fields.push(
4160
- `${SQL_TEMPLATES.COUNT_ALL} ${SQL_TEMPLATES.AS} ${quote("_count._all")}`
4351
+ SQL_TEMPLATES.COUNT_ALL + " " + SQL_TEMPLATES.AS + " " + quote2("_count._all")
4161
4352
  );
4162
4353
  }
4163
4354
  function pushCountField(fields, alias, fieldName, model) {
4164
- const outAlias = `_count.${fieldName}`;
4355
+ const outAlias = "_count." + fieldName;
4165
4356
  fields.push(
4166
- `COUNT(${col(alias, fieldName, model)}) ${SQL_TEMPLATES.AS} ${quote(outAlias)}`
4357
+ "COUNT(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote2(outAlias)
4167
4358
  );
4168
4359
  }
4169
4360
  function addCountFields(fields, countArg, alias, model) {
@@ -4176,12 +4367,14 @@ function addCountFields(fields, countArg, alias, model) {
4176
4367
  if (countArg._all === true) {
4177
4368
  pushCountAllField(fields);
4178
4369
  }
4179
- const selected = Object.entries(countArg).filter(
4180
- ([f, v]) => f !== "_all" && isTruthySelection(v)
4181
- );
4182
- for (const [f] of selected) {
4183
- assertScalarField(model, f, "_count");
4184
- pushCountField(fields, alias, f, model);
4370
+ for (const f in countArg) {
4371
+ if (!Object.prototype.hasOwnProperty.call(countArg, f)) continue;
4372
+ if (f === "_all") continue;
4373
+ const v = countArg[f];
4374
+ if (isTruthySelection(v)) {
4375
+ assertScalarField(model, f, "_count");
4376
+ pushCountField(fields, alias, f, model);
4377
+ }
4185
4378
  }
4186
4379
  }
4187
4380
  function getAggregateSelectionObject(args, agg) {
@@ -4196,16 +4389,18 @@ function assertAggregatableScalarField(model, agg, fieldName) {
4196
4389
  }
4197
4390
  }
4198
4391
  function pushAggregateFieldSql(fields, aggFn, alias, agg, fieldName, model) {
4199
- const outAlias = `${agg}.${fieldName}`;
4392
+ const outAlias = agg + "." + fieldName;
4200
4393
  fields.push(
4201
- `${aggFn}(${col(alias, fieldName, model)}) ${SQL_TEMPLATES.AS} ${quote(outAlias)}`
4394
+ aggFn + "(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote2(outAlias)
4202
4395
  );
4203
4396
  }
4204
4397
  function addAggregateFields(fields, args, alias, model) {
4205
4398
  for (const [agg, aggFn] of AGGREGATES) {
4206
4399
  const obj = getAggregateSelectionObject(args, agg);
4207
4400
  if (!obj) continue;
4208
- for (const [fieldName, selection] of Object.entries(obj)) {
4401
+ for (const fieldName in obj) {
4402
+ if (!Object.prototype.hasOwnProperty.call(obj, fieldName)) continue;
4403
+ const selection = obj[fieldName];
4209
4404
  if (fieldName === "_all")
4210
4405
  throw new Error(`'${agg}' does not support '_all'`);
4211
4406
  if (!isTruthySelection(selection)) continue;
@@ -4229,22 +4424,23 @@ function buildAggregateSql(args, whereResult, tableName, alias, model) {
4229
4424
  throw new Error("buildAggregateSql requires at least one aggregate field");
4230
4425
  }
4231
4426
  const selectClause = aggFields.join(SQL_SEPARATORS.FIELD_LIST);
4232
- const whereClause = isValidWhereClause(whereResult.clause) ? `${SQL_TEMPLATES.WHERE} ${whereResult.clause}` : "";
4233
- const sql = [
4427
+ const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
4428
+ const parts = [
4234
4429
  SQL_TEMPLATES.SELECT,
4235
4430
  selectClause,
4236
4431
  SQL_TEMPLATES.FROM,
4237
4432
  tableName,
4238
- alias,
4239
- whereClause
4240
- ].filter((x) => x && String(x).trim().length > 0).join(" ").trim();
4433
+ alias
4434
+ ];
4435
+ if (whereClause) parts.push(whereClause);
4436
+ const sql = parts.join(" ").trim();
4241
4437
  validateSelectQuery(sql);
4242
4438
  validateParamConsistency(sql, whereResult.params);
4243
- return Object.freeze({
4439
+ return {
4244
4440
  sql,
4245
- params: Object.freeze([...whereResult.params]),
4246
- paramMappings: Object.freeze([...whereResult.paramMappings])
4247
- });
4441
+ params: whereResult.params,
4442
+ paramMappings: whereResult.paramMappings
4443
+ };
4248
4444
  }
4249
4445
  function assertGroupByBy(args, model) {
4250
4446
  if (!isNotNullish(args.by) || !isNonEmptyArray(args.by)) {
@@ -4272,8 +4468,8 @@ function buildGroupByHaving(args, alias, params, model, dialect) {
4272
4468
  if (!isNotNullish(args.having)) return "";
4273
4469
  if (!isPlainObject(args.having)) throw new Error("having must be an object");
4274
4470
  const h = buildHavingClause(args.having, alias, params, model, dialect);
4275
- if (!h || h.trim().length === 0) return "";
4276
- return `${SQL_TEMPLATES.HAVING} ${h}`;
4471
+ if (!h || h.length === 0) return "";
4472
+ return SQL_TEMPLATES.HAVING + " " + h;
4277
4473
  }
4278
4474
  function buildGroupBySql(args, whereResult, tableName, alias, model, dialect) {
4279
4475
  assertSafeAlias(alias);
@@ -4288,29 +4484,28 @@ function buildGroupBySql(args, whereResult, tableName, alias, model, dialect) {
4288
4484
  byFields
4289
4485
  );
4290
4486
  const havingClause = buildGroupByHaving(args, alias, params, model, d);
4291
- const whereClause = isValidWhereClause(whereResult.clause) ? `${SQL_TEMPLATES.WHERE} ${whereResult.clause}` : "";
4292
- const sql = [
4487
+ const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
4488
+ const parts = [
4293
4489
  SQL_TEMPLATES.SELECT,
4294
4490
  selectFields,
4295
4491
  SQL_TEMPLATES.FROM,
4296
4492
  tableName,
4297
- alias,
4298
- whereClause,
4299
- SQL_TEMPLATES.GROUP_BY,
4300
- groupFields,
4301
- havingClause
4302
- ].filter((x) => x && String(x).trim().length > 0).join(" ").trim();
4493
+ alias
4494
+ ];
4495
+ if (whereClause) parts.push(whereClause);
4496
+ parts.push(SQL_TEMPLATES.GROUP_BY, groupFields);
4497
+ if (havingClause) parts.push(havingClause);
4498
+ const sql = parts.join(" ").trim();
4303
4499
  const snapshot = params.snapshot();
4500
+ const allParams = [...whereResult.params, ...snapshot.params];
4501
+ const allMappings = [...whereResult.paramMappings, ...snapshot.mappings];
4304
4502
  validateSelectQuery(sql);
4305
- validateParamConsistency(sql, [...whereResult.params, ...snapshot.params]);
4306
- return Object.freeze({
4503
+ validateParamConsistency(sql, allParams);
4504
+ return {
4307
4505
  sql,
4308
- params: Object.freeze([...whereResult.params, ...snapshot.params]),
4309
- paramMappings: Object.freeze([
4310
- ...whereResult.paramMappings,
4311
- ...snapshot.mappings
4312
- ])
4313
- });
4506
+ params: allParams,
4507
+ paramMappings: allMappings
4508
+ };
4314
4509
  }
4315
4510
  function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4316
4511
  assertSafeAlias(alias);
@@ -4338,24 +4533,25 @@ function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4338
4533
  );
4339
4534
  }
4340
4535
  }
4341
- const whereClause = isValidWhereClause(whereResult.clause) ? `${SQL_TEMPLATES.WHERE} ${whereResult.clause}` : "";
4342
- const sql = [
4536
+ const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
4537
+ const parts = [
4343
4538
  SQL_TEMPLATES.SELECT,
4344
4539
  SQL_TEMPLATES.COUNT_ALL,
4345
4540
  SQL_TEMPLATES.AS,
4346
- quote("_count._all"),
4541
+ quote2("_count._all"),
4347
4542
  SQL_TEMPLATES.FROM,
4348
4543
  tableName,
4349
- alias,
4350
- whereClause
4351
- ].filter((x) => x && String(x).trim().length > 0).join(" ").trim();
4544
+ alias
4545
+ ];
4546
+ if (whereClause) parts.push(whereClause);
4547
+ const sql = parts.join(" ").trim();
4352
4548
  validateSelectQuery(sql);
4353
4549
  validateParamConsistency(sql, whereResult.params);
4354
- return Object.freeze({
4550
+ return {
4355
4551
  sql,
4356
- params: Object.freeze([...whereResult.params]),
4357
- paramMappings: Object.freeze([...whereResult.paramMappings])
4358
- });
4552
+ params: whereResult.params,
4553
+ paramMappings: whereResult.paramMappings
4554
+ };
4359
4555
  }
4360
4556
  function safeAlias(input) {
4361
4557
  const raw = String(input).toLowerCase();
@@ -4859,7 +5055,7 @@ function toSqliteParams(sql, params) {
4859
5055
  parts.push(sql.substring(lastIndex));
4860
5056
  return { sql: parts.join(""), params: reorderedParams };
4861
5057
  }
4862
- function canonicalizeQuery(modelName, method, args) {
5058
+ function canonicalizeQuery(modelName, method, args, dialect) {
4863
5059
  function normalize(obj) {
4864
5060
  if (obj === null || obj === void 0) return obj;
4865
5061
  if (obj instanceof Date) {
@@ -4879,7 +5075,7 @@ function canonicalizeQuery(modelName, method, args) {
4879
5075
  return obj;
4880
5076
  }
4881
5077
  const canonical = normalize(args);
4882
- return `${modelName}:${method}:${JSON.stringify(canonical)}`;
5078
+ return `${dialect}:${modelName}:${method}:${JSON.stringify(canonical)}`;
4883
5079
  }
4884
5080
  function buildSQLFull(model, models, method, args, dialect) {
4885
5081
  const tableName = buildTableReference(
@@ -4942,7 +5138,7 @@ function buildSQLFull(model, models, method, args, dialect) {
4942
5138
  return dialect === "sqlite" ? toSqliteParams(result.sql, result.params) : { sql: result.sql, params: [...result.params] };
4943
5139
  }
4944
5140
  function buildSQLWithCache(model, models, method, args, dialect) {
4945
- const cacheKey = canonicalizeQuery(model.name, method, args);
5141
+ const cacheKey = canonicalizeQuery(model.name, method, args, dialect);
4946
5142
  const cachedSql = queryCache.get(cacheKey);
4947
5143
  if (cachedSql) {
4948
5144
  const result2 = buildSQLFull(model, models, method, args, dialect);
@@ -4950,6 +5146,7 @@ function buildSQLWithCache(model, models, method, args, dialect) {
4950
5146
  }
4951
5147
  const result = buildSQLFull(model, models, method, args, dialect);
4952
5148
  queryCache.set(cacheKey, result.sql);
5149
+ queryCache.size;
4953
5150
  return result;
4954
5151
  }
4955
5152
  var ACCELERATED_METHODS = /* @__PURE__ */ new Set([