prisma-sql 1.63.0 → 1.65.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
@@ -650,81 +650,6 @@ function needsQuoting(identifier) {
650
650
  return false;
651
651
  }
652
652
 
653
- // src/builder/shared/model-field-cache.ts
654
- var MODEL_CACHE = /* @__PURE__ */ new WeakMap();
655
- function quoteIdent(id) {
656
- if (typeof id !== "string" || id.trim().length === 0) {
657
- throw new Error("quoteIdent: identifier is required and cannot be empty");
658
- }
659
- for (let i = 0; i < id.length; i++) {
660
- const code = id.charCodeAt(i);
661
- if (code >= 0 && code <= 31 || code === 127) {
662
- throw new Error(
663
- `quoteIdent: identifier contains invalid characters: ${JSON.stringify(id)}`
664
- );
665
- }
666
- }
667
- if (needsQuoting(id)) {
668
- return `"${id.replace(/"/g, '""')}"`;
669
- }
670
- return id;
671
- }
672
- function ensureFullCache(model) {
673
- let cache = MODEL_CACHE.get(model);
674
- if (!cache) {
675
- const fieldInfo = /* @__PURE__ */ new Map();
676
- const scalarFields = /* @__PURE__ */ new Set();
677
- const relationFields = /* @__PURE__ */ new Set();
678
- const columnMap = /* @__PURE__ */ new Map();
679
- const fieldByName = /* @__PURE__ */ new Map();
680
- const quotedColumns = /* @__PURE__ */ new Map();
681
- for (const f of model.fields) {
682
- const info = {
683
- name: f.name,
684
- dbName: f.dbName || f.name,
685
- type: f.type,
686
- isRelation: !!f.isRelation,
687
- isRequired: !!f.isRequired
688
- };
689
- fieldInfo.set(f.name, info);
690
- fieldByName.set(f.name, f);
691
- if (info.isRelation) {
692
- relationFields.add(f.name);
693
- } else {
694
- scalarFields.add(f.name);
695
- const dbName = info.dbName;
696
- columnMap.set(f.name, dbName);
697
- quotedColumns.set(f.name, quoteIdent(dbName));
698
- }
699
- }
700
- cache = {
701
- fieldInfo,
702
- scalarFields,
703
- relationFields,
704
- columnMap,
705
- fieldByName,
706
- quotedColumns
707
- };
708
- MODEL_CACHE.set(model, cache);
709
- }
710
- return cache;
711
- }
712
- function getFieldInfo(model, fieldName) {
713
- return ensureFullCache(model).fieldInfo.get(fieldName);
714
- }
715
- function getScalarFieldSet(model) {
716
- return ensureFullCache(model).scalarFields;
717
- }
718
- function getRelationFieldSet(model) {
719
- return ensureFullCache(model).relationFields;
720
- }
721
- function getColumnMap(model) {
722
- return ensureFullCache(model).columnMap;
723
- }
724
- function getQuotedColumn(model, fieldName) {
725
- return ensureFullCache(model).quotedColumns.get(fieldName);
726
- }
727
-
728
653
  // src/builder/shared/sql-utils.ts
