prisma-sql 1.57.0 → 1.59.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.js CHANGED
@@ -186,7 +186,8 @@ var REGEX_CACHE = {
186
186
  var LIMITS = Object.freeze({
187
187
  MAX_QUERY_DEPTH: 50,
188
188
  MAX_ARRAY_SIZE: 1e4,
189
- MAX_STRING_LENGTH: 1e4
189
+ MAX_STRING_LENGTH: 1e4,
190
+ MAX_HAVING_DEPTH: 50
190
191
  });
191
192
 
192
193
  // src/utils/normalize-value.ts
@@ -249,6 +250,15 @@ function setGlobalDialect(dialect) {
249
250
  function getGlobalDialect() {
250
251
  return globalDialect;
251
252
  }
253
+ function withDialect(dialect, fn) {
254
+ const prev = globalDialect;
255
+ globalDialect = dialect;
256
+ try {
257
+ return fn();
258
+ } finally {
259
+ globalDialect = prev;
260
+ }
261
+ }
252
262
  function assertNonEmpty(value, name) {
253
263
  if (!value || value.trim().length === 0) {
254
264
  throw new Error(`${name} is required and cannot be empty`);
@@ -483,73 +493,6 @@ function createError(message, ctx, code = "VALIDATION_ERROR") {
483
493
  return new SqlBuilderError(parts.join("\n"), code, ctx);
484
494
  }
485
495
 
486
- // src/builder/shared/model-field-cache.ts
487
- var MODEL_CACHE = /* @__PURE__ */ new WeakMap();
488
- function quote(id) {
489
- 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(
490
- id
491
- );
492
- if (needsQuoting2) {
493
- return `"${id.replace(/"/g, '""')}"`;
494
- }
495
- return id;
496
- }
497
- function ensureFullCache(model) {
498
- let cache = MODEL_CACHE.get(model);
499
- if (!cache) {
500
- const fieldInfo = /* @__PURE__ */ new Map();
501
- const scalarFields = /* @__PURE__ */ new Set();
502
- const relationFields = /* @__PURE__ */ new Set();
503
- const columnMap = /* @__PURE__ */ new Map();
504
- const fieldByName = /* @__PURE__ */ new Map();
505
- const quotedColumns = /* @__PURE__ */ new Map();
506
- for (const f of model.fields) {
507
- const info = {
508
- name: f.name,
509
- dbName: f.dbName || f.name,
510
- type: f.type,
511
- isRelation: !!f.isRelation,
512
- isRequired: !!f.isRequired
513
- };
514
- fieldInfo.set(f.name, info);
515
- fieldByName.set(f.name, f);
516
- if (info.isRelation) {
517
- relationFields.add(f.name);
518
- } else {
519
- scalarFields.add(f.name);
520
- const dbName = info.dbName;
521
- columnMap.set(f.name, dbName);
522
- quotedColumns.set(f.name, quote(dbName));
523
- }
524
- }
525
- cache = {
526
- fieldInfo,
527
- scalarFields,
528
- relationFields,
529
- columnMap,
530
- fieldByName,
531
- quotedColumns
532
- };
533
- MODEL_CACHE.set(model, cache);
534
- }
535
- return cache;
536
- }
537
- function getFieldInfo(model, fieldName) {
538
- return ensureFullCache(model).fieldInfo.get(fieldName);
539
- }
540
- function getScalarFieldSet(model) {
541
- return ensureFullCache(model).scalarFields;
542
- }
543
- function getRelationFieldSet(model) {
544
- return ensureFullCache(model).relationFields;
545
- }
546
- function getColumnMap(model) {
547
- return ensureFullCache(model).columnMap;
548
- }
549
- function getQuotedColumn(model, fieldName) {
550
- return ensureFullCache(model).quotedColumns.get(fieldName);
551
- }
552
-
553
496
  // src/builder/shared/validators/sql-validators.ts
554
497
  function isValidWhereClause(clause) {
555
498
  return isNotNullish(clause) && clause.trim().length > 0 && clause !== DEFAULT_WHERE_CLAUSE;
@@ -693,6 +636,78 @@ function needsQuoting(identifier) {
693
636
  return false;
694
637
  }
695
638
 
639
+ // src/builder/shared/model-field-cache.ts
640
+ var MODEL_CACHE = /* @__PURE__ */ new WeakMap();
641
+ function quoteIdent(id) {
642
+ if (typeof id !== "string" || id.trim().length === 0) {
643
+ throw new Error("quoteIdent: identifier is required and cannot be empty");
644
+ }
645
+ if (/[\u0000-\u001F\u007F]/.test(id)) {
646
+ throw new Error(
647
+ `quoteIdent: identifier contains invalid characters: ${JSON.stringify(id)}`
648
+ );
649
+ }
650
+ if (needsQuoting(id)) {
651
+ return `"${id.replace(/"/g, '""')}"`;
652
+ }
653
+ return id;
654
+ }
655
+ function ensureFullCache(model) {
656
+ let cache = MODEL_CACHE.get(model);
657
+ if (!cache) {
658
+ const fieldInfo = /* @__PURE__ */ new Map();
659
+ const scalarFields = /* @__PURE__ */ new Set();
660
+ const relationFields = /* @__PURE__ */ new Set();
661
+ const columnMap = /* @__PURE__ */ new Map();
662
+ const fieldByName = /* @__PURE__ */ new Map();
663
+ const quotedColumns = /* @__PURE__ */ new Map();
664
+ for (const f of model.fields) {
665
+ const info = {
666
+ name: f.name,
667
+ dbName: f.dbName || f.name,
668
+ type: f.type,
669
+ isRelation: !!f.isRelation,
670
+ isRequired: !!f.isRequired
671
+ };
672
+ fieldInfo.set(f.name, info);
673
+ fieldByName.set(f.name, f);
674
+ if (info.isRelation) {
675
+ relationFields.add(f.name);
676
+ } else {
677
+ scalarFields.add(f.name);
678
+ const dbName = info.dbName;
679
+ columnMap.set(f.name, dbName);
680
+ quotedColumns.set(f.name, quoteIdent(dbName));
681
+ }
682
+ }
683
+ cache = {
684
+ fieldInfo,
685
+ scalarFields,
686
+ relationFields,
687
+ columnMap,
688
+ fieldByName,
689
+ quotedColumns
690
+ };
691
+ MODEL_CACHE.set(model, cache);
692
+ }
693
+ return cache;
694
+ }
695
+ function getFieldInfo(model, fieldName) {
696
+ return ensureFullCache(model).fieldInfo.get(fieldName);
697
+ }
698
+ function getScalarFieldSet(model) {
699
+ return ensureFullCache(model).scalarFields;
700
+ }
701
+ function getRelationFieldSet(model) {
702
+ return ensureFullCache(model).relationFields;
703
+ }
704
+ function getColumnMap(model) {
705
+ return ensureFullCache(model).columnMap;
706
+ }
707
+ function getQuotedColumn(model, fieldName) {
708
+ return ensureFullCache(model).quotedColumns.get(fieldName);
709
+ }
710
+
696
711
  // src/builder/shared/sql-utils.ts
697
712
  function containsControlChars(s) {
698
713
  return /[\u0000-\u001F\u007F]/.test(s);
@@ -835,7 +850,7 @@ function assertSafeQualifiedName(input) {
835
850
  }
836
851
  }
837
852
  }
838
- function quote2(id) {
853
+ function quote(id) {
839
854
  if (isEmptyString(id)) {
840
855
  throw new Error("quote: identifier is required and cannot be empty");
841
856
  }
@@ -855,13 +870,13 @@ function resolveColumnName(model, fieldName) {
855
870
  return columnMap.get(fieldName) || fieldName;
856
871
  }
857
872
  function quoteColumn(model, fieldName) {
858
- if (!model) return quote2(fieldName);
873
+ if (!model) return quote(fieldName);
859
874
  const cached = getQuotedColumn(model, fieldName);
860
- return cached || quote2(fieldName);
875
+ return cached || quote(fieldName);
861
876
  }
862
877
  function col(alias, field, model) {
863
878
  const columnName = model ? getColumnMap(model).get(field) || field : field;
864
- const quoted = model ? getQuotedColumn(model, field) || quote2(columnName) : quote2(columnName);
879
+ const quoted = model ? getQuotedColumn(model, field) || quote(columnName) : quote(columnName);
865
880
  return alias + "." + quoted;
866
881
  }
867
882
  function colWithAlias(alias, field, model) {
@@ -872,9 +887,9 @@ function colWithAlias(alias, field, model) {
872
887
  throw new Error("colWithAlias: field is required and cannot be empty");
873
888
  }
874
889
  const columnName = resolveColumnName(model, field);
875
- const columnRef = alias + "." + (model ? getQuotedColumn(model, field) || quote2(columnName) : quote2(columnName));
890
+ const columnRef = alias + "." + (model ? getQuotedColumn(model, field) || quote(columnName) : quote(columnName));
876
891
  if (columnName !== field) {
877
- return columnRef + " AS " + quote2(field);
892
+ return columnRef + " AS " + quote(field);
878
893
  }
879
894
  return columnRef;
880
895
  }
@@ -897,7 +912,7 @@ function buildTableReference(schemaName, tableName, dialect) {
897
912
  }
898
913
  const d = dialect != null ? dialect : "postgres";
899
914
  if (d === "sqlite") {
900
- return quote2(tableName);
915
+ return quote(tableName);
901
916
  }
902
917
  if (isEmptyString(schemaName)) {
903
918
  throw new Error(
@@ -1562,6 +1577,7 @@ function buildOrderEntries(orderBy) {
1562
1577
  }
1563
1578
  return entries;
1564
1579
  }
1580
+ var MAX_NOT_DEPTH = 50;
1565
1581
  function buildNotComposite(expr, val, params, dialect, buildOp, separator) {
1566
1582
  const entries = Object.entries(val).filter(
1567
1583
  ([k, v]) => k !== "mode" && v !== void 0
@@ -1576,13 +1592,18 @@ function buildNotComposite(expr, val, params, dialect, buildOp, separator) {
1576
1592
  if (clauses.length === 1) return `${SQL_TEMPLATES.NOT} ${clauses[0]}`;
1577
1593
  return `${SQL_TEMPLATES.NOT} (${clauses.join(separator)})`;
1578
1594
  }
1579
- function buildScalarOperator(expr, op, val, params, mode, fieldType, dialect) {
1595
+ function buildScalarOperator(expr, op, val, params, mode, fieldType, dialect, depth = 0) {
1580
1596
  if (val === void 0) return "";
1597
+ if (depth > MAX_NOT_DEPTH) {
1598
+ throw new Error(
1599
+ `NOT operator nesting too deep (max ${MAX_NOT_DEPTH} levels). This usually indicates a circular reference or adversarial input.`
1600
+ );
1601
+ }
1581
1602
  if (val === null) {
1582
1603
  return handleNullValue(expr, op);
1583
1604
  }
1584
1605
  if (op === Ops.NOT && isPlainObject(val)) {
1585
- return handleNotOperator(expr, val, params, mode, fieldType, dialect);
1606
+ return handleNotOperator(expr, val, params, mode, fieldType, dialect, depth);
1586
1607
  }
1587
1608
  if (op === Ops.NOT) {
1588
1609
  const placeholder = params.addAuto(val);
@@ -1628,7 +1649,7 @@ function normalizeMode(v) {
1628
1649
  if (v === Modes.DEFAULT) return Modes.DEFAULT;
1629
1650
  return void 0;
1630
1651
  }
1631
- function handleNotOperator(expr, val, params, outerMode, fieldType, dialect) {
1652
+ function handleNotOperator(expr, val, params, outerMode, fieldType, dialect, depth = 0) {
1632
1653
  const innerMode = normalizeMode(val.mode);
1633
1654
  const effectiveMode = innerMode != null ? innerMode : outerMode;
1634
1655
  const entries = Object.entries(val).filter(
@@ -1645,7 +1666,8 @@ function handleNotOperator(expr, val, params, outerMode, fieldType, dialect) {
1645
1666
  params,
1646
1667
  effectiveMode,
1647
1668
  fieldType,
1648
- void 0
1669
+ void 0,
1670
+ depth + 1
1649
1671
  );
1650
1672
  if (sub && sub.trim().length > 0) clauses.push(`(${sub})`);
1651
1673
  }
@@ -1658,23 +1680,20 @@ function handleNotOperator(expr, val, params, outerMode, fieldType, dialect) {
1658
1680
  val,
1659
1681
  params,
1660
1682
  dialect,
1661
- (e, subOp, subVal, p, d) => buildScalarOperator(e, subOp, subVal, p, effectiveMode, fieldType, d),
1683
+ (e, subOp, subVal, p, d) => buildScalarOperator(
1684
+ e,
1685
+ subOp,
1686
+ subVal,
1687
+ p,
1688
+ effectiveMode,
1689
+ fieldType,
1690
+ d,
1691
+ depth + 1
1692
+ ),
1662
1693
  ` ${SQL_TEMPLATES.AND} `
1663
1694
  );
1664
1695
  }
1665
- function buildDynamicLikePattern(op, placeholder, dialect) {
1666
- if (dialect === "postgres") {
1667
- switch (op) {
1668
- case Ops.CONTAINS:
1669
- return `('%' || ${placeholder} || '%')`;
1670
- case Ops.STARTS_WITH:
1671
- return `(${placeholder} || '%')`;
1672
- case Ops.ENDS_WITH:
1673
- return `('%' || ${placeholder})`;
1674
- default:
1675
- return placeholder;
1676
- }
1677
- }
1696
+ function buildDynamicLikePattern(op, placeholder) {
1678
1697
  switch (op) {
1679
1698
  case Ops.CONTAINS:
1680
1699
  return `('%' || ${placeholder} || '%')`;
@@ -1690,7 +1709,7 @@ function handleLikeOperator(expr, op, val, params, mode, dialect) {
1690
1709
  if (val === void 0) return "";
1691
1710
  if (isDynamicParameter(val)) {
1692
1711
  const placeholder2 = params.addAuto(val);
1693
- const patternExpr = buildDynamicLikePattern(op, placeholder2, dialect);
1712
+ const patternExpr = buildDynamicLikePattern(op, placeholder2);
1694
1713
  if (mode === Modes.INSENSITIVE) {
1695
1714
  return caseInsensitiveLike(expr, patternExpr, dialect);
1696
1715
  }
@@ -1976,7 +1995,7 @@ function freezeJoins(items) {
1976
1995
  function isListRelation(fieldType) {
1977
1996
  return typeof fieldType === "string" && fieldType.endsWith("[]");
1978
1997
  }
1979
- function buildToOneNullCheck(field, parentAlias, relTable, relAlias, join, wantNull) {
1998
+ function buildToOneNullCheck(field, parentModel, parentAlias, relTable, relAlias, join, wantNull) {
1980
1999
  const isLocal = field.isForeignKeyLocal === true;
1981
2000
  const fkFields = normalizeKeyList(field.foreignKey);
1982
2001
  if (isLocal) {
@@ -1986,8 +2005,7 @@ function buildToOneNullCheck(field, parentAlias, relTable, relAlias, join, wantN
1986
2005
  });
1987
2006
  }
1988
2007
  const parts = fkFields.map((fk) => {
1989
- const safe = fk.replace(/"/g, '""');
1990
- const expr = `${parentAlias}."${safe}"`;
2008
+ const expr = `${parentAlias}.${quoteColumn(parentModel, fk)}`;
1991
2009
  return wantNull ? `${expr} ${SQL_TEMPLATES.IS_NULL}` : `${expr} ${SQL_TEMPLATES.IS_NOT_NULL}`;
1992
2010
  });
1993
2011
  if (parts.length === 1) return parts[0];
@@ -2032,7 +2050,7 @@ function buildListRelationFilters(args) {
2032
2050
  ) || relModel.fields.find((f) => !f.isRelation && f.name === "id");
2033
2051
  if (checkField) {
2034
2052
  const leftJoinSql = `LEFT JOIN ${relTable} ${relAlias} ON ${join}`;
2035
- const whereClause = `${relAlias}.${quote2(checkField.name)} IS NULL`;
2053
+ const whereClause = `${relAlias}.${quote(checkField.name)} IS NULL`;
2036
2054
  return Object.freeze({
2037
2055
  clause: whereClause,
2038
2056
  joins: freezeJoins([leftJoinSql])
@@ -2125,6 +2143,7 @@ function buildToOneRelationFilters(args) {
2125
2143
  const wantNull = filterKey === "is";
2126
2144
  const clause2 = buildToOneNullCheck(
2127
2145
  field,
2146
+ ctx.model,
2128
2147
  ctx.alias,
2129
2148
  relTable,
2130
2149
  relAlias,
@@ -2354,7 +2373,8 @@ function buildWhereInternal(where, ctx, builder) {
2354
2373
  }
2355
2374
  const allJoins = [];
2356
2375
  const clauses = [];
2357
- for (const [key, value] of Object.entries(where)) {
2376
+ for (const key in where) {
2377
+ const value = where[key];
2358
2378
  if (value === void 0) continue;
2359
2379
  const result = buildWhereEntry(key, value, ctx, builder);
2360
2380
  appendResult(result, clauses, allJoins);
@@ -2604,8 +2624,6 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2604
2624
  }
2605
2625
  let dirty = true;
2606
2626
  let cachedSnapshot = null;
2607
- let frozenParams = null;
2608
- let frozenMappings = null;
2609
2627
  function assertCanAdd() {
2610
2628
  if (index > MAX_PARAM_INDEX) {
2611
2629
  throw new Error(
@@ -2657,17 +2675,13 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2657
2675
  }
2658
2676
  function snapshot() {
2659
2677
  if (!dirty && cachedSnapshot) return cachedSnapshot;
2660
- if (!frozenParams) frozenParams = Object.freeze(params.slice());
2661
- if (!frozenMappings) frozenMappings = Object.freeze(mappings.slice());
2662
2678
  const snap = {
2663
2679
  index,
2664
- params: frozenParams,
2665
- mappings: frozenMappings
2680
+ params: params.slice(),
2681
+ mappings: mappings.slice()
2666
2682
  };
2667
2683
  cachedSnapshot = snap;
2668
2684
  dirty = false;
2669
- frozenParams = null;
2670
- frozenMappings = null;
2671
2685
  return snap;
2672
2686
  }
2673
2687
  return {
@@ -3597,7 +3611,7 @@ function buildDistinctColumns(distinct, fromAlias, model) {
3597
3611
  }
3598
3612
  function buildOutputColumns(scalarNames, includeNames, hasCount) {
3599
3613
  const outputCols = hasCount ? [...scalarNames, ...includeNames, "_count"] : [...scalarNames, ...includeNames];
3600
- const formatted = outputCols.map((n) => quote2(n)).join(SQL_SEPARATORS.FIELD_LIST);
3614
+ const formatted = outputCols.map((n) => quote(n)).join(SQL_SEPARATORS.FIELD_LIST);
3601
3615
  if (!isNonEmptyString(formatted)) {
3602
3616
  throw new Error("distinct emulation requires at least one output column");
3603
3617
  }
@@ -3693,7 +3707,7 @@ function buildIncludeColumns(spec) {
3693
3707
  dialect
3694
3708
  );
3695
3709
  if (countBuild.jsonPairs) {
3696
- countCols = jsonBuildObject(countBuild.jsonPairs, dialect) + " " + SQL_TEMPLATES.AS + " " + quote2("_count");
3710
+ countCols = jsonBuildObject(countBuild.jsonPairs, dialect) + " " + SQL_TEMPLATES.AS + " " + quote("_count");
3697
3711
  }
3698
3712
  countJoins = countBuild.joins;
3699
3713
  }
@@ -3706,7 +3720,7 @@ function buildIncludeColumns(spec) {
3706
3720
  const emptyJson = dialect === "postgres" ? `'[]'::json` : `json('[]')`;
3707
3721
  const includeCols = hasIncludes ? includes.map((inc) => {
3708
3722
  const expr = inc.isOneToOne ? "(" + inc.sql + ")" : "COALESCE((" + inc.sql + "), " + emptyJson + ")";
3709
- return expr + " " + SQL_TEMPLATES.AS + " " + quote2(inc.name);
3723
+ return expr + " " + SQL_TEMPLATES.AS + " " + quote(inc.name);
3710
3724
  }).join(SQL_SEPARATORS.FIELD_LIST) : "";
3711
3725
  const allCols = joinNonEmpty(
3712
3726
  [includeCols, countCols],
@@ -4071,6 +4085,7 @@ function buildComparisons(expr, filter, params, dialect, builder, excludeKeys =
4071
4085
  }
4072
4086
 
4073
4087
  // src/builder/aggregates.ts
4088
+ var MAX_NOT_DEPTH2 = 50;
4074
4089
  var AGGREGATES = [
4075
4090
  ["_sum", "SUM"],
4076
4091
  ["_avg", "AVG"],
@@ -4185,8 +4200,13 @@ function buildBinaryComparison(expr, op, val, params) {
4185
4200
  const placeholder = addHavingParam(params, op, val);
4186
4201
  return expr + " " + sqlOp + " " + placeholder;
4187
4202
  }
4188
- function buildSimpleComparison(expr, op, val, params, dialect) {
4203
+ function buildSimpleComparison(expr, op, val, params, dialect, depth = 0) {
4189
4204
  assertHavingOp(op);
4205
+ if (depth > MAX_NOT_DEPTH2) {
4206
+ throw new Error(
4207
+ `NOT operator nesting too deep in HAVING (max ${MAX_NOT_DEPTH2} levels).`
4208
+ );
4209
+ }
4190
4210
  if (val === null) return buildNullComparison(expr, op);
4191
4211
  if (op === Ops.NOT && isPlainObject(val)) {
4192
4212
  return buildNotComposite(
@@ -4194,7 +4214,7 @@ function buildSimpleComparison(expr, op, val, params, dialect) {
4194
4214
  val,
4195
4215
  params,
4196
4216
  dialect,
4197
- buildSimpleComparison,
4217
+ (e, subOp, subVal, p, d) => buildSimpleComparison(e, subOp, subVal, p, d, depth + 1),
4198
4218
  SQL_SEPARATORS.CONDITION_AND
4199
4219
  );
4200
4220
  }
@@ -4211,23 +4231,36 @@ function combineLogical(key, subClauses) {
4211
4231
  if (key === LogicalOps.NOT) return negateClauses(subClauses);
4212
4232
  return subClauses.join(" " + key + " ");
4213
4233
  }
4214
- function buildHavingNode(node, alias, params, dialect, model) {
4234
+ function buildHavingNode(node, alias, params, dialect, model, depth = 0) {
4235
+ if (depth > LIMITS.MAX_HAVING_DEPTH) {
4236
+ throw new Error(
4237
+ `HAVING clause nesting too deep (max ${LIMITS.MAX_HAVING_DEPTH} levels). This usually indicates a circular reference.`
4238
+ );
4239
+ }
4215
4240
  const clauses = [];
4216
4241
  for (const key in node) {
4217
4242
  if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
4218
4243
  const value = node[key];
4219
- const built = buildHavingEntry(key, value, alias, params, dialect, model);
4244
+ const built = buildHavingEntry(
4245
+ key,
4246
+ value,
4247
+ alias,
4248
+ params,
4249
+ dialect,
4250
+ model,
4251
+ depth
4252
+ );
4220
4253
  for (const c of built) {
4221
4254
  if (c && c.length > 0) clauses.push(c);
4222
4255
  }
4223
4256
  }
4224
4257
  return clauses.join(SQL_SEPARATORS.CONDITION_AND);
4225
4258
  }
4226
- function buildLogicalClause2(key, value, alias, params, dialect, model) {
4259
+ function buildLogicalClause2(key, value, alias, params, dialect, model, depth = 0) {
4227
4260
  const items = normalizeLogicalValue2(key, value);
4228
4261
  const subClauses = [];
4229
4262
  for (const it of items) {
4230
- const c = buildHavingNode(it, alias, params, dialect, model);
4263
+ const c = buildHavingNode(it, alias, params, dialect, model, depth + 1);
4231
4264
  if (c && c.length > 0) subClauses.push("(" + c + ")");
4232
4265
  }
4233
4266
  if (subClauses.length === 0) return "";
@@ -4286,7 +4319,7 @@ function buildHavingForFieldFirstShape(fieldName, target, alias, params, dialect
4286
4319
  }
4287
4320
  return out;
4288
4321
  }
4289
- function buildHavingEntry(key, value, alias, params, dialect, model) {
4322
+ function buildHavingEntry(key, value, alias, params, dialect, model, depth = 0) {
4290
4323
  if (isLogicalKey(key)) {
4291
4324
  const logical = buildLogicalClause2(
4292
4325
  key,
@@ -4294,7 +4327,8 @@ function buildHavingEntry(key, value, alias, params, dialect, model) {
4294
4327
  alias,
4295
4328
  params,
4296
4329
  dialect,
4297
- model
4330
+ model,
4331
+ depth
4298
4332
  );
4299
4333
  return logical ? [logical] : [];
4300
4334
  }
@@ -4321,7 +4355,7 @@ function buildHavingClause(having, alias, params, model, dialect) {
4321
4355
  if (!isNotNullish(having)) return "";
4322
4356
  const d = dialect != null ? dialect : getGlobalDialect();
4323
4357
  if (!isPlainObject(having)) throw new Error("having must be an object");
4324
- return buildHavingNode(having, alias, params, d, model);
4358
+ return buildHavingNode(having, alias, params, d, model, 0);
4325
4359
  }
4326
4360
  function normalizeCountArg(v) {
4327
4361
  if (!isNotNullish(v)) return void 0;
@@ -4331,13 +4365,13 @@ function normalizeCountArg(v) {
4331
4365
  }
4332
4366
  function pushCountAllField(fields) {
4333
4367
  fields.push(
4334
- SQL_TEMPLATES.COUNT_ALL + " " + SQL_TEMPLATES.AS + " " + quote2("_count._all")
4368
+ SQL_TEMPLATES.COUNT_ALL + " " + SQL_TEMPLATES.AS + " " + quote("_count._all")
4335
4369
  );
4336
4370
  }
4337
4371
  function pushCountField(fields, alias, fieldName, model) {
4338
4372
  const outAlias = "_count." + fieldName;
4339
4373
  fields.push(
4340
- "COUNT(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote2(outAlias)
4374
+ "COUNT(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote(outAlias)
4341
4375
  );
4342
4376
  }
4343
4377
  function addCountFields(fields, countArg, alias, model) {
@@ -4374,7 +4408,7 @@ function assertAggregatableScalarField(model, agg, fieldName) {
4374
4408
  function pushAggregateFieldSql(fields, aggFn, alias, agg, fieldName, model) {
4375
4409
  const outAlias = agg + "." + fieldName;
4376
4410
  fields.push(
4377
- aggFn + "(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote2(outAlias)
4411
+ aggFn + "(" + col(alias, fieldName, model) + ") " + SQL_TEMPLATES.AS + " " + quote(outAlias)
4378
4412
  );
4379
4413
  }
4380
4414
  function addAggregateFields(fields, args, alias, model) {
@@ -4521,7 +4555,7 @@ function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4521
4555
  SQL_TEMPLATES.SELECT,
4522
4556
  SQL_TEMPLATES.COUNT_ALL,
4523
4557
  SQL_TEMPLATES.AS,
4524
- quote2("_count._all"),
4558
+ quote("_count._all"),
4525
4559
  SQL_TEMPLATES.FROM,
4526
4560
  tableName,
4527
4561
  alias
@@ -4562,15 +4596,21 @@ function buildSqlResult(args) {
4562
4596
  return buildAggregateSql(processed, whereResult, tableName, alias, modelDef);
4563
4597
  }
4564
4598
  if (method === "groupBy") {
4565
- return buildGroupBySql(processed, whereResult, tableName, alias, modelDef);
4599
+ return buildGroupBySql(
4600
+ processed,
4601
+ whereResult,
4602
+ tableName,
4603
+ alias,
4604
+ modelDef,
4605
+ dialect
4606
+ );
4566
4607
  }
4567
4608
  if (method === "count") {
4568
4609
  return buildCountSql(
4569
4610
  whereResult,
4570
4611
  tableName,
4571
4612
  alias,
4572
- processed.skip
4573
- );
4613
+ processed.skip);
4574
4614
  }
4575
4615
  return buildSelectSql({
4576
4616
  method,
@@ -4610,22 +4650,23 @@ function normalizeSqlAndMappingsForDialect(sql, paramMappings, dialect) {
4610
4650
  }
4611
4651
  function buildParamsFromMappings(mappings) {
4612
4652
  const sorted = [...mappings].sort((a, b) => a.index - b.index);
4613
- return sorted.reduce(
4614
- (acc, m) => {
4615
- if (m.dynamicName !== void 0) {
4616
- acc.dynamicKeys.push(m.dynamicName);
4617
- return acc;
4618
- }
4619
- if (m.value !== void 0) {
4620
- acc.staticParams.push(m.value);
4621
- return acc;
4622
- }
4653
+ const staticParams = [];
4654
+ const dynamicKeys = [];
4655
+ let paramOrder = "";
4656
+ for (const m of sorted) {
4657
+ if (m.dynamicName !== void 0) {
4658
+ dynamicKeys.push(m.dynamicName);
4659
+ paramOrder += "d";
4660
+ } else if (m.value !== void 0) {
4661
+ staticParams.push(m.value);
4662
+ paramOrder += "s";
4663
+ } else {
4623
4664
  throw new Error(
4624
4665
  `CRITICAL: ParamMap ${m.index} has neither dynamicName nor value`
4625
4666
  );
4626
- },
4627
- { staticParams: [], dynamicKeys: [] }
4628
- );
4667
+ }
4668
+ }
4669
+ return { staticParams, dynamicKeys, paramOrder };
4629
4670
  }
4630
4671
  function resolveModelContext(directive) {
4631
4672
  const { model, datamodel } = directive.context;
@@ -4691,12 +4732,13 @@ function finalizeDirective(args) {
4691
4732
  return (_a = m.value) != null ? _a : void 0;
4692
4733
  });
4693
4734
  validateParamConsistencyByDialect(normalizedSql, params, dialect);
4694
- const { staticParams, dynamicKeys } = buildParamsFromMappings(normalizedMappings);
4735
+ const { staticParams, dynamicKeys, paramOrder } = buildParamsFromMappings(normalizedMappings);
4695
4736
  return {
4696
4737
  method: directive.method,
4697
4738
  sql: normalizedSql,
4698
4739
  staticParams,
4699
4740
  dynamicKeys,
4741
+ paramOrder,
4700
4742
  paramMappings: normalizedMappings,
4701
4743
  originalDirective: directive
4702
4744
  };
@@ -5016,49 +5058,100 @@ function makeAlias(name) {
5016
5058
  }
5017
5059
  function toSqliteParams(sql, params) {
5018
5060
  const reorderedParams = [];
5019
- let lastIndex = 0;
5020
- const parts = [];
5021
- for (let i = 0; i < sql.length; i++) {
5022
- if (sql[i] === "$" && i + 1 < sql.length) {
5023
- let num = 0;
5024
- let j = i + 1;
5025
- while (j < sql.length && sql[j] >= "0" && sql[j] <= "9") {
5026
- num = num * 10 + (sql.charCodeAt(j) - 48);
5027
- j++;
5061
+ const n = sql.length;
5062
+ let i = 0;
5063
+ let out = "";
5064
+ let mode = "normal";
5065
+ while (i < n) {
5066
+ const ch = sql.charCodeAt(i);
5067
+ if (mode === "normal") {
5068
+ if (ch === 39) {
5069
+ out += sql[i];
5070
+ mode = "single";
5071
+ i++;
5072
+ continue;
5073
+ }
5074
+ if (ch === 34) {
5075
+ out += sql[i];
5076
+ mode = "double";
5077
+ i++;
5078
+ continue;
5028
5079
  }
5029
- if (j > i + 1) {
5030
- parts.push(sql.substring(lastIndex, i));
5031
- parts.push("?");
5032
- reorderedParams.push(params[num - 1]);
5033
- i = j - 1;
5034
- lastIndex = j;
5080
+ if (ch === 36) {
5081
+ let j = i + 1;
5082
+ let num = 0;
5083
+ let hasDigit = false;
5084
+ while (j < n) {
5085
+ const d = sql.charCodeAt(j);
5086
+ if (d >= 48 && d <= 57) {
5087
+ num = num * 10 + (d - 48);
5088
+ hasDigit = true;
5089
+ j++;
5090
+ } else {
5091
+ break;
5092
+ }
5093
+ }
5094
+ if (hasDigit && num >= 1) {
5095
+ out += "?";
5096
+ reorderedParams.push(params[num - 1]);
5097
+ i = j;
5098
+ continue;
5099
+ }
5035
5100
  }
5101
+ out += sql[i];
5102
+ i++;
5103
+ continue;
5036
5104
  }
5105
+ if (mode === "single") {
5106
+ out += sql[i];
5107
+ if (ch === 39) {
5108
+ if (i + 1 < n && sql.charCodeAt(i + 1) === 39) {
5109
+ out += sql[i + 1];
5110
+ i += 2;
5111
+ continue;
5112
+ }
5113
+ mode = "normal";
5114
+ }
5115
+ i++;
5116
+ continue;
5117
+ }
5118
+ if (mode === "double") {
5119
+ out += sql[i];
5120
+ if (ch === 34) {
5121
+ if (i + 1 < n && sql.charCodeAt(i + 1) === 34) {
5122
+ out += sql[i + 1];
5123
+ i += 2;
5124
+ continue;
5125
+ }
5126
+ mode = "normal";
5127
+ }
5128
+ i++;
5129
+ continue;
5130
+ }
5131
+ out += sql[i];
5132
+ i++;
5037
5133
  }
5038
- parts.push(sql.substring(lastIndex));
5039
- return { sql: parts.join(""), params: reorderedParams };
5134
+ return { sql: out, params: reorderedParams };
5040
5135
  }
5041
- function canonicalizeQuery(modelName, method, args, dialect) {
5042
- function normalize(obj) {
5043
- if (obj === null || obj === void 0) return obj;
5044
- if (obj instanceof Date) {
5045
- return "__DATE_PARAM__";
5046
- }
5047
- if (Array.isArray(obj)) {
5048
- return obj.map(normalize);
5049
- }
5050
- if (typeof obj === "object") {
5051
- const sorted = {};
5052
- for (const key of Object.keys(obj).sort()) {
5053
- const value = obj[key];
5054
- sorted[key] = isDynamicParameter(value) ? "__DYN__" : normalize(value);
5136
+ function canonicalizeReplacer(key, value) {
5137
+ if (typeof value === "bigint") return `__bigint__${value.toString()}`;
5138
+ if (value && typeof value === "object" && !Array.isArray(value)) {
5139
+ const obj = value;
5140
+ const sorted = {};
5141
+ for (const k of Object.keys(obj).sort()) {
5142
+ const v = obj[k];
5143
+ if (v && typeof v === "object" && !Array.isArray(v) && Object.keys(v).length === 0) {
5144
+ continue;
5055
5145
  }
5056
- return sorted;
5146
+ sorted[k] = v;
5057
5147
  }
5058
- return obj;
5148
+ return sorted;
5059
5149
  }
5060
- const canonical = normalize(args);
5061
- return `${dialect}:${modelName}:${method}:${JSON.stringify(canonical)}`;
5150
+ return value;
5151
+ }
5152
+ function canonicalizeQuery(modelName, method, args, dialect) {
5153
+ if (!args) return `${dialect}:${modelName}:${method}:{}`;
5154
+ return `${dialect}:${modelName}:${method}:${JSON.stringify(args, canonicalizeReplacer)}`;
5062
5155
  }
5063
5156
  function buildSQLFull(model, models, method, args, dialect) {
5064
5157
  const tableName = buildTableReference(
@@ -5122,46 +5215,20 @@ function buildSQLFull(model, models, method, args, dialect) {
5122
5215
  }
5123
5216
  function buildSQLWithCache(model, models, method, args, dialect) {
5124
5217
  const cacheKey = canonicalizeQuery(model.name, method, args, dialect);
5125
- const cachedSql = queryCache.get(cacheKey);
5126
- if (cachedSql) {
5127
- const result2 = buildSQLFull(model, models, method, args, dialect);
5128
- return { sql: cachedSql, params: result2.params };
5218
+ const cached = queryCache.get(cacheKey);
5219
+ if (cached) {
5220
+ return { sql: cached.sql, params: [...cached.params] };
5129
5221
  }
5130
5222
  const result = buildSQLFull(model, models, method, args, dialect);
5131
- queryCache.set(cacheKey, result.sql);
5223
+ queryCache.set(cacheKey, result);
5132
5224
  queryCache.size;
5133
5225
  return result;
5134
5226
  }
5135
5227
 
5136
5228
  // src/batch.ts
5137
- function assertNoControlChars2(label, s) {
5138
- for (let i = 0; i < s.length; i++) {
5139
- const c = s.charCodeAt(i);
5140
- if (c <= 31 || c === 127) {
5141
- throw new Error(`${label} contains control characters`);
5142
- }
5143
- }
5144
- }
5145
- function assertSafeIdentifier(label, s) {
5146
- const raw = String(s);
5147
- if (raw.trim() !== raw) {
5148
- throw new Error(`${label} must not contain leading/trailing whitespace`);
5149
- }
5150
- if (raw.length === 0) throw new Error(`${label} cannot be empty`);
5151
- assertNoControlChars2(label, raw);
5152
- if (/[ \t\r\n]/.test(raw)) {
5153
- throw new Error(`${label} must not contain whitespace`);
5154
- }
5155
- if (raw.includes(";")) {
5156
- throw new Error(`${label} must not contain semicolons`);
5157
- }
5158
- if (raw.includes("--") || raw.includes("/*") || raw.includes("*/")) {
5159
- throw new Error(`${label} must not contain SQL comment tokens`);
5160
- }
5161
- }
5162
- function quoteIdent(id) {
5229
+ function quoteBatchIdent(id) {
5163
5230
  const raw = String(id);
5164
- assertSafeIdentifier("Identifier", raw);
5231
+ assertSafeAlias(raw);
5165
5232
  return `"${raw.replace(/"/g, '""')}"`;
5166
5233
  }
5167
5234
  function makeBatchAlias(i) {
@@ -5323,6 +5390,14 @@ function replacePgPlaceholders(sql, replace) {
5323
5390
  }
5324
5391
  return out;
5325
5392
  }
5393
+ function containsPgPlaceholder(sql) {
5394
+ let found = false;
5395
+ replacePgPlaceholders(sql, (oldIndex) => {
5396
+ found = true;
5397
+ return `$${oldIndex}`;
5398
+ });
5399
+ return found;
5400
+ }
5326
5401
  function reindexParams(sql, params, offset) {
5327
5402
  if (!Number.isInteger(offset) || offset < 0) {
5328
5403
  throw new Error(`Invalid param offset: ${offset}`);
@@ -5346,7 +5421,7 @@ function reindexParams(sql, params, offset) {
5346
5421
  return { sql: reindexed, params: newParams };
5347
5422
  }
5348
5423
  function wrapQueryForMethod(method, cteName, resultAlias) {
5349
- const outKey = quoteIdent(resultAlias);
5424
+ const outKey = quoteBatchIdent(resultAlias);
5350
5425
  switch (method) {
5351
5426
  case "findMany":
5352
5427
  case "groupBy":
@@ -5380,9 +5455,6 @@ function looksTooComplexForFilter(sql) {
5380
5455
  if (s.includes(" distinct ")) return true;
5381
5456
  return false;
5382
5457
  }
5383
- function containsPgPlaceholder(sql) {
5384
- return /\$[1-9][0-9]*/.test(sql);
5385
- }
5386
5458
  function parseSimpleCountSql(sql) {
5387
5459
  const trimmed = sql.trim().replace(/;$/, "").trim();
5388
5460
  const lower = trimmed.toLowerCase();
@@ -5430,7 +5502,7 @@ function buildMergedCountBatchSql(queries, keys, aliasesByKey, modelMap, models,
5430
5502
  if (built.params.length > 0) return null;
5431
5503
  if (sharedFrom === null) sharedFrom = parsed.fromSql;
5432
5504
  if (sharedFrom !== parsed.fromSql) return null;
5433
- expressions.push(`count(*) AS ${quoteIdent(alias2)}`);
5505
+ expressions.push(`count(*) AS ${quoteBatchIdent(alias2)}`);
5434
5506
  localKeys.push(key);
5435
5507
  localAliases.push(alias2);
5436
5508
  continue;
@@ -5444,7 +5516,7 @@ function buildMergedCountBatchSql(queries, keys, aliasesByKey, modelMap, models,
5444
5516
  );
5445
5517
  for (let p = 0; p < re.params.length; p++) localParams.push(re.params[p]);
5446
5518
  expressions.push(
5447
- `count(*) FILTER (WHERE ${re.sql}) AS ${quoteIdent(alias2)}`
5519
+ `count(*) FILTER (WHERE ${re.sql}) AS ${quoteBatchIdent(alias2)}`
5448
5520
  );
5449
5521
  localKeys.push(key);
5450
5522
  localAliases.push(alias2);
@@ -5477,7 +5549,7 @@ function buildMergedCountBatchSql(queries, keys, aliasesByKey, modelMap, models,
5477
5549
  for (let k = 0; k < sq.aliases.length; k++) {
5478
5550
  const outAlias = sq.aliases[k];
5479
5551
  selectParts.push(
5480
- `${sq.alias}.${quoteIdent(outAlias)} AS ${quoteIdent(outAlias)}`
5552
+ `${sq.alias}.${quoteBatchIdent(outAlias)} AS ${quoteBatchIdent(outAlias)}`
5481
5553
  );
5482
5554
  }
5483
5555
  }
@@ -5584,7 +5656,7 @@ function buildBatchCountSql(queries, modelMap, models, dialect) {
5584
5656
  const cteName = `count_${i}`;
5585
5657
  const resultKey = `count_${i}`;
5586
5658
  ctes[i] = `${cteName} AS (${reindexedSql})`;
5587
- selects[i] = `(SELECT * FROM ${cteName}) AS ${quoteIdent(resultKey)}`;
5659
+ selects[i] = `(SELECT * FROM ${cteName}) AS ${quoteBatchIdent(resultKey)}`;
5588
5660
  }
5589
5661
  const sql = `WITH ${ctes.join(", ")} SELECT ${selects.join(", ")}`;
5590
5662
  return { sql, params: allParams };
@@ -5701,6 +5773,20 @@ function isolationLevelToPostgresKeyword(level) {
5701
5773
  return void 0;
5702
5774
  }
5703
5775
  }
5776
+ function validateTimeout(timeout) {
5777
+ if (typeof timeout !== "number") {
5778
+ throw new Error(
5779
+ `Transaction timeout must be a number, got ${typeof timeout}`
5780
+ );
5781
+ }
5782
+ if (!Number.isFinite(timeout)) {
5783
+ throw new Error(`Transaction timeout must be finite, got ${timeout}`);
5784
+ }
5785
+ if (timeout < 0) {
5786
+ throw new Error(`Transaction timeout must be non-negative, got ${timeout}`);
5787
+ }
5788
+ return Math.floor(timeout);
5789
+ }
5704
5790
  function createTransactionExecutor(deps) {
5705
5791
  const { modelMap, allModels, dialect, executeRaw, postgresClient } = deps;
5706
5792
  return {
@@ -5723,10 +5809,11 @@ function createTransactionExecutor(deps) {
5723
5809
  `SET TRANSACTION ISOLATION LEVEL ${isolationLevel.toUpperCase()}`
5724
5810
  );
5725
5811
  }
5726
- if (options == null ? void 0 : options.timeout) {
5727
- yield sql.unsafe(
5728
- `SET LOCAL statement_timeout = ${Math.floor(options.timeout)}`
5729
- );
5812
+ if ((options == null ? void 0 : options.timeout) !== void 0 && options.timeout !== null) {
5813
+ const validatedTimeout = validateTimeout(options.timeout);
5814
+ yield sql.unsafe(`SET LOCAL statement_timeout = $1`, [
5815
+ validatedTimeout
5816
+ ]);
5730
5817
  }
5731
5818
  for (const q of queries) {
5732
5819
  const model = modelMap.get(q.model);
@@ -5752,6 +5839,124 @@ function createTransactionExecutor(deps) {
5752
5839
  }
5753
5840
  };
5754
5841
  }
5842
+
5843
+ // src/fast-path.ts
5844
+ function getIdField(model) {
5845
+ const idField = model.fields.find((f) => f.name === "id" && !f.isRelation);
5846
+ if (!idField) return null;
5847
+ return {
5848
+ name: "id",
5849
+ dbName: idField.dbName || "id"
5850
+ };
5851
+ }
5852
+ function buildColumnList(model) {
5853
+ const cols = [];
5854
+ for (const f of model.fields) {
5855
+ if (f.isRelation) continue;
5856
+ if (f.name.startsWith("@") || f.name.startsWith("//")) continue;
5857
+ const dbName = f.dbName || f.name;
5858
+ if (dbName !== f.name) {
5859
+ cols.push(`${quote(dbName)} AS ${quote(f.name)}`);
5860
+ } else {
5861
+ cols.push(quote(dbName));
5862
+ }
5863
+ }
5864
+ return cols.join(", ");
5865
+ }
5866
+ function buildSimpleQuery(model, dialect, where, params, suffix = "") {
5867
+ const tableName = buildTableReference(
5868
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
5869
+ model.tableName,
5870
+ dialect
5871
+ );
5872
+ const columns = buildColumnList(model);
5873
+ const sql = `SELECT ${columns} FROM ${tableName} ${where}${suffix}`;
5874
+ return { sql, params };
5875
+ }
5876
+ function norm(value) {
5877
+ return normalizeValue(value);
5878
+ }
5879
+ function tryFastPath(model, method, args, dialect) {
5880
+ const where = args.where;
5881
+ if (method === "findUnique" && isPlainObject(where) && Object.keys(where).length === 1 && "id" in where && !args.select && !args.include) {
5882
+ const idField = getIdField(model);
5883
+ if (!idField) return null;
5884
+ const whereClause = dialect === "sqlite" ? `WHERE ${quote(idField.dbName)} = ?` : `WHERE ${quote(idField.dbName)} = $1`;
5885
+ return buildSimpleQuery(
5886
+ model,
5887
+ dialect,
5888
+ whereClause,
5889
+ [norm(where.id)],
5890
+ " LIMIT 1"
5891
+ );
5892
+ }
5893
+ if (method === "findMany" && isPlainObject(where) && Object.keys(where).length === 1 && "id" in where && !args.select && !args.include && !args.orderBy && !args.take && !args.skip && !args.distinct && !args.cursor) {
5894
+ const idField = getIdField(model);
5895
+ if (!idField) return null;
5896
+ const whereClause = dialect === "sqlite" ? `WHERE ${quote(idField.dbName)} = ?` : `WHERE ${quote(idField.dbName)} = $1`;
5897
+ return buildSimpleQuery(model, dialect, whereClause, [norm(where.id)]);
5898
+ }
5899
+ if (method === "count" && (!where || Object.keys(where).length === 0) && !args.select && !args.skip) {
5900
+ const tableName = buildTableReference(
5901
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
5902
+ model.tableName,
5903
+ dialect
5904
+ );
5905
+ const sql = `SELECT COUNT(*) AS ${quote("_count._all")} FROM ${tableName}`;
5906
+ return { sql, params: [] };
5907
+ }
5908
+ if (method === "findMany" && (!where || Object.keys(where).length === 0) && !args.select && !args.include && !args.orderBy && !args.skip && !args.distinct && !args.cursor && typeof args.take === "number") {
5909
+ const tableName = buildTableReference(
5910
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
5911
+ model.tableName,
5912
+ dialect
5913
+ );
5914
+ const columns = buildColumnList(model);
5915
+ const sql = dialect === "sqlite" ? `SELECT ${columns} FROM ${tableName} LIMIT ?` : `SELECT ${columns} FROM ${tableName} LIMIT $1`;
5916
+ return { sql, params: [norm(args.take)] };
5917
+ }
5918
+ if (method === "findFirst" && isPlainObject(where) && Object.keys(where).length === 1 && !args.select && !args.include && !args.orderBy && !args.skip) {
5919
+ const field = Object.keys(where)[0];
5920
+ const value = where[field];
5921
+ if (value !== null && typeof value !== "object") {
5922
+ const fieldDef = model.fields.find((f) => f.name === field);
5923
+ if (fieldDef && !fieldDef.isRelation) {
5924
+ const columnName = fieldDef.dbName || field;
5925
+ const whereClause = dialect === "sqlite" ? `WHERE ${quote(columnName)} = ?` : `WHERE ${quote(columnName)} = $1`;
5926
+ return buildSimpleQuery(
5927
+ model,
5928
+ dialect,
5929
+ whereClause,
5930
+ [norm(value)],
5931
+ " LIMIT 1"
5932
+ );
5933
+ }
5934
+ }
5935
+ }
5936
+ if (method === "findMany" && isPlainObject(where) && Object.keys(where).length === 1 && !args.select && !args.include && !args.orderBy && !args.take && !args.skip && !args.distinct && !args.cursor) {
5937
+ const field = Object.keys(where)[0];
5938
+ const value = where[field];
5939
+ if (value !== null && typeof value !== "object") {
5940
+ const fieldDef = model.fields.find((f) => f.name === field);
5941
+ if (fieldDef && !fieldDef.isRelation) {
5942
+ const columnName = fieldDef.dbName || field;
5943
+ const whereClause = dialect === "sqlite" ? `WHERE ${quote(columnName)} = ?` : `WHERE ${quote(columnName)} = $1`;
5944
+ return buildSimpleQuery(model, dialect, whereClause, [norm(value)]);
5945
+ }
5946
+ }
5947
+ }
5948
+ if (method === "findMany" && (!where || Object.keys(where).length === 0) && !args.select && !args.include && !args.orderBy && !args.take && !args.skip && !args.distinct && !args.cursor) {
5949
+ const tableName = buildTableReference(
5950
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
5951
+ model.tableName,
5952
+ dialect
5953
+ );
5954
+ const columns = buildColumnList(model);
5955
+ const sql = `SELECT ${columns} FROM ${tableName}`;
5956
+ return { sql, params: [] };
5957
+ }
5958
+ return null;
5959
+ }
5755
5960
  var ACCELERATED_METHODS = /* @__PURE__ */ new Set([
5756
5961
  "findMany",
5757
5962
  "findFirst",
@@ -5831,8 +6036,13 @@ function createExecuteQuery(client, dialect) {
5831
6036
  });
5832
6037
  }
5833
6038
  function logAcceleratedError(debug, dialect, modelName, method, error) {
5834
- if (!debug) return;
5835
- console.error(`[${dialect}] ${modelName}.${method} failed:`, error);
6039
+ const msg = error instanceof Error ? error.message : String(error);
6040
+ console.warn(
6041
+ `[prisma-sql] ${modelName}.${method} acceleration failed, falling back to Prisma: ${msg}`
6042
+ );
6043
+ if (debug && error instanceof Error && error.stack) {
6044
+ console.warn(error.stack);
6045
+ }
5836
6046
  }
5837
6047
  function canAccelerate(deps, modelName, method) {
5838
6048
  if (!ACCELERATED_METHODS.has(method)) return false;
@@ -5841,18 +6051,34 @@ function canAccelerate(deps, modelName, method) {
5841
6051
  }
5842
6052
  function runAccelerated(deps, modelName, method, model, args) {
5843
6053
  return __async(this, null, function* () {
5844
- const results = yield executeWithTiming({
5845
- modelName,
5846
- method,
5847
- model,
5848
- allModels: deps.allModels,
5849
- args: args || {},
5850
- dialect: deps.dialect,
5851
- debug: deps.debug,
5852
- executeQuery: deps.executeQuery,
5853
- onQuery: deps.onQuery
5854
- });
5855
- return transformQueryResults(method, results);
6054
+ return withDialect(deps.dialect, () => __async(null, null, function* () {
6055
+ const fastPath = tryFastPath(model, method, args || {}, deps.dialect);
6056
+ if (fastPath) {
6057
+ if (deps.debug) {
6058
+ console.log(`[${deps.dialect}] ${modelName}.${method} \u26A1 FAST PATH`);
6059
+ console.log("SQL:", fastPath.sql);
6060
+ console.log("Params:", fastPath.params);
6061
+ }
6062
+ const results2 = yield deps.executeQuery(
6063
+ method,
6064
+ fastPath.sql,
6065
+ fastPath.params
6066
+ );
6067
+ return transformQueryResults(method, results2);
6068
+ }
6069
+ const results = yield executeWithTiming({
6070
+ modelName,
6071
+ method,
6072
+ model,
6073
+ allModels: deps.allModels,
6074
+ args: args || {},
6075
+ dialect: deps.dialect,
6076
+ debug: deps.debug,
6077
+ executeQuery: deps.executeQuery,
6078
+ onQuery: deps.onQuery
6079
+ });
6080
+ return transformQueryResults(method, results);
6081
+ }));
5856
6082
  });
5857
6083
  }
5858
6084
  function handleMethodCall(ctx, method, args, deps) {