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