729
654
  function containsControlChars(s) {
730
655
  for (let i = 0; i < s.length; i++) {
@@ -1026,6 +951,70 @@ function normalizeKeyList(input) {
1026
951
  return s.length > 0 ? [s] : [];
1027
952
  }
1028
953
 
954
+ // src/builder/shared/model-field-cache.ts
955
+ var SCALAR_FIELD_CACHE = /* @__PURE__ */ new WeakMap();
956
+ var RELATION_FIELD_CACHE = /* @__PURE__ */ new WeakMap();
957
+ var COLUMN_MAP_CACHE = /* @__PURE__ */ new WeakMap();
958
+ var QUOTED_COLUMN_CACHE = /* @__PURE__ */ new WeakMap();
959
+ var FIELD_BY_NAME_CACHE = /* @__PURE__ */ new WeakMap();
960
+ function getScalarFieldSet(model) {
961
+ let cached = SCALAR_FIELD_CACHE.get(model);
962
+ if (cached) return cached;
963
+ const set = /* @__PURE__ */ new Set();
964
+ for (const f of model.fields) {
965
+ if (!f.isRelation) set.add(f.name);
966
+ }
967
+ SCALAR_FIELD_CACHE.set(model, set);
968
+ return set;
969
+ }
970
+ function getRelationFieldSet(model) {
971
+ let cached = RELATION_FIELD_CACHE.get(model);
972
+ if (cached) return cached;
973
+ const set = /* @__PURE__ */ new Set();
974
+ for (const f of model.fields) {
975
+ if (f.isRelation) set.add(f.name);
976
+ }
977
+ RELATION_FIELD_CACHE.set(model, set);
978
+ return set;
979
+ }
980
+ function getColumnMap(model) {
981
+ let cached = COLUMN_MAP_CACHE.get(model);
982
+ if (cached) return cached;
983
+ const map = /* @__PURE__ */ new Map();
984
+ for (const f of model.fields) {
985
+ if (f.dbName && f.dbName !== f.name) {
986
+ map.set(f.name, f.dbName);
987
+ }
988
+ }
989
+ COLUMN_MAP_CACHE.set(model, map);
990
+ return map;
991
+ }
992
+ function getQuotedColumn(model, fieldName) {
993
+ let cache = QUOTED_COLUMN_CACHE.get(model);
994
+ if (!cache) {
995
+ cache = /* @__PURE__ */ new Map();
996
+ QUOTED_COLUMN_CACHE.set(model, cache);
997
+ }
998
+ const cached = cache.get(fieldName);
999
+ if (cached !== void 0) return cached;
1000
+ const columnMap = getColumnMap(model);
1001
+ const columnName = columnMap.get(fieldName) || fieldName;
1002
+ const quoted = quote(columnName);
1003
+ cache.set(fieldName, quoted);
1004
+ return quoted;
1005
+ }
1006
+ function getFieldByName(model, fieldName) {
1007
+ let cache = FIELD_BY_NAME_CACHE.get(model);
1008
+ if (!cache) {
1009
+ cache = /* @__PURE__ */ new Map();
1010
+ for (const field of model.fields) {
1011
+ cache.set(field.name, field);
1012
+ }
1013
+ FIELD_BY_NAME_CACHE.set(model, cache);
1014
+ }
1015
+ return cache.get(fieldName);
1016
+ }
1017
+
1029
1018
  // src/builder/joins.ts
1030
1019
  function isRelationField(fieldName, model) {
1031
1020
  return getRelationFieldSet(model).has(fieldName);
@@ -1139,11 +1128,18 @@ var getNextSort = (sortRaw) => {
1139
1128
  return sortRaw;
1140
1129
  };
1141
1130
  var flipObjectSort = (obj) => {
1142
- const sortRaw = obj.sort;
1143
- const out = __spreadProps(__spreadValues({}, obj), { sort: getNextSort(sortRaw) });
1144
- const nullsRaw = obj.nulls;
1145
- if (typeof nullsRaw === "string") {
1146
- out.nulls = flipNulls(nullsRaw);
1131
+ const out = __spreadValues({}, obj);
1132
+ const hasSort = Object.prototype.hasOwnProperty.call(obj, "sort");
1133
+ const hasDirection = Object.prototype.hasOwnProperty.call(obj, "direction");
1134
+ if (hasSort) {
1135
+ out.sort = getNextSort(obj.sort);
1136
+ } else if (hasDirection) {
1137
+ out.direction = getNextSort(obj.direction);
1138
+ } else {
1139
+ out.sort = getNextSort(obj.sort);
1140
+ }
1141
+ if (typeof obj.nulls === "string") {
1142
+ out.nulls = flipNulls(obj.nulls);
1147
1143
  }
1148
1144
  return out;
1149
1145
  };
@@ -1189,7 +1185,7 @@ var normalizePairs = (pairs, parseValue) => {
1189
1185
  return pairs.map(([field, rawValue]) => {
1190
1186
  const parsed = parseValue(rawValue, field);
1191
1187
  return {
1192
- [field]: parsed.nulls !== void 0 ? { sort: parsed.direction, nulls: parsed.nulls } : parsed.direction
1188
+ [field]: parsed.nulls !== void 0 ? { direction: parsed.direction, nulls: parsed.nulls } : parsed.direction
1193
1189
  };
1194
1190
  });
1195
1191
  };
@@ -1238,37 +1234,113 @@ function ensureDeterministicOrderByInput(args) {
1238
1234
  }
1239
1235
 
1240
1236
  // src/builder/shared/validators/field-assertions.ts
1241
- var NUMERIC_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt"]);
1242
- function assertScalarField(model, fieldName, context) {
1243
- const field = getFieldInfo(model, fieldName);
1237
+ function assertFieldExists(fieldName, model, path) {
1238
+ const field = getFieldByName(model, fieldName);
1244
1239
  if (!field) {
1245
1240
  throw createError(
1246
- `${context} references unknown field '${fieldName}' on model ${model.name}`,
1241
+ `Field '${fieldName}' does not exist on model ${model.name}`,
1247
1242
  {
1248
1243
  field: fieldName,
1249
1244
  modelName: model.name,
1250
- availableFields: model.fields.map((f) => f.name)
1245
+ path
1251
1246
  }
1252
1247
  );
1253
1248
  }
1249
+ return field;
1250
+ }
1251
+ function assertScalarField(model, fieldName, context) {
1252
+ const field = getFieldByName(model, fieldName);
1253
+ if (!field) {
1254
+ throw new Error(
1255
+ `${context}: field '${fieldName}' does not exist on model '${model.name}'`
1256
+ );
1257
+ }
1254
1258
  if (field.isRelation) {
1255
- throw createError(
1256
- `${context} does not support relation field '${fieldName}'`,
1257
- { field: fieldName, modelName: model.name }
1259
+ throw new Error(
1260
+ `${context}: field '${fieldName}' is a relation field, expected scalar field`
1258
1261
  );
1259
1262
  }
1260
- return field;
1261
1263
  }
1262
1264
  function assertNumericField(model, fieldName, context) {
1263
- const field = assertScalarField(model, fieldName, context);
1264
- const baseType = field.type.replace(/\[\]|\?/g, "");
1265
- if (!NUMERIC_TYPES.has(baseType)) {
1265
+ assertScalarField(model, fieldName, context);
1266
+ const field = getFieldByName(model, fieldName);
1267
+ if (!field) return;
1268
+ const numericTypes = /* @__PURE__ */ new Set([
1269
+ "Int",
1270
+ "BigInt",
1271
+ "Float",
1272
+ "Decimal",
1273
+ "Int?",
1274
+ "BigInt?",
1275
+ "Float?",
1276
+ "Decimal?"
1277
+ ]);
1278
+ if (!numericTypes.has(field.type)) {
1279
+ throw new Error(
1280
+ `${context}: field '${fieldName}' must be numeric (Int, BigInt, Float, Decimal), got '${field.type}'`
1281
+ );
1282
+ }
1283
+ }
1284
+ function assertValidOperator(fieldName, operator, fieldType, path, modelName) {
1285
+ const stringOps = /* @__PURE__ */ new Set([
1286
+ "equals",
1287
+ "not",
1288
+ "in",
1289
+ "notIn",
1290
+ "lt",
1291
+ "lte",
1292
+ "gt",
1293
+ "gte",
1294
+ "contains",
1295
+ "startsWith",
1296
+ "endsWith",
1297
+ "mode",
1298
+ "search"
1299
+ ]);
1300
+ const numericOps = /* @__PURE__ */ new Set([
1301
+ "equals",
1302
+ "not",
1303
+ "in",
1304
+ "notIn",
1305
+ "lt",
1306
+ "lte",
1307
+ "gt",
1308
+ "gte"
1309
+ ]);
1310
+ const jsonOps = /* @__PURE__ */ new Set([
1311
+ "equals",
1312
+ "not",
1313
+ "path",
1314
+ "string_contains",
1315
+ "string_starts_with",
1316
+ "string_ends_with",
1317
+ "array_contains",
1318
+ "array_starts_with",
1319
+ "array_ends_with"
1320
+ ]);
1321
+ const isString = fieldType === "String" || fieldType === "String?";
1322
+ const isNumeric = ["Int", "BigInt", "Float", "Decimal"].some(
1323
+ (t) => fieldType === t || fieldType === `${t}?`
1324
+ );
1325
+ const isJson = fieldType === "Json" || fieldType === "Json?";
1326
+ if (isString && !stringOps.has(operator)) {
1266
1327
  throw createError(
1267
- `${context} requires numeric field, got '${field.type}'`,
1268
- { field: fieldName, modelName: model.name }
1328
+ `Operator '${operator}' is not valid for String field '${fieldName}'`,
1329
+ { field: fieldName, modelName, path, operator }
1330
+ );
1331
+ }
1332
+ if (isNumeric && !numericOps.has(operator)) {
1333
+ throw createError(
1334
+ `Operator '${operator}' is not valid for numeric field '${fieldName}'`,
1335
+ { field: fieldName, modelName, path, operator }
1336
+ );
1337
+ }
1338
+ if (isJson && !jsonOps.has(operator)) {
1339
+ throw createError(
1340
+ `Operator '${operator}' is not valid for Json field '${fieldName}'`,
1341
+ { field: fieldName, modelName, path, operator }
1269
1342
  );
1270
1343
  }
1271
- return field;
1272
1344
  }
1273
1345
 
1274
1346
  // src/builder/pagination.ts
@@ -1782,6 +1854,14 @@ function handleInOperator(expr, op, val, params, dialect) {
1782
1854
  if (val.length === 0) {
1783
1855
  return op === Ops.IN ? "0=1" : "1=1";
1784
1856
  }
1857
+ if (dialect === "sqlite" && val.length <= 30) {
1858
+ const placeholders = [];
1859
+ for (const item of val) {
1860
+ placeholders.push(params.add(item));
1861
+ }
1862
+ const list = placeholders.join(", ");
1863
+ return op === Ops.IN ? `${expr} IN (${list})` : `${expr} NOT IN (${list})`;
1864
+ }
1785
1865
  const paramValue = prepareArrayParam(val, dialect);
1786
1866
  const placeholder = params.add(paramValue);
1787
1867
  return op === Ops.IN ? inArray(expr, placeholder, dialect) : notInArray(expr, placeholder, dialect);
@@ -2317,57 +2397,6 @@ function buildNestedRelation(fieldName, value, ctx, whereBuilder) {
2317
2397
  return buildTopLevelRelation(fieldName, value, ctx, whereBuilder);
2318
2398
  }
2319
2399
 
2320
- // src/builder/shared/validators/field-validators.ts
2321
- function assertFieldExists(name, model, path) {
2322
- const field = model.fields.find((f) => f.name === name);
2323
- if (!isNotNullish(field)) {
2324
- throw createError(`Field '${name}' does not exist on '${model.name}'`, {
2325
- field: name,
2326
- path,
2327
- modelName: model.name,
2328
- availableFields: model.fields.map((f) => f.name)
2329
- });
2330
- }
2331
- return field;
2332
- }
2333
- function assertValidOperator(fieldName, op, fieldType, path, modelName) {
2334
- if (!isNotNullish(fieldType)) return;
2335
- const ARRAY_OPS = /* @__PURE__ */ new Set([
2336
- Ops.HAS,
2337
- Ops.HAS_SOME,
2338
- Ops.HAS_EVERY,
2339
- Ops.IS_EMPTY
2340
- ]);
2341
- const JSON_OPS2 = /* @__PURE__ */ new Set([
2342
- Ops.PATH,
2343
- Ops.STRING_CONTAINS,
2344
- Ops.STRING_STARTS_WITH,
2345
- Ops.STRING_ENDS_WITH
2346
- ]);
2347
- const isArrayOp = ARRAY_OPS.has(op);
2348
- const isFieldArray = isArrayType(fieldType);
2349
- const arrayOpMismatch = isArrayOp && !isFieldArray;
2350
- if (arrayOpMismatch) {
2351
- throw createError(`'${op}' requires array field, got '${fieldType}'`, {
2352
- operator: op,
2353
- field: fieldName,
2354
- path,
2355
- modelName
2356
- });
2357
- }
2358
- const isJsonOp = JSON_OPS2.has(op);
2359
- const isFieldJson = isJsonType(fieldType);
2360
- const jsonOpMismatch = isJsonOp && !isFieldJson;
2361
- if (jsonOpMismatch) {
2362
- throw createError(`'${op}' requires JSON field, got '${fieldType}'`, {
2363
- operator: op,
2364
- field: fieldName,
2365
- path,
2366
- modelName
2367
- });
2368
- }
2369
- }
2370
-
2371
2400
  // src/builder/where/builder.ts
2372
2401
  var MAX_QUERY_DEPTH = 50;
2373
2402
  var EMPTY_JOINS = Object.freeze([]);
@@ -2424,6 +2453,23 @@ function buildRelationFilter(fieldName, value, ctx, builder) {
2424
2453
  }
2425
2454
  return buildTopLevelRelation(fieldName, value, ctx2, builder);
2426
2455
  }
2456
+ function buildSimpleEquality(expr, value, ctx) {
2457
+ if (value === null) return `${expr} ${SQL_TEMPLATES.IS_NULL}`;
2458
+ const placeholder = ctx.params.addAuto(value);
2459
+ return `${expr} = ${placeholder}`;
2460
+ }
2461
+ function isSimpleWhere(where) {
2462
+ const keys = Object.keys(where);
2463
+ if (keys.length !== 1) return false;
2464
+ const key = keys[0];
2465
+ const value = where[key];
2466
+ if (value === null) return true;
2467
+ if (value === void 0) return false;
2468
+ if (typeof value === "string") return true;
2469
+ if (typeof value === "number") return true;
2470
+ if (typeof value === "boolean") return true;
2471
+ return false;
2472
+ }
2427
2473
  function buildWhereEntry(key, value, ctx, builder) {
2428
2474
  const op = asLogicalOperator(key);
2429
2475
  if (op) return buildLogical(op, value, ctx, builder);
@@ -2450,6 +2496,14 @@ function buildWhereInternal(where, ctx, builder) {
2450
2496
  if (isEmptyWhere(where)) {
2451
2497
  return freezeResult(DEFAULT_WHERE_CLAUSE, EMPTY_JOINS);
2452
2498
  }
2499
+ if (isSimpleWhere(where)) {
2500
+ const key = Object.keys(where)[0];
2501
+ const value = where[key];
2502
+ assertFieldExists(key, ctx.model, ctx.path);
2503
+ const expr = col(ctx.alias, key, ctx.model);
2504
+ const clause = buildSimpleEquality(expr, value, ctx);
2505
+ return freezeResult(clause, EMPTY_JOINS);
2506
+ }
2453
2507
  const allJoins = [];
2454
2508
  const clauses = [];
2455
2509
  for (const key in where) {
@@ -2576,10 +2630,16 @@ function buildOperator(expr, op, val, ctx, mode, fieldType) {
2576
2630
  }
2577
2631
 
2578
2632
  // src/builder/shared/alias-generator.ts
2633
+ var SAFE_IDENTIFIER_CACHE = /* @__PURE__ */ new Map();
2579
2634
  function toSafeSqlIdentifier(input) {
2635
+ const cached = SAFE_IDENTIFIER_CACHE.get(input);
2636
+ if (cached !== void 0) return cached;
2580
2637
  const raw = String(input);
2581
2638
  const n = raw.length;
2582
- if (n === 0) return "_t";
2639
+ if (n === 0) {
2640
+ SAFE_IDENTIFIER_CACHE.set(input, "_t");
2641
+ return "_t";
2642
+ }
2583
2643
  let out = "";
2584
2644
  for (let i = 0; i < n; i++) {
2585
2645
  const c = raw.charCodeAt(i);
@@ -2591,7 +2651,11 @@ function toSafeSqlIdentifier(input) {
2591
2651
  const c0 = out.charCodeAt(0);
2592
2652
  const startsOk = c0 >= 65 && c0 <= 90 || c0 >= 97 && c0 <= 122 || c0 === 95;
2593
2653
  const lowered = (startsOk ? out : `_${out}`).toLowerCase();
2594
- return ALIAS_FORBIDDEN_KEYWORDS.has(lowered) ? `_${lowered}` : lowered;
2654
+ const result = ALIAS_FORBIDDEN_KEYWORDS.has(lowered) ? `_${lowered}` : lowered;
2655
+ if (SAFE_IDENTIFIER_CACHE.size < 1e3) {
2656
+ SAFE_IDENTIFIER_CACHE.set(input, result);
2657
+ }
2658
+ return result;
2595
2659
  }
2596
2660
  function createAliasGenerator(maxAliases = 1e4) {
2597
2661
  let counter = 0;
@@ -2702,9 +2766,17 @@ function assertCanAddParam(currentIndex) {
2702
2766
  );
2703
2767
  }
2704
2768
  }
2705
- function formatPosition(position) {
2769
+ var POSTGRES_POSITION_CACHE = new Array(100);
2770
+ for (let i = 0; i < 100; i++) {
2771
+ POSTGRES_POSITION_CACHE[i] = `$${i + 1}`;
2772
+ }
2773
+ function formatPositionPostgres(position) {
2774
+ if (position <= 100) return POSTGRES_POSITION_CACHE[position - 1];
2706
2775
  return `$${position}`;
2707
2776
  }
2777
+ function formatPositionSqlite(_position) {
2778
+ return "?";
2779
+ }
2708
2780
  function validateDynamicName(dynamicName) {
2709
2781
  const dn = dynamicName.trim();
2710
2782
  if (dn.length === 0) {
@@ -2712,13 +2784,14 @@ function validateDynamicName(dynamicName) {
2712
2784
  }
2713
2785
  return dn;
2714
2786
  }
2715
- function createStoreInternal(startIndex, initialParams = [], initialMappings = []) {
2787
+ function createStoreInternal(startIndex, dialect, initialParams = [], initialMappings = []) {
2716
2788
  let index = startIndex;
2717
2789
  const params = initialParams.length > 0 ? initialParams.slice() : [];
2718
2790
  const mappings = initialMappings.length > 0 ? initialMappings.slice() : [];
2719
2791
  const dynamicNameToIndex = buildDynamicNameIndex(mappings);
2720
2792
  let dirty = true;
2721
2793
  let cachedSnapshot = null;
2794
+ const formatPosition = dialect === "sqlite" ? formatPositionSqlite : formatPositionPostgres;
2722
2795
  function addDynamic(dynamicName) {
2723
2796
  const dn = validateDynamicName(dynamicName);
2724
2797
  const existing = dynamicNameToIndex.get(dn);
@@ -2768,10 +2841,13 @@ function createStoreInternal(startIndex, initialParams = [], initialMappings = [
2768
2841
  snapshot,
2769
2842
  get index() {
2770
2843
  return index;
2844
+ },
2845
+ get dialect() {
2846
+ return dialect;
2771
2847
  }
2772
2848
  };
2773
2849
  }
2774
- function createParamStore(startIndex = 1) {
2850
+ function createParamStore(startIndex = 1, dialect = "postgres") {
2775
2851
  if (!Number.isInteger(startIndex) || startIndex < 1) {
2776
2852
  throw new Error(`Start index must be integer >= 1, got ${startIndex}`);
2777
2853
  }
@@ -2780,12 +2856,13 @@ function createParamStore(startIndex = 1) {
2780
2856
  `Start index too high (${startIndex}), risk of overflow at MAX_SAFE_INTEGER`
2781
2857
  );
2782
2858
  }
2783
- return createStoreInternal(startIndex);
2859
+ return createStoreInternal(startIndex, dialect);
2784
2860
  }
2785
- function createParamStoreFrom(existingParams, existingMappings, nextIndex) {
2861
+ function createParamStoreFrom(existingParams, existingMappings, nextIndex, dialect = "postgres") {
2786
2862
  validateState(existingParams, existingMappings, nextIndex);
2787
2863
  return createStoreInternal(
2788
2864
  nextIndex,
2865
+ dialect,
2789
2866
  existingParams.slice(),
2790
2867
  existingMappings.slice()
2791
2868
  );
@@ -2826,6 +2903,7 @@ function buildWhereClause(where, options) {
2826
2903
  }
2827
2904
 
2828
2905
  // src/builder/select/fields.ts
2906
+ var DEFAULT_SELECT_CACHE = /* @__PURE__ */ new WeakMap();
2829
2907
  function toSelectEntries(select) {
2830
2908
  const out = [];
2831
2909
  for (const [k, v] of Object.entries(select)) {
@@ -2873,13 +2951,29 @@ function buildDefaultScalarFields(model, alias) {
2873
2951
  }
2874
2952
  return out;
2875
2953
  }
2954
+ function getDefaultSelectCached(model, alias) {
2955
+ var _a;
2956
+ return (_a = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a.get(alias);
2957
+ }
2958
+ function cacheDefaultSelect(model, alias, sql) {
2959
+ let cache = DEFAULT_SELECT_CACHE.get(model);
2960
+ if (!cache) {
2961
+ cache = /* @__PURE__ */ new Map();
2962
+ DEFAULT_SELECT_CACHE.set(model, cache);
2963
+ }
2964
+ cache.set(alias, sql);
2965
+ }
2876
2966
  function buildSelectFields(args, model, alias) {
2877
2967
  const scalarSet = getScalarFieldSet(model);
2878
2968
  const relationSet = getRelationFieldSet(model);
2879
2969
  if (!isNotNullish(args.select)) {
2880
- return buildDefaultScalarFields(model, alias).join(
2970
+ const cached = getDefaultSelectCached(model, alias);
2971
+ if (cached) return cached;
2972
+ const result = buildDefaultScalarFields(model, alias).join(
2881
2973
  SQL_SEPARATORS.FIELD_LIST
2882
2974
  );
2975
+ cacheDefaultSelect(model, alias, result);
2976
+ return result;
2883
2977
  }
2884
2978
  const entries = toSelectEntries(args.select);
2885
2979
  validateSelectKeys(entries, scalarSet, relationSet);
@@ -2957,8 +3051,6 @@ function buildRelationSelect(relArgs, relModel, relAlias) {
2957
3051
  }
2958
3052
  return buildAllScalarParts(relModel, relAlias).join(SQL_SEPARATORS.FIELD_LIST);
2959
3053
  }
2960
-
2961
- // src/builder/select/includes.ts
2962
3054
  var MAX_INCLUDE_DEPTH = 10;
2963
3055
  var MAX_TOTAL_SUBQUERIES = 100;
2964
3056
  var MAX_TOTAL_INCLUDES = 50;
@@ -3146,8 +3238,12 @@ function buildWhereParts(whereInput, relModel, relAlias, ctx) {
3146
3238
  dialect: ctx.dialect
3147
3239
  });
3148
3240
  const joins = whereResult.joins.join(" ");
3149
- const whereClause = isValidWhereClause(whereResult.clause) ? ` ${SQL_TEMPLATES.AND} ${whereResult.clause}` : "";
3150
- return { joins, whereClause };
3241
+ const hasClause = isValidWhereClause(whereResult.clause);
3242
+ return {
3243
+ joins,
3244
+ whereClause: hasClause ? ` ${SQL_TEMPLATES.AND} ${whereResult.clause}` : "",
3245
+ rawClause: hasClause ? whereResult.clause : ""
3246
+ };
3151
3247
  }
3152
3248
  function limitOneSql(sql, params, skipVal, scope) {
3153
3249
  if (isNotNullish(skipVal)) {
@@ -3192,8 +3288,10 @@ function buildListIncludeSpec(args) {
3192
3288
  const rowExpr = jsonBuildObject(args.relSelect, args.ctx.dialect);
3193
3289
  const noTake = !isNotNullish(args.takeVal);
3194
3290
  const noSkip = !isNotNullish(args.skipVal);
3291
+ const emptyJson = args.ctx.dialect === "postgres" ? `'[]'::json` : `json('[]')`;
3195
3292
  if (args.ctx.dialect === "postgres" && noTake && noSkip) {
3196
- const selectExpr2 = args.orderBySql ? `json_agg(${rowExpr} ORDER BY ${args.orderBySql})` : `json_agg(${rowExpr})`;
3293
+ const rawAgg = args.orderBySql ? `json_agg(${rowExpr} ORDER BY ${args.orderBySql})` : `json_agg(${rowExpr})`;
3294
+ const selectExpr2 = `COALESCE(${rawAgg}, ${emptyJson})`;
3197
3295
  const sql2 = buildBaseSql({
3198
3296
  selectExpr: selectExpr2,
3199
3297
  relTable: args.relTable,
@@ -3223,10 +3321,154 @@ function buildListIncludeSpec(args) {
3223
3321
  args.skipVal,
3224
3322
  scopeBase
3225
3323
  );
3226
- const selectExpr = jsonAgg("row", args.ctx.dialect);
3324
+ const agg = jsonAgg("row", args.ctx.dialect);
3325
+ const selectExpr = `COALESCE(${agg}, ${emptyJson})`;
3227
3326
  const sql = `${SQL_TEMPLATES.SELECT} ${selectExpr} ${SQL_TEMPLATES.FROM} (${base}) ${SQL_TEMPLATES.AS} ${rowAlias}`;
3228
3327
  return Object.freeze({ name: args.relName, sql, isOneToOne: false });
3229
3328
  }
3329
+ function resolveIncludeKeyPairs(field) {
3330
+ const fkFields = normalizeKeyList(field.foreignKey);
3331
+ if (fkFields.length === 0) {
3332
+ throw new Error(
3333
+ `Relation '${field.name}' is missing foreignKey for join-based include`
3334
+ );
3335
+ }
3336
+ const refs = normalizeKeyList(field.references);
3337
+ const refFields = refs.length > 0 ? refs : fkFields.length === 1 ? ["id"] : [];
3338
+ if (refFields.length !== fkFields.length) {
3339
+ throw new Error(
3340
+ `Relation '${field.name}' references count doesn't match foreignKey count`
3341
+ );
3342
+ }
3343
+ return {
3344
+ relKeyFields: field.isForeignKeyLocal ? refFields : fkFields,
3345
+ parentKeyFields: field.isForeignKeyLocal ? fkFields : refFields
3346
+ };
3347
+ }
3348
+ function buildFkSelectList(relAlias, relModel, relKeyFields) {
3349
+ return relKeyFields.map((f, i) => `${relAlias}.${quoteColumn(relModel, f)} AS "__fk${i}"`).join(SQL_SEPARATORS.FIELD_LIST);
3350
+ }
3351
+ function buildFkGroupByUnqualified(relKeyFields) {
3352
+ return relKeyFields.map((_, i) => `"__fk${i}"`).join(SQL_SEPARATORS.FIELD_LIST);
3353
+ }
3354
+ function buildJoinOnCondition(joinAlias, parentAlias, parentModel, parentKeyFields) {
3355
+ const parts = parentKeyFields.map(
3356
+ (f, i) => `${joinAlias}."__fk${i}" = ${parentAlias}.${quoteColumn(parentModel, f)}`
3357
+ );
3358
+ return parts.length === 1 ? parts[0] : `(${parts.join(" AND ")})`;
3359
+ }
3360
+ function buildPartitionBy(relAlias, relModel, relKeyFields) {
3361
+ return relKeyFields.map((f) => `${relAlias}.${quoteColumn(relModel, f)}`).join(SQL_SEPARATORS.FIELD_LIST);
3362
+ }
3363
+ function hasNestedRelationInArgs(relArgs, relModel) {
3364
+ if (!isPlainObject(relArgs)) return false;
3365
+ const relationSet = getRelationFieldSet(relModel);
3366
+ const checkSource = (src) => {
3367
+ if (!isPlainObject(src)) return false;
3368
+ for (const k of Object.keys(src)) {
3369
+ if (relationSet.has(k) && src[k] !== false)
3370
+ return true;
3371
+ }
3372
+ return false;
3373
+ };
3374
+ if (checkSource(relArgs.include)) return true;
3375
+ if (checkSource(relArgs.select)) return true;
3376
+ return false;
3377
+ }
3378
+ function canUseJoinInclude(dialect, isList, takeVal, skipVal, depth, outerHasLimit, hasNestedIncludes2) {
3379
+ if (dialect !== "postgres") return false;
3380
+ if (!isList) return false;
3381
+ if (depth > 0) return false;
3382
+ if (outerHasLimit) return false;
3383
+ if (hasNestedIncludes2) return false;
3384
+ if (isDynamicParameter(takeVal) || isDynamicParameter(skipVal)) return false;
3385
+ return true;
3386
+ }
3387
+ function buildJoinBasedNonPaginated(args) {
3388
+ const { relKeyFields, parentKeyFields } = resolveIncludeKeyPairs(args.field);
3389
+ const joinAlias = args.ctx.aliasGen.next(`__inc_${args.relName}`);
3390
+ const fkSelect = buildFkSelectList(args.relAlias, args.relModel, relKeyFields);
3391
+ const fkGroupBy = buildPartitionBy(args.relAlias, args.relModel, relKeyFields);
3392
+ const rowExpr = jsonBuildObject(args.relSelect, args.ctx.dialect);
3393
+ const aggExpr = args.orderBySql ? `json_agg(${rowExpr} ORDER BY ${args.orderBySql})` : `json_agg(${rowExpr})`;
3394
+ const joinsPart = args.whereJoins ? ` ${args.whereJoins}` : "";
3395
+ const wherePart = args.rawWhereClause ? ` ${SQL_TEMPLATES.WHERE} ${args.rawWhereClause}` : "";
3396
+ const subquery = `SELECT ${fkSelect}${SQL_SEPARATORS.FIELD_LIST}${aggExpr} AS __agg FROM ${args.relTable} ${args.relAlias}${joinsPart}${wherePart} GROUP BY ${fkGroupBy}`;
3397
+ const onCondition = buildJoinOnCondition(
3398
+ joinAlias,
3399
+ args.ctx.parentAlias,
3400
+ args.ctx.model,
3401
+ parentKeyFields
3402
+ );
3403
+ const joinSql = `LEFT JOIN (${subquery}) ${joinAlias} ON ${onCondition}`;
3404
+ const selectExpr = `COALESCE(${joinAlias}.__agg, '[]'::json) AS ${quote(args.relName)}`;
3405
+ return Object.freeze({
3406
+ name: args.relName,
3407
+ sql: "",
3408
+ isOneToOne: false,
3409
+ joinSql,
3410
+ selectExpr
3411
+ });
3412
+ }
3413
+ function buildJoinBasedPaginated(args) {
3414
+ const { relKeyFields, parentKeyFields } = resolveIncludeKeyPairs(args.field);
3415
+ const joinAlias = args.ctx.aliasGen.next(`__inc_${args.relName}`);
3416
+ const rankedAlias = args.ctx.aliasGen.next(`__ranked_${args.relName}`);
3417
+ const fkSelect = buildFkSelectList(args.relAlias, args.relModel, relKeyFields);
3418
+ const partitionBy = buildPartitionBy(
3419
+ args.relAlias,
3420
+ args.relModel,
3421
+ relKeyFields
3422
+ );
3423
+ const rowExpr = jsonBuildObject(args.relSelect, args.ctx.dialect);
3424
+ const orderExpr = args.orderBySql || `${args.relAlias}.${quoteColumn(args.relModel, "id")} ASC`;
3425
+ const joinsPart = args.whereJoins ? ` ${args.whereJoins}` : "";
3426
+ const wherePart = args.rawWhereClause ? ` ${SQL_TEMPLATES.WHERE} ${args.rawWhereClause}` : "";
3427
+ const innerSql = `SELECT ${fkSelect}${SQL_SEPARATORS.FIELD_LIST}${rowExpr} AS __row${SQL_SEPARATORS.FIELD_LIST}ROW_NUMBER() OVER (PARTITION BY ${partitionBy} ORDER BY ${orderExpr}) AS __rn FROM ${args.relTable} ${args.relAlias}${joinsPart}${wherePart}`;
3428
+ const scopeBase = buildIncludeScope(args.ctx.includePath);
3429
+ const rnFilterParts = [];
3430
+ if (isNotNullish(args.skipVal) && args.skipVal > 0) {
3431
+ const skipPh = addAutoScoped(
3432
+ args.ctx.params,
3433
+ args.skipVal,
3434
+ `${scopeBase}.skip`
3435
+ );
3436
+ rnFilterParts.push(`__rn > ${skipPh}`);
3437
+ if (isNotNullish(args.takeVal)) {
3438
+ const takePh = addAutoScoped(
3439
+ args.ctx.params,
3440
+ args.takeVal,
3441
+ `${scopeBase}.take`
3442
+ );
3443
+ rnFilterParts.push(`__rn <= (${skipPh} + ${takePh})`);
3444
+ }
3445
+ } else if (isNotNullish(args.takeVal)) {
3446
+ const takePh = addAutoScoped(
3447
+ args.ctx.params,
3448
+ args.takeVal,
3449
+ `${scopeBase}.take`
3450
+ );
3451
+ rnFilterParts.push(`__rn <= ${takePh}`);
3452
+ }
3453
+ const rnFilter = rnFilterParts.length > 0 ? ` ${SQL_TEMPLATES.WHERE} ${rnFilterParts.join(SQL_SEPARATORS.CONDITION_AND)}` : "";
3454
+ const fkGroupByOuter = buildFkGroupByUnqualified(relKeyFields);
3455
+ const outerSql = `SELECT ${fkGroupByOuter}${SQL_SEPARATORS.FIELD_LIST}json_agg(__row ORDER BY __rn) AS __agg FROM (${innerSql}) ${rankedAlias}${rnFilter} GROUP BY ${fkGroupByOuter}`;
3456
+ const onCondition = buildJoinOnCondition(
3457
+ joinAlias,
3458
+ args.ctx.parentAlias,
3459
+ args.ctx.model,
3460
+ parentKeyFields
3461
+ );
3462
+ const joinSql = `LEFT JOIN (${outerSql}) ${joinAlias} ON ${onCondition}`;
3463
+ const selectExpr = `COALESCE(${joinAlias}.__agg, '[]'::json) AS ${quote(args.relName)}`;
3464
+ return Object.freeze({
3465
+ name: args.relName,
3466
+ sql: "",
3467
+ isOneToOne: false,
3468
+ joinSql,
3469
+ selectExpr
3470
+ });
3471
+ }
3230
3472
  function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3231
3473
  const relTable = getRelationTableReference(relModel, ctx.dialect);
3232
3474
  const relAlias = ctx.aliasGen.next(relName);
@@ -3283,6 +3525,48 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3283
3525
  });
3284
3526
  return Object.freeze({ name: relName, sql, isOneToOne: true });
3285
3527
  }
3528
+ const depth = ctx.depth || 0;
3529
+ const outerHasLimit = ctx.outerHasLimit === true;
3530
+ const nestedIncludes = hasNestedRelationInArgs(relArgs, relModel);
3531
+ if (canUseJoinInclude(
3532
+ ctx.dialect,
3533
+ isList,
3534
+ adjusted.takeVal,
3535
+ paginationConfig.skipVal,
3536
+ depth,
3537
+ outerHasLimit,
3538
+ nestedIncludes
3539
+ )) {
3540
+ const hasTakeOrSkip = isNotNullish(adjusted.takeVal) || isNotNullish(paginationConfig.skipVal);
3541
+ if (!hasTakeOrSkip) {
3542
+ return buildJoinBasedNonPaginated({
3543
+ relName,
3544
+ relTable,
3545
+ relAlias,
3546
+ relModel,
3547
+ field,
3548
+ whereJoins: whereParts.joins,
3549
+ rawWhereClause: whereParts.rawClause,
3550
+ orderBySql,
3551
+ relSelect,
3552
+ ctx
3553
+ });
3554
+ }
3555
+ return buildJoinBasedPaginated({
3556
+ relName,
3557
+ relTable,
3558
+ relAlias,
3559
+ relModel,
3560
+ field,
3561
+ whereJoins: whereParts.joins,
3562
+ rawWhereClause: whereParts.rawClause,
3563
+ orderBySql,
3564
+ relSelect,
3565
+ takeVal: adjusted.takeVal,
3566
+ skipVal: paginationConfig.skipVal,
3567
+ ctx
3568
+ });
3569
+ }
3286
3570
  return buildListIncludeSpec({
3287
3571
  relName,
3288
3572
  relTable,
@@ -3352,14 +3636,14 @@ function buildIncludeSqlInternal(args, ctx) {
3352
3636
  buildSingleInclude(relName, relArgs, resolved.field, resolved.relModel, __spreadProps(__spreadValues({}, ctx), {
3353
3637
  includePath: nextIncludePath,
3354
3638
  visitPath: currentPath,
3355
- depth: depth + 1,
3639
+ depth,
3356
3640
  stats
3357
3641
  }))
3358
3642
  );
3359
3643
  }
3360
3644
  return includes;
3361
3645
  }
3362
- function buildIncludeSql(args, model, schemas, parentAlias, params, dialect) {
3646
+ function buildIncludeSql(args, model, schemas, parentAlias, params, dialect, outerHasLimit = true) {
3363
3647
  const aliasGen = createAliasGenerator();
3364
3648
  const stats = {
3365
3649
  totalIncludes: 0,
@@ -3379,7 +3663,8 @@ function buildIncludeSql(args, model, schemas, parentAlias, params, dialect) {
3379
3663
  includePath: [],
3380
3664
  visitPath: [],
3381
3665
  depth: 0,
3382
- stats
3666
+ stats,
3667
+ outerHasLimit
3383
3668
  });
3384
3669
  }
3385
3670
  function resolveCountRelationOrThrow(relName, model, schemaByName) {
@@ -3417,7 +3702,7 @@ function resolveCountRelationOrThrow(relName, model, schemaByName) {
3417
3702
  function defaultReferencesForCount(fkCount) {
3418
3703
  if (fkCount === 1) return ["id"];
3419
3704
  throw new Error(
3420
- "Relation count for composite keys requires explicit references matching foreignKey length"
3705
+ "Relation count for composite keys requires explicit references matching..."
3421
3706
  );
3422
3707
  }
3423
3708
  function resolveCountKeyPairs(field) {
@@ -3526,6 +3811,307 @@ function joinNonEmpty(parts, sep) {
3526
3811
  }
3527
3812
  return result;
3528
3813
  }
3814
+
3815
+ // src/builder/select/flat-join.ts
3816
+ function getPrimaryKeyField(model) {
3817
+ const scalarSet = getScalarFieldSet(model);
3818
+ for (const f of model.fields) {
3819
+ if (f.isId && !f.isRelation && scalarSet.has(f.name)) {
3820
+ return f.name;
3821
+ }
3822
+ }
3823
+ if (scalarSet.has("id")) return "id";
3824
+ throw new Error(
3825
+ `Model ${model.name} has no primary key field. Models must have either a field with isId=true or a field named 'id'.`
3826
+ );
3827
+ }
3828
+ function findPrimaryKeyFields(model) {
3829
+ const pkFields = model.fields.filter((f) => f.isId && !f.isRelation);
3830
+ if (pkFields.length > 0) return pkFields.map((f) => f.name);
3831
+ const idField = model.fields.find((f) => f.name === "id" && !f.isRelation);
3832
+ if (idField) return ["id"];
3833
+ throw new Error(`Model ${model.name} has no primary key field`);
3834
+ }
3835
+ function getRelationModel(parentModel, relationName, schemas) {
3836
+ const field = parentModel.fields.find((f) => f.name === relationName);
3837
+ if (!(field == null ? void 0 : field.isRelation) || !field.relatedModel) {
3838
+ throw new Error(`Invalid relation ${relationName} on ${parentModel.name}`);
3839
+ }
3840
+ const relModel = schemas.find((m) => m.name === field.relatedModel);
3841
+ if (!relModel) {
3842
+ throw new Error(`Related model ${field.relatedModel} not found`);
3843
+ }
3844
+ return relModel;
3845
+ }
3846
+ function extractIncludeSpecFromArgs(args, model) {
3847
+ const includeSpec = {};
3848
+ const relationSet = getRelationFieldSet(model);
3849
+ if (args.include && isPlainObject(args.include)) {
3850
+ for (const [key, value] of Object.entries(args.include)) {
3851
+ if (value !== false) includeSpec[key] = value;
3852
+ }
3853
+ }
3854
+ if (args.select && isPlainObject(args.select)) {
3855
+ for (const [key, value] of Object.entries(args.select)) {
3856
+ if (!relationSet.has(key)) continue;
3857
+ if (value === false) continue;
3858
+ if (value === true) {
3859
+ includeSpec[key] = true;
3860
+ continue;
3861
+ }
3862
+ if (isPlainObject(value)) {
3863
+ const v = value;
3864
+ if (isPlainObject(v.include) || isPlainObject(v.select)) {
3865
+ includeSpec[key] = value;
3866
+ }
3867
+ }
3868
+ }
3869
+ }
3870
+ return includeSpec;
3871
+ }
3872
+ function hasChildPagination(relArgs) {
3873
+ if (!isPlainObject(relArgs)) return false;
3874
+ const args = relArgs;
3875
+ if (args.take !== void 0 && args.take !== null) return true;
3876
+ if (args.skip !== void 0 && args.skip !== null) return true;
3877
+ return false;
3878
+ }
3879
+ function extractNestedIncludeSpec(relArgs, relModel) {
3880
+ const relationSet = getRelationFieldSet(relModel);
3881
+ const out = {};
3882
+ if (!isPlainObject(relArgs)) return out;
3883
+ const obj = relArgs;
3884
+ if (isPlainObject(obj.include)) {
3885
+ for (const [k, v] of Object.entries(
3886
+ obj.include
3887
+ )) {
3888
+ if (!relationSet.has(k)) continue;
3889
+ if (v === false) continue;
3890
+ out[k] = v;
3891
+ }
3892
+ }
3893
+ if (isPlainObject(obj.select)) {
3894
+ for (const [k, v] of Object.entries(
3895
+ obj.select
3896
+ )) {
3897
+ if (!relationSet.has(k)) continue;
3898
+ if (v === false) continue;
3899
+ if (v === true) {
3900
+ out[k] = true;
3901
+ continue;
3902
+ }
3903
+ if (isPlainObject(v)) {
3904
+ const vv = v;
3905
+ if (isPlainObject(vv.include) || isPlainObject(vv.select)) {
3906
+ out[k] = v;
3907
+ }
3908
+ }
3909
+ }
3910
+ }
3911
+ return out;
3912
+ }
3913
+ function extractSelectedScalarFields(relArgs, relModel) {
3914
+ const scalarFields = relModel.fields.filter((f) => !f.isRelation).map((f) => f.name);
3915
+ const scalarSet = new Set(scalarFields);
3916
+ if (relArgs === true || !isPlainObject(relArgs)) {
3917
+ return { includeAllScalars: true, selected: scalarFields };
3918
+ }
3919
+ const obj = relArgs;
3920
+ if (!isPlainObject(obj.select)) {
3921
+ return { includeAllScalars: true, selected: scalarFields };
3922
+ }
3923
+ const sel = obj.select;
3924
+ const selected = [];
3925
+ for (const [k, v] of Object.entries(sel)) {
3926
+ if (!scalarSet.has(k)) continue;
3927
+ if (v === true) selected.push(k);
3928
+ }
3929
+ return { includeAllScalars: false, selected };
3930
+ }
3931
+ function uniqPreserveOrder(items) {
3932
+ const seen = /* @__PURE__ */ new Set();
3933
+ const out = [];
3934
+ for (const it of items) {
3935
+ if (seen.has(it)) continue;
3936
+ seen.add(it);
3937
+ out.push(it);
3938
+ }
3939
+ return out;
3940
+ }
3941
+ function buildChildColumns(args) {
3942
+ const { relModel, relationName, childAlias, prefix, relArgs } = args;
3943
+ const fullPrefix = prefix ? `${prefix}.${relationName}` : relationName;
3944
+ const pkFields = findPrimaryKeyFields(relModel);
3945
+ const scalarSelection = extractSelectedScalarFields(relArgs, relModel);
3946
+ const selectedScalar = scalarSelection.selected;
3947
+ const required = uniqPreserveOrder([...pkFields, ...selectedScalar]);
3948
+ const columns = [];
3949
+ for (const fieldName of required) {
3950
+ const field = relModel.fields.find(
3951
+ (f) => f.name === fieldName && !f.isRelation
3952
+ );
3953
+ if (!field) continue;
3954
+ const colName = field.dbName || field.name;
3955
+ const quotedCol = quote(colName);
3956
+ columns.push(`${childAlias}.${quotedCol} AS "${fullPrefix}.${field.name}"`);
3957
+ }
3958
+ return columns;
3959
+ }
3960
+ function canUseNestedFlatJoin(relArgs, depth) {
3961
+ if (depth > 10) return false;
3962
+ if (!isPlainObject(relArgs)) return true;
3963
+ if (hasChildPagination(relArgs)) return false;
3964
+ const obj = relArgs;
3965
+ if (obj.include && isPlainObject(obj.include)) {
3966
+ for (const childValue of Object.values(
3967
+ obj.include
3968
+ )) {
3969
+ if (childValue !== false && !canUseNestedFlatJoin(childValue, depth + 1))
3970
+ return false;
3971
+ }
3972
+ }
3973
+ if (obj.select && isPlainObject(obj.select)) {
3974
+ for (const childValue of Object.values(
3975
+ obj.select
3976
+ )) {
3977
+ if (childValue !== false && !canUseNestedFlatJoin(childValue, depth + 1))
3978
+ return false;
3979
+ }
3980
+ }
3981
+ return true;
3982
+ }
3983
+ function canUseFlatJoinForAll(includeSpec) {
3984
+ for (const value of Object.values(includeSpec)) {
3985
+ if (value === false) continue;
3986
+ if (!canUseNestedFlatJoin(value, 0)) return false;
3987
+ }
3988
+ return true;
3989
+ }
3990
+ function buildNestedJoins(parentModel, parentAlias, includeSpec, schemas, dialect, prefix, aliasCounter, depth = 0) {
3991
+ if (depth > 10) {
3992
+ throw new Error(
3993
+ `Nested joins exceeded maximum depth of 10 at prefix '${prefix}'`
3994
+ );
3995
+ }
3996
+ const joins = [];
3997
+ const selects = [];
3998
+ const orderBy = [];
3999
+ for (const [relName, relValue] of Object.entries(includeSpec)) {
4000
+ if (relValue === false) continue;
4001
+ const field = parentModel.fields.find((f) => f.name === relName);
4002
+ if (!isValidRelationField(field)) continue;
4003
+ const relModel = getRelationModel(parentModel, relName, schemas);
4004
+ const relTable = buildTableReference(
4005
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
4006
+ relModel.tableName,
4007
+ dialect
4008
+ );
4009
+ const childAlias = `fj_${aliasCounter.count++}`;
4010
+ const joinCond = joinCondition(
4011
+ field,
4012
+ parentModel,
4013
+ relModel,
4014
+ parentAlias,
4015
+ childAlias
4016
+ );
4017
+ joins.push(`LEFT JOIN ${relTable} ${childAlias} ON ${joinCond}`);
4018
+ selects.push(
4019
+ ...buildChildColumns({
4020
+ relModel,
4021
+ relationName: relName,
4022
+ childAlias,
4023
+ prefix,
4024
+ relArgs: relValue
4025
+ })
4026
+ );
4027
+ const childPkFields = findPrimaryKeyFields(relModel);
4028
+ for (const pkField of childPkFields) {
4029
+ orderBy.push(
4030
+ `${childAlias}.${quoteColumn(relModel, pkField)} ASC NULLS LAST`
4031
+ );
4032
+ }
4033
+ const nested = extractNestedIncludeSpec(relValue, relModel);
4034
+ if (Object.keys(nested).length > 0) {
4035
+ const nestedPrefix = prefix ? `${prefix}.${relName}` : relName;
4036
+ const deeper = buildNestedJoins(
4037
+ relModel,
4038
+ childAlias,
4039
+ nested,
4040
+ schemas,
4041
+ dialect,
4042
+ nestedPrefix,
4043
+ aliasCounter,
4044
+ depth + 1
4045
+ );
4046
+ joins.push(...deeper.joins);
4047
+ selects.push(...deeper.selects);
4048
+ orderBy.push(...deeper.orderBy);
4049
+ }
4050
+ }
4051
+ return { joins, selects, orderBy };
4052
+ }
4053
+ function buildFlatJoinSql(spec) {
4054
+ const {
4055
+ select,
4056
+ from,
4057
+ whereClause,
4058
+ whereJoins,
4059
+ orderBy,
4060
+ dialect,
4061
+ model,
4062
+ schemas,
4063
+ args
4064
+ } = spec;
4065
+ const includeSpec = extractIncludeSpecFromArgs(args, model);
4066
+ if (Object.keys(includeSpec).length === 0) {
4067
+ return { sql: "", requiresReduction: false, includeSpec: {} };
4068
+ }
4069
+ if (!canUseFlatJoinForAll(includeSpec)) {
4070
+ return { sql: "", requiresReduction: false, includeSpec: {} };
4071
+ }
4072
+ const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
4073
+ const baseWhere = whereClause && whereClause !== "1=1" ? `WHERE ${whereClause}` : "";
4074
+ const baseOrderBy = orderBy ? `ORDER BY ${orderBy}` : "";
4075
+ let baseSubquery = `
4076
+ SELECT * FROM ${from.table} ${from.alias}
4077
+ ${baseJoins}
4078
+ ${baseWhere}
4079
+ ${baseOrderBy}
4080
+ `.trim();
4081
+ baseSubquery = appendPagination(baseSubquery, spec);
4082
+ const aliasCounter = { count: 0 };
4083
+ const built = buildNestedJoins(
4084
+ model,
4085
+ from.alias,
4086
+ includeSpec,
4087
+ schemas,
4088
+ dialect,
4089
+ "",
4090
+ aliasCounter,
4091
+ 0
4092
+ );
4093
+ if (built.joins.length === 0) {
4094
+ return { sql: "", requiresReduction: false, includeSpec: {} };
4095
+ }
4096
+ const baseSelect = (select != null ? select : "").trim();
4097
+ const allSelects = [baseSelect, ...built.selects].filter((s) => s && s.trim().length > 0).join(SQL_SEPARATORS.FIELD_LIST);
4098
+ if (!allSelects) {
4099
+ throw new Error("Flat-join SELECT requires at least one selected field");
4100
+ }
4101
+ const pkField = getPrimaryKeyField(model);
4102
+ const orderByParts = [];
4103
+ if (orderBy) orderByParts.push(orderBy);
4104
+ orderByParts.push(`${from.alias}.${quoteColumn(model, pkField)} ASC`);
4105
+ orderByParts.push(...built.orderBy);
4106
+ const finalOrderBy = orderByParts.join(", ");
4107
+ const sql = `
4108
+ SELECT ${allSelects}
4109
+ FROM (${baseSubquery}) ${from.alias}
4110
+ ${built.joins.join(" ")}
4111
+ ORDER BY ${finalOrderBy}
4112
+ `.trim();
4113
+ return { sql, requiresReduction: true, includeSpec };
4114
+ }
3529
4115
  function buildWhereSql(conditions) {
3530
4116
  if (!isNonEmptyArray(conditions)) return "";
3531
4117
  return " " + SQL_TEMPLATES.WHERE + " " + conditions.join(SQL_SEPARATORS.CONDITION_AND);
@@ -3560,9 +4146,6 @@ function finalizeSql(sql, params, dialect) {
3560
4146
  paramMappings: snapshot.mappings
3561
4147
  };
3562
4148
  }
3563
- function isIdent(s) {
3564
- return /^[A-Za-z_]\w*$/.test(s);
3565
- }
3566
4149
  function skipSpaces(s, i) {
3567
4150
  while (i < s.length) {
3568
4151
  const c = s.charCodeAt(i);
@@ -3656,11 +4239,6 @@ function parseSelectField(p, fromAlias) {
3656
4239
  i = skipSpaces(p, i);
3657
4240
  const a = readIdentOrQuoted(p, i);
3658
4241
  const actualAlias = a.text.toLowerCase();
3659
- if (!isIdent(a.text)) {
3660
- throw new Error(
3661
- `sqlite distinct emulation requires scalar select fields to be simple columns (alias.column). Got: ${p}`
3662
- );
3663
- }
3664
4242
  if (actualAlias !== fromLower) {
3665
4243
  throw new Error(`Expected alias '${fromAlias}', got '${a.text}' in: ${p}`);
3666
4244
  }
@@ -3729,10 +4307,10 @@ function extractDistinctOrderEntries(spec) {
3729
4307
  const value = item[field];
3730
4308
  if (typeof value === "string") {
3731
4309
  entries.push({ field, direction: value });
3732
- } else {
3733
- const obj = value;
3734
- entries.push({ field, direction: obj.sort, nulls: obj.nulls });
4310
+ continue;
3735
4311
  }
4312
+ const obj = value;
4313
+ entries.push({ field, direction: obj.direction, nulls: obj.nulls });
3736
4314
  }
3737
4315
  }
3738
4316
  if (entries.length > 0) return entries;
@@ -3866,19 +4444,43 @@ function buildIncludeColumns(spec) {
3866
4444
  const hasIncludes = isNonEmptyArray(includes);
3867
4445
  const hasCountCols = isNonEmptyString(countCols);
3868
4446
  if (!hasIncludes && !hasCountCols) {
3869
- return { includeCols: "", selectWithIncludes: baseSelect, countJoins: [] };
4447
+ return {
4448
+ includeCols: "",
4449
+ selectWithIncludes: baseSelect,
4450
+ countJoins: [],
4451
+ includeJoins: []
4452
+ };
3870
4453
  }
3871
4454
  const emptyJson = dialect === "postgres" ? `'[]'::json` : `json('[]')`;
3872
- const includeCols = hasIncludes ? includes.map((inc) => {
3873
- const expr = inc.isOneToOne ? "(" + inc.sql + ")" : "COALESCE((" + inc.sql + "), " + emptyJson + ")";
3874
- return expr + " " + SQL_TEMPLATES.AS + " " + quote(inc.name);
3875
- }).join(SQL_SEPARATORS.FIELD_LIST) : "";
3876
- const allCols = joinNonEmpty(
3877
- [includeCols, countCols],
4455
+ const correlatedParts = [];
4456
+ const joinIncludeJoins = [];
4457
+ const joinIncludeSelects = [];
4458
+ if (hasIncludes) {
4459
+ for (const inc of includes) {
4460
+ if (inc.joinSql && inc.selectExpr) {
4461
+ joinIncludeJoins.push(inc.joinSql);
4462
+ joinIncludeSelects.push(inc.selectExpr);
4463
+ } else {
4464
+ const expr = inc.isOneToOne ? "(" + inc.sql + ")" : "COALESCE((" + inc.sql + "), " + emptyJson + ")";
4465
+ correlatedParts.push(
4466
+ expr + " " + SQL_TEMPLATES.AS + " " + quote(inc.name)
4467
+ );
4468
+ }
4469
+ }
4470
+ }
4471
+ const correlatedCols = correlatedParts.join(SQL_SEPARATORS.FIELD_LIST);
4472
+ const joinSelectCols = joinIncludeSelects.join(SQL_SEPARATORS.FIELD_LIST);
4473
+ const allIncludeCols = joinNonEmpty(
4474
+ [correlatedCols, joinSelectCols, countCols],
3878
4475
  SQL_SEPARATORS.FIELD_LIST
3879
4476
  );
3880
- const selectWithIncludes = buildSelectList(baseSelect, allCols);
3881
- return { includeCols: allCols, selectWithIncludes, countJoins };
4477
+ const selectWithIncludes = buildSelectList(baseSelect, allIncludeCols);
4478
+ return {
4479
+ includeCols: allIncludeCols,
4480
+ selectWithIncludes,
4481
+ countJoins,
4482
+ includeJoins: joinIncludeJoins
4483
+ };
3882
4484
  }
3883
4485
  function appendPagination(sql, spec) {
3884
4486
  const { method, pagination, params } = spec;
@@ -3916,9 +4518,13 @@ function appendPagination(sql, spec) {
3916
4518
  return parts.join(" ");
3917
4519
  }
3918
4520
  function hasWindowDistinct(spec) {
4521
+ if (spec.dialect !== "sqlite") return false;
3919
4522
  const d = spec.distinct;
3920
4523
  return isNotNullish(d) && isNonEmptyArray(d);
3921
4524
  }
4525
+ function hasAnyDistinct(spec) {
4526
+ return isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct);
4527
+ }
3922
4528
  function assertDistinctAllowed(method, enabled) {
3923
4529
  if (enabled && method !== "findMany") {
3924
4530
  throw new Error(
@@ -3926,11 +4532,6 @@ function assertDistinctAllowed(method, enabled) {
3926
4532
  );
3927
4533
  }
3928
4534
  }
3929
- function assertHasSelectFields(baseSelect, includeCols) {
3930
- if (!isNonEmptyString(baseSelect) && !isNonEmptyString(includeCols)) {
3931
- throw new Error("SELECT requires at least one selected field or include");
3932
- }
3933
- }
3934
4535
  function withCountJoins(spec, countJoins, whereJoins) {
3935
4536
  return __spreadProps(__spreadValues({}, spec), {
3936
4537
  whereJoins: [...whereJoins || [], ...countJoins || []]
@@ -3957,6 +4558,63 @@ function pushWhere(parts, conditions) {
3957
4558
  if (!isNonEmptyArray(conditions)) return;
3958
4559
  parts.push(SQL_TEMPLATES.WHERE, conditions.join(SQL_SEPARATORS.CONDITION_AND));
3959
4560
  }
4561
+ function extractIncludeSpec(args) {
4562
+ const includeSpec = {};
4563
+ if (args.include && isPlainObject(args.include)) {
4564
+ for (const [key, value] of Object.entries(args.include)) {
4565
+ if (value !== false) {
4566
+ includeSpec[key] = value;
4567
+ }
4568
+ }
4569
+ }
4570
+ if (args.select && isPlainObject(args.select)) {
4571
+ for (const [key, value] of Object.entries(args.select)) {
4572
+ if (value !== false && value !== true && isPlainObject(value)) {
4573
+ const selectVal = value;
4574
+ if (selectVal.include || selectVal.select) {
4575
+ includeSpec[key] = value;
4576
+ }
4577
+ }
4578
+ }
4579
+ }
4580
+ return includeSpec;
4581
+ }
4582
+ function hasNestedIncludes(includeSpec) {
4583
+ return Object.keys(includeSpec).length > 0;
4584
+ }
4585
+ function splitOrderByTerms(orderBy) {
4586
+ const raw = orderBy.trim();
4587
+ if (raw.length === 0) return [];
4588
+ return raw.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim()).filter((s) => s.length > 0);
4589
+ }
4590
+ function hasIdInOrderBy(orderBy, fromAlias) {
4591
+ const aliasLower = String(fromAlias).toLowerCase();
4592
+ const terms = splitOrderByTerms(orderBy).map((t) => t.toLowerCase());
4593
+ return terms.some(
4594
+ (t) => t.startsWith(aliasLower + ".id ") || t.startsWith(aliasLower + '."id" ') || t === aliasLower + ".id" || t === aliasLower + '."id"'
4595
+ );
4596
+ }
4597
+ function ensureIdTiebreakerOrderBy(orderBy, fromAlias, model) {
4598
+ var _a, _b;
4599
+ const idField = (_b = (_a = model == null ? void 0 : model.fields) == null ? void 0 : _a.find) == null ? void 0 : _b.call(
4600
+ _a,
4601
+ (f) => f.name === "id" && !f.isRelation
4602
+ );
4603
+ if (!idField) return orderBy;
4604
+ if (hasIdInOrderBy(orderBy, fromAlias)) return orderBy;
4605
+ const t = col(fromAlias, "id", model) + " ASC";
4606
+ return isNonEmptyString(orderBy) ? orderBy + ", " + t : t;
4607
+ }
4608
+ function ensurePostgresDistinctOrderBy(args) {
4609
+ const { orderBy, distinct, fromAlias, model } = args;
4610
+ const distinctTerms = distinct.map((f) => col(fromAlias, f, model) + " ASC");
4611
+ const existing = splitOrderByTerms(orderBy);
4612
+ const canKeepAsIs = existing.length >= distinctTerms.length && distinctTerms.every(
4613
+ (term, i) => existing[i].toLowerCase().startsWith(term.split(" ASC")[0].toLowerCase())
4614
+ );
4615
+ const merged = canKeepAsIs ? orderBy : [...distinctTerms, ...existing].join(SQL_SEPARATORS.ORDER_BY);
4616
+ return ensureIdTiebreakerOrderBy(merged, fromAlias, model);
4617
+ }
3960
4618
  function constructFinalSql(spec) {
3961
4619
  const {
3962
4620
  select,
@@ -3970,15 +4628,36 @@ function constructFinalSql(spec) {
3970
4628
  cursorClause,
3971
4629
  params,
3972
4630
  dialect,
3973
- model
4631
+ model,
4632
+ includes,
4633
+ schemas,
4634
+ pagination,
4635
+ args
3974
4636
  } = spec;
3975
4637
  const useWindowDistinct = hasWindowDistinct(spec);
3976
4638
  assertDistinctAllowed(method, useWindowDistinct);
3977
- const { includeCols, selectWithIncludes, countJoins } = buildIncludeColumns(spec);
4639
+ const hasDistinct = hasAnyDistinct(spec);
4640
+ assertDistinctAllowed(method, hasDistinct);
4641
+ const includeSpec = extractIncludeSpec(args);
4642
+ const hasIncludes = hasNestedIncludes(includeSpec);
4643
+ const shouldUseFlatJoin = dialect === "postgres" && hasIncludes && canUseFlatJoinForAll(includeSpec);
4644
+ if (shouldUseFlatJoin) {
4645
+ const flatResult = buildFlatJoinSql(spec);
4646
+ if (flatResult.sql) {
4647
+ const baseSqlResult = finalizeSql(flatResult.sql, params, dialect);
4648
+ return {
4649
+ sql: baseSqlResult.sql,
4650
+ params: baseSqlResult.params,
4651
+ paramMappings: baseSqlResult.paramMappings,
4652
+ requiresReduction: true,
4653
+ includeSpec: flatResult.includeSpec
4654
+ };
4655
+ }
4656
+ }
4657
+ const { includeCols, selectWithIncludes, countJoins, includeJoins } = buildIncludeColumns(spec);
3978
4658
  if (useWindowDistinct) {
3979
- const baseSelect2 = (select != null ? select : "").trim();
3980
- assertHasSelectFields(baseSelect2, includeCols);
3981
- const spec2 = withCountJoins(spec, countJoins, whereJoins);
4659
+ const allExtraJoins = [...countJoins, ...includeJoins];
4660
+ const spec2 = withCountJoins(spec, allExtraJoins, whereJoins);
3982
4661
  let sql2 = buildSqliteDistinctQuery(spec2, selectWithIncludes).trim();
3983
4662
  sql2 = appendPagination(sql2, spec);
3984
4663
  return finalizeSql(sql2, params, dialect);
@@ -4000,9 +4679,22 @@ function constructFinalSql(spec) {
4000
4679
  parts.push("CROSS JOIN", cteName);
4001
4680
  }
4002
4681
  pushJoinGroups(parts, whereJoins, countJoins);
4682
+ if (isNonEmptyArray(includeJoins)) {
4683
+ parts.push(includeJoins.join(" "));
4684
+ }
4003
4685
  const conditions = buildConditions(whereClause, cursorClause);
4004
4686
  pushWhere(parts, conditions);
4005
- if (isNonEmptyString(orderBy)) parts.push(SQL_TEMPLATES.ORDER_BY, orderBy);
4687
+ let finalOrderBy = orderBy;
4688
+ if (dialect === "postgres" && isNonEmptyArray(distinct)) {
4689
+ finalOrderBy = ensurePostgresDistinctOrderBy({
4690
+ orderBy: orderBy || "",
4691
+ distinct: [...distinct],
4692
+ fromAlias: from.alias,
4693
+ model
4694
+ });
4695
+ }
4696
+ if (isNonEmptyString(finalOrderBy))
4697
+ parts.push(SQL_TEMPLATES.ORDER_BY, finalOrderBy);
4006
4698
  let sql = parts.join(" ").trim();
4007
4699
  sql = appendPagination(sql, spec);
4008
4700
  return finalizeSql(sql, params, dialect);
@@ -4156,13 +4848,15 @@ function buildSelectSpec(input) {
4156
4848
  whereResult.paramMappings,
4157
4849
  whereResult.nextParamIndex
4158
4850
  );
4851
+ const outerHasLimit = isNotNullish(take);
4159
4852
  const includes = buildIncludeSql(
4160
4853
  normalizedArgs,
4161
4854
  model,
4162
4855
  schemas,
4163
4856
  alias,
4164
4857
  params,
4165
- dialect
4858
+ dialect,
4859
+ outerHasLimit
4166
4860
  );
4167
4861
  const cursorResult = buildCursorClauseIfAny({
4168
4862
  cursor,
@@ -4342,6 +5036,14 @@ function buildInComparison(expr, op, val, params, dialect) {
4342
5036
  if (val.length === 0) {
4343
5037
  return op === Ops.IN ? "0=1" : "1=1";
4344
5038
  }
5039
+ if (dialect === "sqlite" && val.length <= 30) {
5040
+ const placeholders = [];
5041
+ for (const item of val) {
5042
+ placeholders.push(params.add(item));
5043
+ }
5044
+ const list = placeholders.join(", ");
5045
+ return op === Ops.IN ? `${expr} IN (${list})` : `${expr} NOT IN (${list})`;
5046
+ }
4345
5047
  const paramValue = prepareArrayParam(val, dialect);
4346
5048
  const placeholder = params.add(paramValue);
4347
5049
  return op === Ops.IN ? inArray(expr, placeholder, dialect) : notInArray(expr, placeholder, dialect);
@@ -4592,6 +5294,7 @@ function buildAggregateSql(args, whereResult, tableName, alias, model) {
4592
5294
  throw new Error("buildAggregateSql requires at least one aggregate field");
4593
5295
  }
4594
5296
  const selectClause = aggFields.join(SQL_SEPARATORS.FIELD_LIST);
5297
+ const joinsPart = whereResult.joins && whereResult.joins.length > 0 ? whereResult.joins.join(" ") : "";
4595
5298
  const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
4596
5299
  const parts = [
4597
5300
  SQL_TEMPLATES.SELECT,
@@ -4600,6 +5303,7 @@ function buildAggregateSql(args, whereResult, tableName, alias, model) {
4600
5303
  tableName,
4601
5304
  alias
4602
5305
  ];
5306
+ if (joinsPart) parts.push(joinsPart);
4603
5307
  if (whereClause) parts.push(whereClause);
4604
5308
  const sql = parts.join(" ").trim();
4605
5309
  validateSelectQuery(sql);
@@ -4652,7 +5356,9 @@ function buildGroupBySql(args, whereResult, tableName, alias, model, dialect) {
4652
5356
  byFields
4653
5357
  );
4654
5358
  const havingClause = buildGroupByHaving(args, alias, params, model, d);
5359
+ const joinsPart = whereResult.joins && whereResult.joins.length > 0 ? whereResult.joins.join(" ") : "";
4655
5360
  const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
5361
+ const orderBySql = isNotNullish(args.orderBy) ? buildOrderBy(args.orderBy, alias, d, model) : "";
4656
5362
  const parts = [
4657
5363
  SQL_TEMPLATES.SELECT,
4658
5364
  selectFields,
@@ -4660,9 +5366,21 @@ function buildGroupBySql(args, whereResult, tableName, alias, model, dialect) {
4660
5366
  tableName,
4661
5367
  alias
4662
5368
  ];
5369
+ if (joinsPart) parts.push(joinsPart);
4663
5370
  if (whereClause) parts.push(whereClause);
4664
5371
  parts.push(SQL_TEMPLATES.GROUP_BY, groupFields);
4665
5372
  if (havingClause) parts.push(havingClause);
5373
+ if (orderBySql) {
5374
+ parts.push(SQL_TEMPLATES.ORDER_BY, orderBySql);
5375
+ }
5376
+ if (isNotNullish(args.take)) {
5377
+ const ph = addAutoScoped(params, args.take, "groupBy.take");
5378
+ parts.push(SQL_TEMPLATES.LIMIT, ph);
5379
+ }
5380
+ if (isNotNullish(args.skip)) {
5381
+ const ph = addAutoScoped(params, args.skip, "groupBy.skip");
5382
+ parts.push(SQL_TEMPLATES.OFFSET, ph);
5383
+ }
4666
5384
  const sql = parts.join(" ").trim();
4667
5385
  const snapshot = params.snapshot();
4668
5386
  const allParams = [...whereResult.params, ...snapshot.params];
@@ -4675,32 +5393,25 @@ function buildGroupBySql(args, whereResult, tableName, alias, model, dialect) {
4675
5393
  paramMappings: allMappings
4676
5394
  };
4677
5395
  }
4678
- function isPositiveInteger(value) {
4679
- return Number.isFinite(value) && Number.isInteger(value) && value > 0;
5396
+ function findPrimaryKeyFields2(model) {
5397
+ const pkFields = model.fields.filter((f) => f.isId && !f.isRelation);
5398
+ if (pkFields.length > 0) return pkFields.map((f) => f.name);
5399
+ const defaultId = model.fields.find((f) => f.name === "id" && !f.isRelation);
5400
+ if (defaultId) return ["id"];
5401
+ return [];
4680
5402
  }
4681
- function parseSkipValue(skip) {
4682
- return typeof skip === "string" ? Number(skip.trim()) : skip;
5403
+ function normalizeCountArgs(argsOrSkip) {
5404
+ if (isPlainObject(argsOrSkip)) return argsOrSkip;
5405
+ if (argsOrSkip === void 0 || argsOrSkip === null) return {};
5406
+ return { skip: argsOrSkip };
4683
5407
  }
4684
- function validateSkipParameter(skip) {
4685
- if (skip === void 0 || skip === null) {
4686
- return;
4687
- }
4688
- if (isDynamicParameter(skip)) {
4689
- throw new Error(
4690
- "count() with skip is not supported because it produces nondeterministic results. Dynamic skip cannot be validated at build time. Use findMany().length or add explicit orderBy + cursor/skip logic in a deterministic query."
4691
- );
4692
- }
4693
- const skipValue = parseSkipValue(skip);
4694
- if (isPositiveInteger(skipValue)) {
4695
- throw new Error(
4696
- "count() with skip is not supported because it produces nondeterministic results. Use findMany().length or add explicit orderBy to ensure deterministic behavior."
4697
- );
5408
+ function assertNoNegativeTake(args) {
5409
+ if (typeof args.take === "number" && args.take < 0) {
5410
+ throw new Error("Negative take is not supported for count()");
4698
5411
  }
4699
5412
  }
4700
- function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4701
- assertSafeAlias(alias);
4702
- assertSafeTableRef(tableName);
4703
- validateSkipParameter(skip);
5413
+ function buildSimpleCountSql(whereResult, tableName, alias) {
5414
+ const joinsPart = whereResult.joins && whereResult.joins.length > 0 ? whereResult.joins.join(" ") : "";
4704
5415
  const whereClause = isValidWhereClause(whereResult.clause) ? SQL_TEMPLATES.WHERE + " " + whereResult.clause : "";
4705
5416
  const parts = [
4706
5417
  SQL_TEMPLATES.SELECT,
@@ -4711,6 +5422,7 @@ function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4711
5422
  tableName,
4712
5423
  alias
4713
5424
  ];
5425
+ if (joinsPart) parts.push(joinsPart);
4714
5426
  if (whereClause) parts.push(whereClause);
4715
5427
  const sql = parts.join(" ").trim();
4716
5428
  validateSelectQuery(sql);
@@ -4721,6 +5433,49 @@ function buildCountSql(whereResult, tableName, alias, skip, _dialect) {
4721
5433
  paramMappings: whereResult.paramMappings
4722
5434
  };
4723
5435
  }
5436
+ function buildCountSql(whereResult, tableName, alias, argsOrSkip, dialect, model, schemas) {
5437
+ assertSafeAlias(alias);
5438
+ assertSafeTableRef(tableName);
5439
+ const args = normalizeCountArgs(argsOrSkip);
5440
+ assertNoNegativeTake(args);
5441
+ if (!model) {
5442
+ return buildSimpleCountSql(whereResult, tableName, alias);
5443
+ }
5444
+ const pkFields = findPrimaryKeyFields2(model);
5445
+ const distinctFields = isNonEmptyArray(args.distinct) ? args.distinct.map((x) => String(x)).filter((x) => x) : [];
5446
+ const selectFields = distinctFields.length > 0 ? distinctFields : pkFields;
5447
+ if (selectFields.length === 0) {
5448
+ return buildSimpleCountSql(whereResult, tableName, alias);
5449
+ }
5450
+ const select = {};
5451
+ for (const f of selectFields) select[f] = true;
5452
+ const subArgs = __spreadProps(__spreadValues({}, args), {
5453
+ include: void 0,
5454
+ select
5455
+ });
5456
+ const d = dialect != null ? dialect : getGlobalDialect();
5457
+ const subSchemas = Array.isArray(schemas) && schemas.length > 0 ? schemas : [model];
5458
+ const sub = buildSelectSql({
5459
+ method: "findMany",
5460
+ args: subArgs,
5461
+ model,
5462
+ schemas: subSchemas,
5463
+ from: { tableName, alias },
5464
+ whereResult,
5465
+ dialect: d
5466
+ });
5467
+ const countAlias = quote("__count_sub");
5468
+ const sql = `${SQL_TEMPLATES.SELECT} ${SQL_TEMPLATES.COUNT_ALL} ${SQL_TEMPLATES.AS} ${quote(
5469
+ "_count._all"
5470
+ )} ${SQL_TEMPLATES.FROM} (${sub.sql}) ${SQL_TEMPLATES.AS} ${countAlias}`;
5471
+ validateSelectQuery(sql);
5472
+ validateParamConsistency(sql, sub.params);
5473
+ return {
5474
+ sql,
5475
+ params: sub.params,
5476
+ paramMappings: sub.paramMappings
5477
+ };
5478
+ }
4724
5479
  function safeAlias(input) {
4725
5480
  const raw = String(input).toLowerCase();
4726
5481
  const cleaned = raw.replace(/[^a-z0-9_]/g, "_");
@@ -4732,6 +5487,17 @@ function safeAlias(input) {
4732
5487
  }
4733
5488
  return base;
4734
5489
  }
5490
+ function isPrismaMethod(v) {
5491
+ return v === "findMany" || v === "findFirst" || v === "findUnique" || v === "aggregate" || v === "groupBy" || v === "count";
5492
+ }
5493
+ function resolveMethod(directive) {
5494
+ var _a, _b;
5495
+ const m = directive == null ? void 0 : directive.method;
5496
+ if (isPrismaMethod(m)) return m;
5497
+ const pm = (_b = (_a = directive == null ? void 0 : directive.query) == null ? void 0 : _a.processed) == null ? void 0 : _b.method;
5498
+ if (isPrismaMethod(pm)) return pm;
5499
+ return "findMany";
5500
+ }
4735
5501
  function buildSqlResult(args) {
4736
5502
  const {
4737
5503
  method,
@@ -4761,7 +5527,11 @@ function buildSqlResult(args) {
4761
5527
  whereResult,
4762
5528
  tableName,
4763
5529
  alias,
4764
- processed.skip);
5530
+ processed,
5531
+ dialect,
5532
+ modelDef,
5533
+ schemaModels
5534
+ );
4765
5535
  }
4766
5536
  return buildSelectSql({
4767
5537
  method,
@@ -4849,7 +5619,43 @@ function buildMainWhere(args) {
4849
5619
  dialect
4850
5620
  });
4851
5621
  }
5622
+ function extractIncludeSpec2(processed, modelDef) {
5623
+ const includeSpec = {};
5624
+ const relationSet = new Set(
5625
+ Array.isArray(modelDef == null ? void 0 : modelDef.fields) ? modelDef.fields.filter((f) => f && f.isRelation && typeof f.name === "string").map((f) => f.name) : []
5626
+ );
5627
+ if (processed.include && isPlainObject(processed.include)) {
5628
+ for (const [key, value] of Object.entries(processed.include)) {
5629
+ if (!relationSet.has(key)) continue;
5630
+ if (value !== false) {
5631
+ includeSpec[key] = value;
5632
+ }
5633
+ }
5634
+ }
5635
+ if (processed.select && isPlainObject(processed.select)) {
5636
+ for (const [key, value] of Object.entries(processed.select)) {
5637
+ if (!relationSet.has(key)) continue;
5638
+ if (value === false) continue;
5639
+ if (value === true) {
5640
+ includeSpec[key] = true;
5641
+ continue;
5642
+ }
5643
+ if (isPlainObject(value)) {
5644
+ const selectVal = value;
5645
+ if (selectVal.include || selectVal.select) {
5646
+ includeSpec[key] = value;
5647
+ } else {
5648
+ includeSpec[key] = true;
5649
+ }
5650
+ } else {
5651
+ includeSpec[key] = true;
5652
+ }
5653
+ }
5654
+ }
5655
+ return includeSpec;
5656
+ }
4852
5657
  function buildAndNormalizeSql(args) {
5658
+ var _a;
4853
5659
  const {
4854
5660
  method,
4855
5661
  processed,
@@ -4870,14 +5676,30 @@ function buildAndNormalizeSql(args) {
4870
5676
  schemaModels,
4871
5677
  dialect
4872
5678
  });
4873
- return normalizeSqlAndMappingsForDialect(
5679
+ const normalized = normalizeSqlAndMappingsForDialect(
4874
5680
  sqlResult.sql,
4875
5681
  sqlResult.paramMappings,
4876
5682
  dialect
4877
5683
  );
5684
+ const includeSpec = (_a = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a : extractIncludeSpec2(processed, modelDef);
5685
+ const requiresReduction = sqlResult.requiresReduction === true;
5686
+ return {
5687
+ sql: normalized.sql,
5688
+ paramMappings: normalized.paramMappings,
5689
+ requiresReduction,
5690
+ includeSpec
5691
+ };
4878
5692
  }
4879
5693
  function finalizeDirective(args) {
4880
- const { directive, normalizedSql, normalizedMappings, dialect } = args;
5694
+ const {
5695
+ directive,
5696
+ method,
5697
+ normalizedSql,
5698
+ normalizedMappings,
5699
+ dialect,
5700
+ requiresReduction,
5701
+ includeSpec
5702
+ } = args;
4881
5703
  const params = normalizedMappings.map((m) => {
4882
5704
  var _a;
4883
5705
  return (_a = m.value) != null ? _a : void 0;
@@ -4885,12 +5707,14 @@ function finalizeDirective(args) {
4885
5707
  validateParamConsistencyByDialect(normalizedSql, params, dialect);
4886
5708
  const { staticParams, dynamicKeys, paramOrder } = buildParamsFromMappings(normalizedMappings);
4887
5709
  return {
4888
- method: directive.method,
5710
+ method,
4889
5711
  sql: normalizedSql,
4890
5712
  staticParams,
4891
5713
  dynamicKeys,
4892
5714
  paramOrder,
4893
5715
  paramMappings: normalizedMappings,
5716
+ requiresReduction,
5717
+ includeSpec,
4894
5718
  originalDirective: directive
4895
5719
  };
4896
5720
  }
@@ -4906,8 +5730,8 @@ function generateSQL(directive) {
4906
5730
  modelDef,
4907
5731
  dialect
4908
5732
  });
4909
- const method = directive.method;
4910
- const normalized = buildAndNormalizeSql({
5733
+ const method = resolveMethod(directive);
5734
+ const built = buildAndNormalizeSql({
4911
5735
  method,
4912
5736
  processed: query.processed,
4913
5737
  whereResult,
@@ -4919,9 +5743,12 @@ function generateSQL(directive) {
4919
5743
  });
4920
5744
  return finalizeDirective({
4921
5745
  directive,
4922
- normalizedSql: normalized.sql,
4923
- normalizedMappings: normalized.paramMappings,
4924
- dialect
5746
+ method,
5747
+ normalizedSql: built.sql,
5748
+ normalizedMappings: built.paramMappings,
5749
+ dialect,
5750
+ requiresReduction: built.requiresReduction,
5751
+ includeSpec: built.includeSpec
4925
5752
  });
4926
5753
  }
4927
5754
 
@@ -5509,7 +6336,9 @@ function buildSQLFull(model, models, method, args, dialect) {
5509
6336
  whereResult,
5510
6337
  tableName,
5511
6338
  alias,
5512
- args.skip);
6339
+ args.skip,
6340
+ dialect
6341
+ );
5513
6342
  break;
5514
6343
  default:
5515
6344
  result = buildSelectSql({
@@ -5522,14 +6351,25 @@ function buildSQLFull(model, models, method, args, dialect) {
5522
6351
  dialect
5523
6352
  });
5524
6353
  }
5525
- return dialect === "sqlite" ? toSqliteParams(result.sql, result.params) : { sql: result.sql, params: [...result.params] };
6354
+ const sqlResult = dialect === "sqlite" ? toSqliteParams(result.sql, result.params) : { sql: result.sql, params: [...result.params] };
6355
+ return __spreadProps(__spreadValues({}, sqlResult), {
6356
+ paramMappings: result.paramMappings,
6357
+ requiresReduction: result.requiresReduction,
6358
+ includeSpec: result.includeSpec
6359
+ });
5526
6360
  }
5527
6361
  function buildSQLWithCache(model, models, method, args, dialect) {
5528
6362
  const cacheKey = canonicalizeQuery(model.name, method, args, dialect);
5529
6363
  const cached = queryCache.get(cacheKey);
5530
6364
  if (cached) {
5531
6365
  queryCacheStats.hit();
5532
- return { sql: cached.sql, params: [...cached.params] };
6366
+ return {
6367
+ sql: cached.sql,
6368
+ params: [...cached.params],
6369
+ paramMappings: cached.paramMappings,
6370
+ requiresReduction: cached.requiresReduction,
6371
+ includeSpec: cached.includeSpec
6372
+ };
5533
6373
  }
5534
6374
  queryCacheStats.miss();
5535
6375
  const fastResult = tryFastPath(model, method, args, dialect);
@@ -5541,61 +6381,20 @@ function buildSQLWithCache(model, models, method, args, dialect) {
5541
6381
  return fastResult;
5542
6382
  }
5543
6383
  const result = buildSQLFull(model, models, method, args, dialect);
5544
- queryCache.set(cacheKey, { sql: result.sql, params: [...result.params] });
6384
+ queryCache.set(cacheKey, {
6385
+ sql: result.sql,
6386
+ params: [...result.params],
6387
+ paramMappings: result.paramMappings,
6388
+ requiresReduction: result.requiresReduction,
6389
+ includeSpec: result.includeSpec
6390
+ });
5545
6391
  return result;
5546
6392
  }
5547
6393
 
5548
6394
  // src/result-transformers.ts
5549
- function parseAggregateValue(value) {
5550
- if (typeof value === "string" && /^-?\d+(\.\d+)?$/.test(value)) {
5551
- return parseFloat(value);
5552
- }
5553
- return value;
5554
- }
5555
- function transformGroupByResults(results) {
5556
- return results.map((row) => {
5557
- const raw = row;
5558
- const parsed = {};
5559
- for (const [key, value] of Object.entries(raw)) {
5560
- const parts = key.split(".");
5561
- if (parts.length === 2) {
5562
- const [group, field] = parts;
5563
- if (!parsed[group]) parsed[group] = {};
5564
- parsed[group][field] = parseAggregateValue(value);
5565
- } else {
5566
- parsed[key] = value;
5567
- }
5568
- }
5569
- return parsed;
5570
- });
5571
- }
5572
- function transformCountResults(results) {
5573
- var _a, _b;
5574
- const result = results[0];
5575
- const count = (_b = (_a = result == null ? void 0 : result["_count._all"]) != null ? _a : result == null ? void 0 : result.count) != null ? _b : 0;
5576
- return typeof count === "string" ? parseInt(count, 10) : count;
5577
- }
5578
- function transformAggregateResults(results) {
5579
- const raw = results[0] || {};
5580
- const parsed = {};
5581
- for (const [key, value] of Object.entries(raw)) {
5582
- const parts = key.split(".");
5583
- if (parts.length === 2) {
5584
- const [group, field] = parts;
5585
- if (!parsed[group]) parsed[group] = {};
5586
- parsed[group][field] = parseAggregateValue(value);
5587
- } else {
5588
- parsed[key] = value;
5589
- }
5590
- }
5591
- return parsed;
5592
- }
5593
6395
  var RESULT_TRANSFORMERS = {
5594
6396
  findFirst: (results) => results[0] || null,
5595
- findUnique: (results) => results[0] || null,
5596
- count: transformCountResults,
5597
- aggregate: transformAggregateResults,
5598
- groupBy: transformGroupByResults
6397
+ findUnique: (results) => results[0] || null
5599
6398
  };
5600
6399
  function transformQueryResults(method, results) {
5601
6400
  const transformer = RESULT_TRANSFORMERS[method];
@@ -6518,6 +7317,321 @@ function createTransactionExecutor(deps) {
6518
7317
  };
6519
7318
  }
6520
7319
 
7320
+ // src/builder/select/reducer.ts
7321
+ var PK_FIELDS_CACHE = /* @__PURE__ */ new WeakMap();
7322
+ var SCALAR_FIELDS_CACHE = /* @__PURE__ */ new WeakMap();
7323
+ var JSON_FIELD_SET_CACHE = /* @__PURE__ */ new WeakMap();
7324
+ function findPrimaryKeyFieldsCached(model) {
7325
+ const cached = PK_FIELDS_CACHE.get(model);
7326
+ if (cached) return cached;
7327
+ const pkFields = model.fields.filter((f) => f.isId && !f.isRelation);
7328
+ if (pkFields.length > 0) {
7329
+ const out = pkFields.map((f) => f.name);
7330
+ PK_FIELDS_CACHE.set(model, out);
7331
+ return out;
7332
+ }
7333
+ const defaultId = model.fields.find((f) => f.name === "id" && !f.isRelation);
7334
+ if (defaultId) {
7335
+ const out = ["id"];
7336
+ PK_FIELDS_CACHE.set(model, out);
7337
+ return out;
7338
+ }
7339
+ throw new Error(
7340
+ `Model ${model.name} has no primary key field. Models must have either fields with isId=true or a field named 'id'.`
7341
+ );
7342
+ }
7343
+ function scalarFieldNamesCached(model) {
7344
+ const cached = SCALAR_FIELDS_CACHE.get(model);
7345
+ if (cached) return cached;
7346
+ const out = model.fields.filter((f) => !f.isRelation).map((f) => f.name);
7347
+ SCALAR_FIELDS_CACHE.set(model, out);
7348
+ return out;
7349
+ }
7350
+ function jsonFieldSetCached(model) {
7351
+ var _a;
7352
+ const cached = JSON_FIELD_SET_CACHE.get(model);
7353
+ if (cached) return cached;
7354
+ const s = /* @__PURE__ */ new Set();
7355
+ for (const f of model.fields) {
7356
+ if (f.isRelation) continue;
7357
+ const t = String((_a = f.type) != null ? _a : "").toLowerCase();
7358
+ if (t === "json") s.add(f.name);
7359
+ }
7360
+ JSON_FIELD_SET_CACHE.set(model, s);
7361
+ return s;
7362
+ }
7363
+ function maybeParseJsonScalarFast(isJson, value) {
7364
+ if (!isJson) return value;
7365
+ if (value == null) return value;
7366
+ if (typeof value !== "string") return value;
7367
+ try {
7368
+ return JSON.parse(value);
7369
+ } catch (e) {
7370
+ return value;
7371
+ }
7372
+ }
7373
+ function extractIncludeSpecFromRelArgs(relArgs, relModel) {
7374
+ const relationSet = getRelationFieldSet(relModel);
7375
+ const out = {};
7376
+ if (!isPlainObject(relArgs)) return out;
7377
+ const obj = relArgs;
7378
+ if (isPlainObject(obj.include)) {
7379
+ for (const [k, v] of Object.entries(
7380
+ obj.include
7381
+ )) {
7382
+ if (!relationSet.has(k)) continue;
7383
+ if (v === false) continue;
7384
+ out[k] = v;
7385
+ }
7386
+ }
7387
+ if (isPlainObject(obj.select)) {
7388
+ for (const [k, v] of Object.entries(
7389
+ obj.select
7390
+ )) {
7391
+ if (!relationSet.has(k)) continue;
7392
+ if (v === false) continue;
7393
+ if (v === true) {
7394
+ out[k] = true;
7395
+ continue;
7396
+ }
7397
+ if (isPlainObject(v)) {
7398
+ const vv = v;
7399
+ if (isPlainObject(vv.include) || isPlainObject(vv.select)) {
7400
+ out[k] = v;
7401
+ }
7402
+ }
7403
+ }
7404
+ }
7405
+ return out;
7406
+ }
7407
+ function extractScalarSelection(relArgs, relModel) {
7408
+ const scalars = scalarFieldNamesCached(relModel);
7409
+ const scalarSet = new Set(scalars);
7410
+ if (relArgs === true || !isPlainObject(relArgs)) {
7411
+ return { includeAllScalars: true, selectedScalarFields: scalars };
7412
+ }
7413
+ const obj = relArgs;
7414
+ if (!isPlainObject(obj.select)) {
7415
+ return { includeAllScalars: true, selectedScalarFields: scalars };
7416
+ }
7417
+ const sel = obj.select;
7418
+ const selected = [];
7419
+ for (const [k, v] of Object.entries(sel)) {
7420
+ if (!scalarSet.has(k)) continue;
7421
+ if (v === true) selected.push(k);
7422
+ }
7423
+ return { includeAllScalars: false, selectedScalarFields: selected };
7424
+ }
7425
+ function buildRelationScalarCols(relModel, relPath, includeAllScalars, selectedScalarFields) {
7426
+ const jsonSet = jsonFieldSetCached(relModel);
7427
+ const scalarFields = includeAllScalars ? scalarFieldNamesCached(relModel) : selectedScalarFields;
7428
+ const out = [];
7429
+ for (const fieldName of scalarFields) {
7430
+ out.push({
7431
+ fieldName,
7432
+ colName: `${relPath}.${fieldName}`,
7433
+ isJson: jsonSet.has(fieldName)
7434
+ });
7435
+ }
7436
+ return out;
7437
+ }
7438
+ function buildReducerConfig(parentModel, includeSpec, allModels, prefix = "", depth = 0) {
7439
+ if (depth > 10) {
7440
+ throw new Error(
7441
+ `Reducer config exceeded maximum depth of 10 at path '${prefix}'`
7442
+ );
7443
+ }
7444
+ const includedRelations = [];
7445
+ const modelMap = new Map(allModels.map((m) => [m.name, m]));
7446
+ for (const [incName, incValue] of Object.entries(includeSpec)) {
7447
+ if (incValue === false) continue;
7448
+ const field = parentModel.fields.find((f) => f.name === incName);
7449
+ if (!field || !field.isRelation) {
7450
+ throw new Error(
7451
+ `Field '${incName}' is not a relation on model ${parentModel.name}`
7452
+ );
7453
+ }
7454
+ const relatedModel = modelMap.get(field.relatedModel);
7455
+ if (!relatedModel) {
7456
+ throw new Error(
7457
+ `Related model '${field.relatedModel}' not found for relation '${incName}'`
7458
+ );
7459
+ }
7460
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
7461
+ const primaryKeyFields = findPrimaryKeyFieldsCached(relatedModel);
7462
+ const scalarSel = extractScalarSelection(incValue, relatedModel);
7463
+ const relPath = prefix ? `${prefix}.${incName}` : incName;
7464
+ let nestedIncludes = null;
7465
+ const nestedSpec = extractIncludeSpecFromRelArgs(incValue, relatedModel);
7466
+ if (Object.keys(nestedSpec).length > 0) {
7467
+ nestedIncludes = buildReducerConfig(
7468
+ relatedModel,
7469
+ nestedSpec,
7470
+ allModels,
7471
+ relPath,
7472
+ depth + 1
7473
+ );
7474
+ }
7475
+ const keyCols = primaryKeyFields.map((f) => `${relPath}.${f}`);
7476
+ const scalarCols = buildRelationScalarCols(
7477
+ relatedModel,
7478
+ relPath,
7479
+ scalarSel.includeAllScalars,
7480
+ scalarSel.selectedScalarFields
7481
+ );
7482
+ includedRelations.push({
7483
+ name: incName,
7484
+ cardinality: isList ? "many" : "one",
7485
+ relatedModel,
7486
+ primaryKeyFields,
7487
+ includeAllScalars: scalarSel.includeAllScalars,
7488
+ selectedScalarFields: scalarSel.selectedScalarFields,
7489
+ nestedIncludes,
7490
+ path: relPath,
7491
+ keyCols,
7492
+ scalarCols
7493
+ });
7494
+ }
7495
+ return {
7496
+ parentModel,
7497
+ includedRelations,
7498
+ allModels
7499
+ };
7500
+ }
7501
+ function typedKeyPart(v) {
7502
+ const t = typeof v;
7503
+ if (t === "string") return `s:${v}`;
7504
+ if (t === "number") return `n:${v}`;
7505
+ if (t === "boolean") return `b:${v ? 1 : 0}`;
7506
+ return `o:${String(v)}`;
7507
+ }
7508
+ function keyFromRowByCols(row, cols) {
7509
+ if (cols.length === 0) return null;
7510
+ if (cols.length === 1) {
7511
+ const v = row[cols[0]];
7512
+ if (v == null) return null;
7513
+ return typedKeyPart(v);
7514
+ }
7515
+ let out = "";
7516
+ for (let i = 0; i < cols.length; i++) {
7517
+ const v = row[cols[i]];
7518
+ if (v == null) return null;
7519
+ if (i > 0) out += "";
7520
+ out += typedKeyPart(v);
7521
+ }
7522
+ return out;
7523
+ }
7524
+ function getIndexForParent(store, parentObj, path) {
7525
+ let byPath = store.get(parentObj);
7526
+ if (!byPath) {
7527
+ byPath = /* @__PURE__ */ new Map();
7528
+ store.set(parentObj, byPath);
7529
+ }
7530
+ let idx = byPath.get(path);
7531
+ if (!idx) {
7532
+ idx = /* @__PURE__ */ new Map();
7533
+ byPath.set(path, idx);
7534
+ }
7535
+ return idx;
7536
+ }
7537
+ function initNestedPlaceholders(obj, nested) {
7538
+ if (!nested) return;
7539
+ for (const r of nested.includedRelations) {
7540
+ obj[r.name] = r.cardinality === "many" ? [] : null;
7541
+ }
7542
+ }
7543
+ function materializeRelationObject(row, rel) {
7544
+ const relKey = keyFromRowByCols(row, rel.keyCols);
7545
+ if (relKey == null) return null;
7546
+ const obj = {};
7547
+ for (const c of rel.scalarCols) {
7548
+ obj[c.fieldName] = maybeParseJsonScalarFast(c.isJson, row[c.colName]);
7549
+ }
7550
+ initNestedPlaceholders(obj, rel.nestedIncludes);
7551
+ return obj;
7552
+ }
7553
+ function processRelation(parentObj, rel, row, manyStore) {
7554
+ const relKey = keyFromRowByCols(row, rel.keyCols);
7555
+ if (relKey == null) return;
7556
+ if (rel.cardinality === "one") {
7557
+ let current = parentObj[rel.name];
7558
+ if (current == null) {
7559
+ const created2 = materializeRelationObject(row, rel);
7560
+ if (!created2) return;
7561
+ parentObj[rel.name] = created2;
7562
+ current = created2;
7563
+ }
7564
+ if (rel.nestedIncludes) {
7565
+ for (const nestedRel of rel.nestedIncludes.includedRelations) {
7566
+ processRelation(current, nestedRel, row, manyStore);
7567
+ }
7568
+ }
7569
+ return;
7570
+ }
7571
+ const arr = parentObj[rel.name];
7572
+ const idx = getIndexForParent(manyStore, parentObj, rel.path);
7573
+ const existing = idx.get(relKey);
7574
+ if (existing) {
7575
+ if (rel.nestedIncludes) {
7576
+ for (const nestedRel of rel.nestedIncludes.includedRelations) {
7577
+ processRelation(existing, nestedRel, row, manyStore);
7578
+ }
7579
+ }
7580
+ return;
7581
+ }
7582
+ const created = materializeRelationObject(row, rel);
7583
+ if (!created) return;
7584
+ arr.push(created);
7585
+ idx.set(relKey, created);
7586
+ if (rel.nestedIncludes) {
7587
+ for (const nestedRel of rel.nestedIncludes.includedRelations) {
7588
+ processRelation(created, nestedRel, row, manyStore);
7589
+ }
7590
+ }
7591
+ }
7592
+ function pickParentScalarFieldsFromRows(parentModel, rows) {
7593
+ const all = scalarFieldNamesCached(parentModel);
7594
+ if (rows.length === 0) return all;
7595
+ const row0 = rows[0];
7596
+ const picked = [];
7597
+ for (const f of all) {
7598
+ if (Object.prototype.hasOwnProperty.call(row0, f)) picked.push(f);
7599
+ }
7600
+ return picked.length > 0 ? picked : all;
7601
+ }
7602
+ function reduceFlatRows(rows, config) {
7603
+ if (rows.length === 0) return [];
7604
+ const { parentModel, includedRelations } = config;
7605
+ const parentPkFields = findPrimaryKeyFieldsCached(parentModel);
7606
+ const parentKeyCols = parentPkFields;
7607
+ const parentScalarFields = pickParentScalarFieldsFromRows(parentModel, rows);
7608
+ const parentJsonSet = jsonFieldSetCached(parentModel);
7609
+ const resultMap = /* @__PURE__ */ new Map();
7610
+ const manyStore = /* @__PURE__ */ new WeakMap();
7611
+ for (const row of rows) {
7612
+ const parentKey = keyFromRowByCols(row, parentKeyCols);
7613
+ if (parentKey == null) continue;
7614
+ let record = resultMap.get(parentKey);
7615
+ if (!record) {
7616
+ record = {};
7617
+ for (const fieldName of parentScalarFields) {
7618
+ record[fieldName] = maybeParseJsonScalarFast(
7619
+ parentJsonSet.has(fieldName),
7620
+ row[fieldName]
7621
+ );
7622
+ }
7623
+ for (const rel of includedRelations) {
7624
+ record[rel.name] = rel.cardinality === "many" ? [] : null;
7625
+ }
7626
+ resultMap.set(parentKey, record);
7627
+ }
7628
+ for (const rel of includedRelations) {
7629
+ processRelation(record, rel, row, manyStore);
7630
+ }
7631
+ }
7632
+ return Array.from(resultMap.values());
7633
+ }
7634
+
6521
7635
  // src/index.ts
6522
7636
  function buildSQL(model, models, method, args, dialect) {
6523
7637
  return buildSQLWithCache(model, models, method, args, dialect);
@@ -6559,8 +7673,20 @@ function createPrismaSQL(config) {
6559
7673
  const modelMap = new Map(models.map((m) => [m.name, m]));
6560
7674
  function query(_0, _1) {
6561
7675
  return __async(this, arguments, function* (model, method, args = {}) {
6562
- const { sql, params } = toSQL(model, method, args);
6563
- return execute(client, sql, params);
7676
+ const sqlResult = toSQL(model, method, args);
7677
+ let results = yield execute(client, sqlResult.sql, [...sqlResult.params]);
7678
+ if (sqlResult.requiresReduction && sqlResult.includeSpec) {
7679
+ const modelDef = modelMap.get(model);
7680
+ if (modelDef) {
7681
+ const config2 = buildReducerConfig(
7682
+ modelDef,
7683
+ sqlResult.includeSpec,
7684
+ models
7685
+ );
7686
+ results = reduceFlatRows(results, config2);
7687
+ }
7688
+ }
7689
+ return transformQueryResults(method, results);
6564
7690
  });
6565
7691
  }
6566
7692
  function batchSql(queries) {
@@ -6609,6 +7735,6 @@ function generateSQLByModel(directives) {
6609
7735
  return byModel;
6610
7736
  }
6611
7737
 
6612
- export { buildBatchCountSql, buildBatchSql, buildSQL, createPrismaSQL, createToSQL, createTransactionExecutor, generateAllSQL, generateSQL2 as generateSQL, generateSQLByModel, normalizeValue, parseBatchCountResults, parseBatchResults, transformQueryResults };
7738
+ export { buildBatchCountSql, buildBatchSql, buildReducerConfig, buildSQL, createPrismaSQL, createToSQL, createTransactionExecutor, generateAllSQL, generateSQL2 as generateSQL, generateSQLByModel, normalizeValue, parseBatchCountResults, parseBatchResults, reduceFlatRows, transformQueryResults };
6613
7739
  //# sourceMappingURL=index.js.map
6614
7740
  //# sourceMappingURL=index.js.map