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