prisma-sql 1.67.0 → 1.68.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
@@ -449,6 +449,8 @@ var AGGREGATE_PREFIXES = /* @__PURE__ */ new Set([
449
449
  "_min",
450
450
  "_max"
451
451
  ]);
452
+ var _a;
453
+ var DEBUG_PARAMS = typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.DEBUG_PARAMS) === "1";
452
454
 
453
455
  // src/builder/shared/validators/type-guards.ts
454
456
  function isNotNullish(value) {
@@ -992,7 +994,7 @@ function normalizeField(field) {
992
994
  return field;
993
995
  }
994
996
  function getFieldIndices(model) {
995
- var _a;
997
+ var _a3;
996
998
  let cached = FIELD_INDICES_CACHE.get(model);
997
999
  if (cached) return cached;
998
1000
  const scalarFields = /* @__PURE__ */ new Map();
@@ -1011,7 +1013,7 @@ function getFieldIndices(model) {
1011
1013
  } else {
1012
1014
  scalarFields.set(field.name, field);
1013
1015
  scalarNames.push(field.name);
1014
- const fieldType = String((_a = field.type) != null ? _a : "").toLowerCase();
1016
+ const fieldType = String((_a3 = field.type) != null ? _a3 : "").toLowerCase();
1015
1017
  if (fieldType === "json") {
1016
1018
  jsonFields.add(field.name);
1017
1019
  }
@@ -1135,13 +1137,13 @@ function getModelByName(schemas, name) {
1135
1137
  return schemas.find((m) => m.name === name);
1136
1138
  }
1137
1139
  function normalizeIntLike(name, v, opts = {}) {
1138
- var _a, _b;
1140
+ var _a3, _b;
1139
1141
  if (!isNotNullish(v)) return void 0;
1140
1142
  if (schemaParser.isDynamicParameter(v)) return v;
1141
1143
  if (typeof v !== "number" || !Number.isFinite(v) || !Number.isInteger(v)) {
1142
1144
  throw new Error(`${name} must be an integer`);
1143
1145
  }
1144
- const min = (_a = opts.min) != null ? _a : 0;
1146
+ const min = (_a3 = opts.min) != null ? _a3 : 0;
1145
1147
  const allowZero = (_b = opts.allowZero) != null ? _b : true;
1146
1148
  if (!allowZero && v === 0) {
1147
1149
  throw new Error(`${name} must be > 0`);
@@ -1163,7 +1165,9 @@ function scopeName(scope, dynamicName) {
1163
1165
  function addAutoScoped(params, value, scope) {
1164
1166
  if (schemaParser.isDynamicParameter(value)) {
1165
1167
  const dn = schemaParser.extractDynamicName(value);
1166
- console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
1168
+ if (DEBUG_PARAMS) {
1169
+ console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
1170
+ }
1167
1171
  return params.add(void 0, scopeName(scope, dn));
1168
1172
  }
1169
1173
  return params.add(value);
@@ -1604,7 +1608,7 @@ function assertCursorAndOrderFieldsScalar(model, cursor, orderEntries) {
1604
1608
  }
1605
1609
  }
1606
1610
  function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
1607
- var _a;
1611
+ var _a3;
1608
1612
  assertSafeTableRef(tableName);
1609
1613
  assertSafeAlias(alias);
1610
1614
  const d = dialect != null ? dialect : getGlobalDialect();
@@ -1619,6 +1623,33 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
1619
1623
  }
1620
1624
  if (cursorEntries.length === 0)
1621
1625
  throw new Error("cursor must have at least one field with defined value");
1626
+ const orderEntries = normalizeAndValidateOrderBy(
1627
+ orderBy,
1628
+ model,
1629
+ parseOrderByValue
1630
+ );
1631
+ if (cursorEntries.length === 1 && orderEntries.length === 0) {
1632
+ const [field, value] = cursorEntries[0];
1633
+ const ph = addAutoScoped(params, value, `cursor.${field}`);
1634
+ const c = col(alias, field, model);
1635
+ return {
1636
+ cte: "",
1637
+ condition: `${c} >= ${ph}`
1638
+ };
1639
+ }
1640
+ if (cursorEntries.length === 1 && orderEntries.length === 1) {
1641
+ const [cursorField, cursorValue] = cursorEntries[0];
1642
+ const orderEntry = orderEntries[0];
1643
+ if (orderEntry.field === cursorField) {
1644
+ const ph = addAutoScoped(params, cursorValue, `cursor.${cursorField}`);
1645
+ const c = col(alias, cursorField, model);
1646
+ const op = orderEntry.direction === "asc" ? ">=" : "<=";
1647
+ return {
1648
+ cte: "",
1649
+ condition: `${c} ${op} ${ph}`
1650
+ };
1651
+ }
1652
+ }
1622
1653
  const { cteName, srcAlias } = buildCursorNames(alias);
1623
1654
  assertSafeAlias(cteName);
1624
1655
  assertSafeAlias(srcAlias);
@@ -1627,49 +1658,52 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
1627
1658
  model,
1628
1659
  parseValue: parseOrderByValue
1629
1660
  });
1630
- let orderEntries = normalizeAndValidateOrderBy(
1661
+ let finalOrderEntries = normalizeAndValidateOrderBy(
1631
1662
  orderBy,
1632
1663
  model,
1633
1664
  parseOrderByValue
1634
1665
  );
1635
- if (orderEntries.length === 0) {
1636
- orderEntries = cursorEntries.map(([field]) => ({
1666
+ if (finalOrderEntries.length === 0) {
1667
+ finalOrderEntries = cursorEntries.map(([field]) => ({
1637
1668
  field,
1638
1669
  direction: "asc"
1639
1670
  }));
1640
1671
  } else {
1641
- orderEntries = ensureCursorFieldsInOrder(orderEntries, cursorEntries);
1672
+ finalOrderEntries = ensureCursorFieldsInOrder(
1673
+ finalOrderEntries,
1674
+ cursorEntries
1675
+ );
1642
1676
  }
1643
- assertCursorAndOrderFieldsScalar(model, cursor, orderEntries);
1677
+ assertCursorAndOrderFieldsScalar(model, cursor, finalOrderEntries);
1644
1678
  const { whereSql: cursorWhereSql } = buildCursorFilterParts(
1645
1679
  cursor,
1646
1680
  srcAlias,
1647
1681
  params,
1648
1682
  model
1649
1683
  );
1650
- const cursorOrderBy = orderEntries.map(
1684
+ const cursorOrderBy = finalOrderEntries.map(
1651
1685
  (e) => srcAlias + "." + quoteColumn(model, e.field) + " " + e.direction.toUpperCase()
1652
1686
  ).join(", ");
1653
1687
  const selectList = buildCursorCteSelectList(
1654
1688
  cursorEntries,
1655
- orderEntries,
1689
+ finalOrderEntries,
1656
1690
  model
1657
1691
  );
1658
1692
  const cte = cteName + " AS (\n SELECT " + selectList + " FROM " + tableName + " " + srcAlias + "\n WHERE " + cursorWhereSql + "\n ORDER BY " + cursorOrderBy + "\n LIMIT 1\n )";
1659
1693
  const existsExpr = "EXISTS (SELECT 1 FROM " + cteName + ")";
1660
1694
  const orClauses = [];
1661
- for (let level = 0; level < orderEntries.length; level++) {
1695
+ for (let level = 0; level < finalOrderEntries.length; level++) {
1662
1696
  const andParts = [];
1663
1697
  for (let i = 0; i < level; i++) {
1664
- const e2 = orderEntries[i];
1698
+ const e2 = finalOrderEntries[i];
1665
1699
  const c2 = col(alias, e2.field, model);
1666
1700
  const cursorField2 = cteName + "." + quoteColumn(model, e2.field);
1667
1701
  andParts.push(buildCursorEqualityExpr(c2, cursorField2));
1668
1702
  }
1669
- const e = orderEntries[level];
1703
+ const e = finalOrderEntries[level];
1670
1704
  const c = col(alias, e.field, model);
1671
1705
  const cursorField = cteName + "." + quoteColumn(model, e.field);
1672
- const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
1706
+ const nulls = (_a3 = e.nulls) != null ? _a3 : defaultNullsFor(d, e.direction);
1673
1707
  andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, cursorField));
1674
1708
  orClauses.push("(" + andParts.join(SQL_SEPARATORS.CONDITION_AND) + ")");
1675
1709
  }
@@ -2215,6 +2249,16 @@ function handleJsonWildcard(expr, op, val, params, wildcards, dialect) {
2215
2249
 
2216
2250
  // src/builder/where/relations.ts
2217
2251
  var NO_JOINS = [];
2252
+ var SCHEMA_MAP_CACHE = /* @__PURE__ */ new WeakMap();
2253
+ function getSchemaByName(schemas) {
2254
+ let map = SCHEMA_MAP_CACHE.get(schemas);
2255
+ if (!map) {
2256
+ map = /* @__PURE__ */ new Map();
2257
+ for (const m of schemas) map.set(m.name, m);
2258
+ SCHEMA_MAP_CACHE.set(schemas, map);
2259
+ }
2260
+ return map;
2261
+ }
2218
2262
  function isListRelation(fieldType) {
2219
2263
  return typeof fieldType === "string" && fieldType.endsWith("[]");
2220
2264
  }
@@ -2414,7 +2458,8 @@ function buildRelation(fieldName, value, ctx, whereBuilder) {
2414
2458
  modelName: ctx.model.name
2415
2459
  });
2416
2460
  }
2417
- const relModel = ctx.schemaModels.find((m) => m.name === field.relatedModel);
2461
+ const schemaMap = getSchemaByName(ctx.schemaModels);
2462
+ const relModel = schemaMap.get(field.relatedModel);
2418
2463
  if (!isNotNullish(relModel)) {
2419
2464
  throw createError(
2420
2465
  `Related model '${field.relatedModel}' not found in schema. Available models: ${ctx.schemaModels.map((m) => m.name).join(", ")}`,
@@ -2745,6 +2790,8 @@ function createAliasGenerator(maxAliases = 1e4) {
2745
2790
  };
2746
2791
  }
2747
2792
  var MAX_PARAM_INDEX = Number.MAX_SAFE_INTEGER - 1e3;
2793
+ var _a2;
2794
+ var IS_PRODUCTION2 = typeof process !== "undefined" && ((_a2 = process.env) == null ? void 0 : _a2.NODE_ENV) === "production";
2748
2795
  function assertSameLength(params, mappings) {
2749
2796
  if (params.length !== mappings.length) {
2750
2797
  throw new Error(
@@ -2804,6 +2851,11 @@ function validateMappings(mappings) {
2804
2851
  }
2805
2852
  }
2806
2853
  function validateState(params, mappings, index) {
2854
+ if (IS_PRODUCTION2) {
2855
+ assertSameLength(params, mappings);
2856
+ assertValidNextIndex(index);
2857
+ return;
2858
+ }
2807
2859
  assertSameLength(params, mappings);
2808
2860
  assertValidNextIndex(index);
2809
2861
  if (mappings.length === 0) return;
@@ -2958,10 +3010,10 @@ function toPublicResult(clause, joins, params) {
2958
3010
 
2959
3011
  // src/builder/where.ts
2960
3012
  function buildWhereClause(where, options) {
2961
- var _a, _b, _c, _d, _e;
3013
+ var _a3, _b, _c, _d, _e;
2962
3014
  assertSafeAlias(options.alias);
2963
3015
  const dialect = options.dialect || getGlobalDialect();
2964
- const params = (_a = options.params) != null ? _a : createParamStore(1, dialect);
3016
+ const params = (_a3 = options.params) != null ? _a3 : createParamStore(1, dialect);
2965
3017
  const ctx = {
2966
3018
  alias: options.alias,
2967
3019
  model: options.model,
@@ -3020,8 +3072,8 @@ function buildDefaultScalarFields(model, alias) {
3020
3072
  return out;
3021
3073
  }
3022
3074
  function getDefaultSelectCached(model, alias) {
3023
- var _a;
3024
- return (_a = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a.get(alias);
3075
+ var _a3;
3076
+ return (_a3 = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a3.get(alias);
3025
3077
  }
3026
3078
  function cacheDefaultSelect(model, alias, sql) {
3027
3079
  let cache = DEFAULT_SELECT_CACHE.get(model);
@@ -3118,7 +3170,8 @@ function buildRelationSelect(relArgs, relModel, relAlias) {
3118
3170
  }
3119
3171
 
3120
3172
  // src/builder/shared/relation-key-utils.ts
3121
- function resolveRelationKeys(field, context = "include") {
3173
+ var RELATION_KEYS_CACHE = /* @__PURE__ */ new WeakMap();
3174
+ function computeRelationKeys(field, context) {
3122
3175
  const fkFields = normalizeKeyList(field.foreignKey);
3123
3176
  if (fkFields.length === 0) {
3124
3177
  throw new Error(
@@ -3136,6 +3189,13 @@ function resolveRelationKeys(field, context = "include") {
3136
3189
  const parentKeys = field.isForeignKeyLocal ? fkFields : refFields;
3137
3190
  return { childKeys, parentKeys };
3138
3191
  }
3192
+ function resolveRelationKeys(field, context = "include") {
3193
+ let cached = RELATION_KEYS_CACHE.get(field);
3194
+ if (cached) return cached;
3195
+ cached = computeRelationKeys(field, context);
3196
+ RELATION_KEYS_CACHE.set(field, cached);
3197
+ return cached;
3198
+ }
3139
3199
 
3140
3200
  // src/builder/shared/relation-extraction-utils.ts
3141
3201
  function extractRelationEntries(args, model) {
@@ -3165,6 +3225,18 @@ function extractRelationEntries(args, model) {
3165
3225
  var MAX_INCLUDE_DEPTH = 5;
3166
3226
  var MAX_INCLUDES_PER_LEVEL = 10;
3167
3227
  var MAX_TOTAL_SUBQUERIES = 100;
3228
+ var FIELD_BY_NAME_CACHE2 = /* @__PURE__ */ new WeakMap();
3229
+ function getFieldMap(model) {
3230
+ let map = FIELD_BY_NAME_CACHE2.get(model);
3231
+ if (!map) {
3232
+ map = /* @__PURE__ */ new Map();
3233
+ for (const f of model.fields) {
3234
+ map.set(f.name, f);
3235
+ }
3236
+ FIELD_BY_NAME_CACHE2.set(model, map);
3237
+ }
3238
+ return map;
3239
+ }
3168
3240
  function buildIncludeScope(includePath) {
3169
3241
  if (includePath.length === 0) return "include";
3170
3242
  let scope = "include";
@@ -3184,7 +3256,8 @@ function getRelationTableReference(relModel, dialect) {
3184
3256
  );
3185
3257
  }
3186
3258
  function resolveRelationOrThrow(model, schemaByName, relName) {
3187
- const field = model.fields.find((f) => f.name === relName);
3259
+ const fieldMap = getFieldMap(model);
3260
+ const field = fieldMap.get(relName);
3188
3261
  if (!isNotNullish(field)) {
3189
3262
  throw new Error(
3190
3263
  `Unknown relation '${relName}' on model ${model.name}. Available relation fields: ${model.fields.filter((f) => f.isRelation).map((f) => f.name).join(", ")}`
@@ -3301,11 +3374,22 @@ function finalizeOrderByForInclude(args) {
3301
3374
  }
3302
3375
  function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
3303
3376
  let relSelect = buildRelationSelect(relArgs, relModel, relAlias);
3304
- const nestedIncludes = isPlainObject(relArgs) ? buildIncludeSqlInternal(relArgs, __spreadProps(__spreadValues({}, ctx), {
3305
- model: relModel,
3306
- parentAlias: relAlias,
3307
- depth: ctx.depth + 1
3308
- })) : [];
3377
+ let nestedIncludes = [];
3378
+ if (isPlainObject(relArgs)) {
3379
+ const prevModel = ctx.model;
3380
+ const prevParentAlias = ctx.parentAlias;
3381
+ const prevDepth = ctx.depth;
3382
+ ctx.model = relModel;
3383
+ ctx.parentAlias = relAlias;
3384
+ ctx.depth = prevDepth + 1;
3385
+ try {
3386
+ nestedIncludes = buildIncludeSqlInternal(relArgs, ctx);
3387
+ } finally {
3388
+ ctx.model = prevModel;
3389
+ ctx.parentAlias = prevParentAlias;
3390
+ ctx.depth = prevDepth;
3391
+ }
3392
+ }
3309
3393
  if (isNonEmptyArray(nestedIncludes)) {
3310
3394
  const emptyJson = ctx.dialect === "postgres" ? `'[]'::json` : `json('[]')`;
3311
3395
  const nestedSelects = nestedIncludes.map(
@@ -3449,9 +3533,9 @@ function hasNestedRelationInArgs(relArgs, relModel) {
3449
3533
  if (checkSource(relArgs.select)) return true;
3450
3534
  return false;
3451
3535
  }
3452
- function canUseJoinInclude(dialect, isList2, takeVal, skipVal, depth, outerHasLimit, hasNestedIncludes2) {
3536
+ function canUseJoinInclude(dialect, isList, takeVal, skipVal, depth, outerHasLimit, hasNestedIncludes2) {
3453
3537
  if (dialect !== "postgres") return false;
3454
- if (!isList2) return false;
3538
+ if (!isList) return false;
3455
3539
  if (depth > 0) return false;
3456
3540
  if (outerHasLimit) return false;
3457
3541
  if (hasNestedIncludes2) return false;
@@ -3546,7 +3630,7 @@ function buildJoinBasedPaginated(args) {
3546
3630
  function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3547
3631
  const relTable = getRelationTableReference(relModel, ctx.dialect);
3548
3632
  const relAlias = ctx.aliasGen.next(relName);
3549
- const isList2 = typeof field.type === "string" && field.type.endsWith("[]");
3633
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
3550
3634
  const joinPredicate = joinCondition(
3551
3635
  field,
3552
3636
  ctx.model,
@@ -3563,7 +3647,7 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3563
3647
  );
3564
3648
  const whereParts = buildWhereParts(whereInput, relModel, relAlias, ctx);
3565
3649
  const paginationConfig = extractRelationPaginationConfig(relArgs);
3566
- if (!isList2 && typeof paginationConfig.takeVal === "number" && paginationConfig.takeVal < 0) {
3650
+ if (!isList && typeof paginationConfig.takeVal === "number" && paginationConfig.takeVal < 0) {
3567
3651
  throw new Error("Negative take is only supported for list relations");
3568
3652
  }
3569
3653
  const adjusted = maybeReverseNegativeTake(
@@ -3584,7 +3668,7 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3584
3668
  ctx.dialect,
3585
3669
  relModel
3586
3670
  );
3587
- if (!isList2) {
3671
+ if (!isList) {
3588
3672
  const sql = buildOneToOneIncludeSql({
3589
3673
  relTable,
3590
3674
  relAlias,
@@ -3604,7 +3688,7 @@ function buildSingleInclude(relName, relArgs, field, relModel, ctx) {
3604
3688
  const nestedIncludes = hasNestedRelationInArgs(relArgs, relModel);
3605
3689
  if (canUseJoinInclude(
3606
3690
  ctx.dialect,
3607
- isList2,
3691
+ isList,
3608
3692
  adjusted.takeVal,
3609
3693
  paginationConfig.skipVal,
3610
3694
  depth,
@@ -3702,16 +3786,22 @@ function buildIncludeSqlInternal(args, ctx) {
3702
3786
  `Circular include detected: ${Array.from(ctx.visitSet).join(" -> ")} -> ${relationPath}. Relation '${relationPath}' creates an infinite loop.`
3703
3787
  );
3704
3788
  }
3705
- const nextIncludePath = [...ctx.includePath, relName];
3706
- const nextVisitSet = new Set(ctx.visitSet);
3707
- nextVisitSet.add(relationPath);
3708
- includes.push(
3709
- buildSingleInclude(relName, relArgs, resolved.field, resolved.relModel, __spreadProps(__spreadValues({}, ctx), {
3710
- includePath: nextIncludePath,
3711
- visitSet: nextVisitSet,
3712
- depth
3713
- }))
3714
- );
3789
+ ctx.includePath.push(relName);
3790
+ ctx.visitSet.add(relationPath);
3791
+ try {
3792
+ includes.push(
3793
+ buildSingleInclude(
3794
+ relName,
3795
+ relArgs,
3796
+ resolved.field,
3797
+ resolved.relModel,
3798
+ ctx
3799
+ )
3800
+ );
3801
+ } finally {
3802
+ ctx.includePath.pop();
3803
+ ctx.visitSet.delete(relationPath);
3804
+ }
3715
3805
  }
3716
3806
  return includes;
3717
3807
  }
@@ -3995,10 +4085,19 @@ function canUseNestedFlatJoin(relArgs, depth) {
3995
4085
  }
3996
4086
  return true;
3997
4087
  }
3998
- function canUseFlatJoinForAll(includeSpec) {
3999
- for (const value of Object.values(includeSpec)) {
4088
+ function canUseFlatJoinForAll(includeSpec, parentModel, schemas) {
4089
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
4090
+ for (const [relName, value] of Object.entries(includeSpec)) {
4000
4091
  if (value === false) continue;
4092
+ const field = parentModel.fields.find((f) => f.name === relName);
4093
+ if (!field || !field.isRelation) continue;
4001
4094
  if (!canUseNestedFlatJoin(value, 0)) return false;
4095
+ const relModel = modelMap.get(field.relatedModel);
4096
+ if (!relModel) continue;
4097
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
4098
+ if (Object.keys(nestedSpec).length > 0) {
4099
+ if (!canUseFlatJoinForAll(nestedSpec, relModel, schemas)) return false;
4100
+ }
4002
4101
  }
4003
4102
  return true;
4004
4103
  }
@@ -4095,7 +4194,7 @@ function buildFlatJoinSql(spec) {
4095
4194
  if (Object.keys(includeSpec).length === 0) {
4096
4195
  return { sql: "", requiresReduction: false, includeSpec: {} };
4097
4196
  }
4098
- if (!canUseFlatJoinForAll(includeSpec)) {
4197
+ if (!canUseFlatJoinForAll(includeSpec, model, schemas)) {
4099
4198
  return { sql: "", requiresReduction: false, includeSpec: {} };
4100
4199
  }
4101
4200
  const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
@@ -4141,6 +4240,217 @@ function buildFlatJoinSql(spec) {
4141
4240
  `.trim();
4142
4241
  return { sql, requiresReduction: true, includeSpec };
4143
4242
  }
4243
+
4244
+ // src/builder/select/array-agg.ts
4245
+ function canUseArrayAggForAll(includeSpec, parentModel, schemas) {
4246
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
4247
+ for (const [relName, value] of Object.entries(includeSpec)) {
4248
+ if (value === false) continue;
4249
+ const field = parentModel.fields.find((f) => f.name === relName);
4250
+ if (!field || !field.isRelation) continue;
4251
+ if (isPlainObject(value) && hasChildPagination(value)) return false;
4252
+ const relModel = modelMap.get(field.relatedModel);
4253
+ if (!relModel) continue;
4254
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
4255
+ if (Object.keys(nestedSpec).length > 0) return false;
4256
+ }
4257
+ return true;
4258
+ }
4259
+ function getRelationModel2(parentModel, relationName, schemas) {
4260
+ const field = parentModel.fields.find((f) => f.name === relationName);
4261
+ if (!(field == null ? void 0 : field.isRelation) || !field.relatedModel) {
4262
+ throw new Error(`Invalid relation ${relationName} on ${parentModel.name}`);
4263
+ }
4264
+ const relModel = schemas.find((m) => m.name === field.relatedModel);
4265
+ if (!relModel) {
4266
+ throw new Error(`Related model ${field.relatedModel} not found`);
4267
+ }
4268
+ return relModel;
4269
+ }
4270
+ function buildSubqueryRawSelect2(model, alias) {
4271
+ const cols = [];
4272
+ for (const f of model.fields) {
4273
+ if (f.isRelation) continue;
4274
+ cols.push(`${alias}.${quoteColumn(model, f.name)}`);
4275
+ }
4276
+ return cols.length > 0 ? cols.join(SQL_SEPARATORS.FIELD_LIST) : "*";
4277
+ }
4278
+ function readWhereInput2(relArgs) {
4279
+ if (!isPlainObject(relArgs)) return {};
4280
+ const obj = relArgs;
4281
+ if (!("where" in obj)) return {};
4282
+ const w = obj.where;
4283
+ return isPlainObject(w) ? w : {};
4284
+ }
4285
+ function buildArrayAggRelation(args) {
4286
+ const {
4287
+ relationName,
4288
+ relArgs,
4289
+ field,
4290
+ relModel,
4291
+ parentModel,
4292
+ parentAlias,
4293
+ schemas,
4294
+ dialect,
4295
+ aliasCounter,
4296
+ params
4297
+ } = args;
4298
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
4299
+ const { childKeys: relKeyFields, parentKeys: parentKeyFields } = resolveRelationKeys(field, "include");
4300
+ if (relKeyFields.length === 0) return null;
4301
+ const innerAlias = `__aa_r${aliasCounter.count++}`;
4302
+ const joinAlias = `__aa_j${aliasCounter.count++}`;
4303
+ const indices = getFieldIndices(relModel);
4304
+ const scalarSel = extractScalarSelection(relArgs, relModel);
4305
+ const pkFields = getPrimaryKeyFields(relModel);
4306
+ const selectedFields = scalarSel.includeAllScalars ? Array.from(indices.scalarFields.keys()) : [.../* @__PURE__ */ new Set([...pkFields, ...scalarSel.selectedScalarFields])];
4307
+ const pkOrderExpr = pkFields.map((f) => `${innerAlias}.${quoteColumn(relModel, f)}`).join(SQL_SEPARATORS.FIELD_LIST);
4308
+ const pkFilterExpr = `${innerAlias}.${quoteColumn(relModel, pkFields[0])}`;
4309
+ const fkSelectParts = relKeyFields.map(
4310
+ (f, i) => `${innerAlias}.${quoteColumn(relModel, f)} AS "__fk${i}"`
4311
+ );
4312
+ const aggParts = selectedFields.map((fieldName) => {
4313
+ const f = indices.scalarFields.get(fieldName);
4314
+ if (!f) return null;
4315
+ const colRef = `${innerAlias}.${quoteColumn(relModel, fieldName)}`;
4316
+ const alias = `"${relationName}.${f.name}"`;
4317
+ return `array_agg(${colRef} ORDER BY ${pkOrderExpr}) FILTER (WHERE ${pkFilterExpr} IS NOT NULL) AS ${alias}`;
4318
+ }).filter(Boolean);
4319
+ const fkGroupByParts = relKeyFields.map(
4320
+ (f) => `${innerAlias}.${quoteColumn(relModel, f)}`
4321
+ );
4322
+ const relTable = buildTableReference(
4323
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
4324
+ relModel.tableName,
4325
+ dialect
4326
+ );
4327
+ const whereInput = readWhereInput2(relArgs);
4328
+ let whereJoinsSql = "";
4329
+ let whereClauseSql = "";
4330
+ if (Object.keys(whereInput).length > 0) {
4331
+ const aliasGen = createAliasGenerator();
4332
+ const whereResult = buildWhereClause(whereInput, {
4333
+ alias: innerAlias,
4334
+ schemaModels: schemas,
4335
+ model: relModel,
4336
+ params,
4337
+ isSubquery: true,
4338
+ aliasGen,
4339
+ dialect
4340
+ });
4341
+ if (whereResult.joins.length > 0) {
4342
+ whereJoinsSql = " " + whereResult.joins.join(" ");
4343
+ }
4344
+ if (isValidWhereClause(whereResult.clause)) {
4345
+ whereClauseSql = ` ${SQL_TEMPLATES.WHERE} ${whereResult.clause}`;
4346
+ }
4347
+ }
4348
+ const subquery = `SELECT ${fkSelectParts.join(SQL_SEPARATORS.FIELD_LIST)}${SQL_SEPARATORS.FIELD_LIST}${aggParts.join(SQL_SEPARATORS.FIELD_LIST)} FROM ${relTable} ${innerAlias}${whereJoinsSql}${whereClauseSql} GROUP BY ${fkGroupByParts.join(SQL_SEPARATORS.FIELD_LIST)}`;
4349
+ const onParts = parentKeyFields.map(
4350
+ (f, i) => `${joinAlias}."__fk${i}" = ${parentAlias}.${quoteColumn(parentModel, f)}`
4351
+ );
4352
+ const onCondition = onParts.length === 1 ? onParts[0] : `(${onParts.join(" AND ")})`;
4353
+ const joinSql = `LEFT JOIN (${subquery}) ${joinAlias} ON ${onCondition}`;
4354
+ const selectExprs = selectedFields.map((fieldName) => {
4355
+ const f = indices.scalarFields.get(fieldName);
4356
+ if (!f) return null;
4357
+ return `${joinAlias}."${relationName}.${f.name}"`;
4358
+ }).filter(Boolean);
4359
+ return {
4360
+ joinSql,
4361
+ selectExprs,
4362
+ relationName,
4363
+ isList,
4364
+ scalarFieldNames: selectedFields
4365
+ };
4366
+ }
4367
+ function buildArrayAggSql(spec) {
4368
+ const {
4369
+ select,
4370
+ from,
4371
+ whereClause,
4372
+ whereJoins,
4373
+ orderBy,
4374
+ dialect,
4375
+ model,
4376
+ schemas,
4377
+ args,
4378
+ params
4379
+ } = spec;
4380
+ const entries = extractRelationEntries(args, model);
4381
+ const includeSpec = {};
4382
+ for (const e of entries) {
4383
+ includeSpec[e.name] = e.value;
4384
+ }
4385
+ if (Object.keys(includeSpec).length === 0) {
4386
+ return {
4387
+ sql: "",
4388
+ requiresReduction: false,
4389
+ includeSpec: {},
4390
+ isArrayAgg: false
4391
+ };
4392
+ }
4393
+ if (!canUseArrayAggForAll(includeSpec, model, schemas)) {
4394
+ return {
4395
+ sql: "",
4396
+ requiresReduction: false,
4397
+ includeSpec: {},
4398
+ isArrayAgg: false
4399
+ };
4400
+ }
4401
+ const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
4402
+ const baseWhere = whereClause && whereClause !== "1=1" ? `WHERE ${whereClause}` : "";
4403
+ const baseOrderBy = orderBy ? `ORDER BY ${orderBy}` : "";
4404
+ const subqueryScalarCols = buildSubqueryRawSelect2(model, from.alias);
4405
+ let baseSubquery = `SELECT ${subqueryScalarCols} FROM ${from.table} ${from.alias}` + (baseJoins ? ` ${baseJoins}` : "") + (baseWhere ? ` ${baseWhere}` : "") + (baseOrderBy ? ` ${baseOrderBy}` : "");
4406
+ baseSubquery = appendPagination(baseSubquery.trim(), spec);
4407
+ const aliasCounter = { count: 0 };
4408
+ const joins = [];
4409
+ const arraySelectExprs = [];
4410
+ for (const [relName, relValue] of Object.entries(includeSpec)) {
4411
+ if (relValue === false) continue;
4412
+ const field = model.fields.find((f) => f.name === relName);
4413
+ if (!field || !isValidRelationField(field)) continue;
4414
+ const relModel = getRelationModel2(model, relName, schemas);
4415
+ const built = buildArrayAggRelation({
4416
+ relationName: relName,
4417
+ relArgs: relValue,
4418
+ field,
4419
+ relModel,
4420
+ parentModel: model,
4421
+ parentAlias: from.alias,
4422
+ schemas,
4423
+ dialect,
4424
+ aliasCounter,
4425
+ params
4426
+ });
4427
+ if (!built) continue;
4428
+ joins.push(built.joinSql);
4429
+ arraySelectExprs.push(...built.selectExprs);
4430
+ }
4431
+ if (joins.length === 0) {
4432
+ return {
4433
+ sql: "",
4434
+ requiresReduction: false,
4435
+ includeSpec: {},
4436
+ isArrayAgg: false
4437
+ };
4438
+ }
4439
+ const baseSelect = (select != null ? select : "").trim();
4440
+ const allSelects = [baseSelect, ...arraySelectExprs].filter((s) => s && s.trim().length > 0).join(SQL_SEPARATORS.FIELD_LIST);
4441
+ if (!allSelects) {
4442
+ throw new Error("Array-agg SELECT requires at least one selected field");
4443
+ }
4444
+ const pkField = getPrimaryKeyField(model);
4445
+ const pkOrder = `${from.alias}.${quoteColumn(model, pkField)} ASC`;
4446
+ const sql = `
4447
+ SELECT ${allSelects}
4448
+ FROM (${baseSubquery}) ${from.alias}
4449
+ ${joins.join(" ")}
4450
+ ORDER BY ${pkOrder}
4451
+ `.trim();
4452
+ return { sql, requiresReduction: true, includeSpec, isArrayAgg: true };
4453
+ }
4144
4454
  var SELECT_FIELD_REGEX = /^\s*("(?:[^"]|"")+"|[a-z_][a-z0-9_]*)\s*\.\s*("(?:[^"]|"")+"|[a-z_][a-z0-9_]*)(?:\s+AS\s+("(?:[^"]|"")+"|[a-z_][a-z0-9_]*))?\s*$/i;
4145
4455
  function buildWhereSql(conditions) {
4146
4456
  if (!isNonEmptyArray(conditions)) return "";
@@ -4228,47 +4538,45 @@ function buildOutputColumns(scalarNames, includeNames, hasCount) {
4228
4538
  }
4229
4539
  return formatted;
4230
4540
  }
4231
- function buildWindowOrder(args) {
4232
- const { baseOrder, idField, fromAlias, model } = args;
4233
- const fromLower = String(fromAlias).toLowerCase();
4234
- const orderFields = baseOrder.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim().toLowerCase().replace(/\s+/g, " "));
4235
- const hasIdInOrder = orderFields.some((f) => {
4236
- return f.includes(`${fromLower}.id`) || f.includes(`${fromLower}."id"`);
4237
- });
4238
- if (hasIdInOrder) return baseOrder;
4239
- const idTiebreaker = idField ? ", " + col(fromAlias, "id", model) + " ASC" : "";
4240
- return baseOrder + idTiebreaker;
4241
- }
4242
- function extractDistinctOrderEntries(spec) {
4243
- if (isNotNullish(spec.args.orderBy)) {
4244
- const normalized = normalizeOrderByInput(
4245
- spec.args.orderBy,
4246
- parseOrderByValue
4247
- );
4248
- const entries = [];
4249
- for (const item of normalized) {
4250
- for (const field in item) {
4251
- if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
4252
- const value = item[field];
4253
- if (typeof value === "string") {
4254
- entries.push({ field, direction: value });
4255
- continue;
4256
- }
4257
- const obj = value;
4258
- entries.push({ field, direction: obj.direction, nulls: obj.nulls });
4541
+ function getOrderByEntries(spec) {
4542
+ if (!isNotNullish(spec.args.orderBy)) return [];
4543
+ const normalized = normalizeOrderByInput(spec.args.orderBy, parseOrderByValue);
4544
+ const entries = [];
4545
+ for (const item of normalized) {
4546
+ for (const field in item) {
4547
+ if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
4548
+ const value = item[field];
4549
+ if (typeof value === "string") {
4550
+ entries.push({ field, direction: value });
4551
+ continue;
4259
4552
  }
4553
+ const obj = value;
4554
+ entries.push({ field, direction: obj.direction, nulls: obj.nulls });
4260
4555
  }
4261
- if (entries.length > 0) return entries;
4262
4556
  }
4263
- if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
4264
- return [...spec.distinct].map((f) => ({
4265
- field: f,
4266
- direction: "asc"
4267
- }));
4557
+ return entries;
4558
+ }
4559
+ function renderOrderBySql(entries, alias, dialect, model) {
4560
+ if (entries.length === 0) return "";
4561
+ const out = [];
4562
+ for (const e of entries) {
4563
+ const dir = e.direction.toUpperCase();
4564
+ const c = col(alias, e.field, model);
4565
+ if (dialect === "postgres") {
4566
+ const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
4567
+ out.push(c + " " + dir + nulls);
4568
+ } else if (isNotNullish(e.nulls)) {
4569
+ const isNullExpr = `(${c} IS NULL)`;
4570
+ const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
4571
+ out.push(isNullExpr + " " + nullRankDir);
4572
+ out.push(c + " " + dir);
4573
+ } else {
4574
+ out.push(c + " " + dir);
4575
+ }
4268
4576
  }
4269
- return [];
4577
+ return out.join(SQL_SEPARATORS.ORDER_BY);
4270
4578
  }
4271
- function buildFieldNameOrderBy(entries, alias) {
4579
+ function renderOrderBySimple(entries, alias) {
4272
4580
  if (entries.length === 0) return "";
4273
4581
  const out = [];
4274
4582
  for (const e of entries) {
@@ -4279,40 +4587,73 @@ function buildFieldNameOrderBy(entries, alias) {
4279
4587
  const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
4280
4588
  out.push(isNullExpr + " " + nullRankDir);
4281
4589
  out.push(c + " " + dir);
4282
- continue;
4590
+ } else {
4591
+ out.push(c + " " + dir);
4283
4592
  }
4284
- out.push(c + " " + dir);
4285
4593
  }
4286
4594
  return out.join(SQL_SEPARATORS.ORDER_BY);
4287
4595
  }
4596
+ function ensureIdTiebreakerEntries(entries, model) {
4597
+ var _a3, _b;
4598
+ const idField = (_b = (_a3 = model == null ? void 0 : model.fields) == null ? void 0 : _a3.find) == null ? void 0 : _b.call(
4599
+ _a3,
4600
+ (f) => f.name === "id" && !f.isRelation
4601
+ );
4602
+ if (!idField) return entries;
4603
+ if (entries.some((e) => e.field === "id")) return entries;
4604
+ return [...entries, { field: "id", direction: "asc" }];
4605
+ }
4606
+ function ensurePostgresDistinctOrderEntries(args) {
4607
+ const { entries, distinct, model } = args;
4608
+ const distinctEntries = [...distinct].map((f) => ({
4609
+ field: f,
4610
+ direction: "asc"
4611
+ }));
4612
+ const canKeepAsIs = entries.length >= distinctEntries.length && distinctEntries.every((de, i) => entries[i].field === de.field);
4613
+ const merged = canKeepAsIs ? entries : [...distinctEntries, ...entries];
4614
+ return ensureIdTiebreakerEntries(merged, model);
4615
+ }
4616
+ function extractDistinctOrderEntries(spec) {
4617
+ const entries = getOrderByEntries(spec);
4618
+ if (entries.length > 0) return entries;
4619
+ if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
4620
+ return [...spec.distinct].map((f) => ({
4621
+ field: f,
4622
+ direction: "asc"
4623
+ }));
4624
+ }
4625
+ return [];
4626
+ }
4288
4627
  function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
4289
- var _a, _b;
4290
- const { includes, from, whereClause, whereJoins, orderBy, distinct, model } = spec;
4628
+ var _a3, _b;
4629
+ const { includes, from, whereClause, whereJoins, distinct, model } = spec;
4291
4630
  if (!isNotNullish(distinct) || !isNonEmptyArray(distinct)) {
4292
4631
  throw new Error("buildSqliteDistinctQuery requires distinct fields");
4293
4632
  }
4294
4633
  const scalarNames = parseSimpleScalarSelect(spec.select, from.alias);
4295
4634
  const includeNames = includes.map((i) => i.name);
4296
- const hasCount = Boolean((_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count);
4635
+ const hasCount = Boolean((_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count);
4297
4636
  const outerSelectCols = buildOutputColumns(
4298
4637
  scalarNames,
4299
4638
  includeNames,
4300
4639
  hasCount
4301
4640
  );
4302
4641
  const distinctCols = buildDistinctColumns([...distinct], from.alias, model);
4303
- const fallbackOrder = [...distinct].map((f) => col(from.alias, f, model) + " ASC").join(SQL_SEPARATORS.FIELD_LIST);
4304
- const idField = model.fields.find(
4305
- (f) => f.name === "id" && !f.isRelation
4306
- );
4307
- const baseOrder = isNonEmptyString(orderBy) ? orderBy : fallbackOrder;
4308
- const windowOrder = buildWindowOrder({
4309
- baseOrder,
4310
- idField,
4311
- fromAlias: from.alias,
4642
+ const baseEntries = getOrderByEntries(spec);
4643
+ const fallbackEntries = [...distinct].map((f) => ({
4644
+ field: f,
4645
+ direction: "asc"
4646
+ }));
4647
+ const resolvedEntries = baseEntries.length > 0 ? baseEntries : fallbackEntries;
4648
+ const windowEntries = ensureIdTiebreakerEntries(resolvedEntries, model);
4649
+ const windowOrder = renderOrderBySql(
4650
+ windowEntries,
4651
+ from.alias,
4652
+ "sqlite",
4312
4653
  model
4313
- });
4654
+ );
4314
4655
  const outerEntries = extractDistinctOrderEntries(spec);
4315
- const outerOrder = buildFieldNameOrderBy(outerEntries, '"__tp_distinct"');
4656
+ const outerOrder = renderOrderBySimple(outerEntries, '"__tp_distinct"');
4316
4657
  const joins = buildJoinsSql(whereJoins, countJoins);
4317
4658
  const conditions = [];
4318
4659
  if (whereClause && whereClause !== "1=1") conditions.push(whereClause);
@@ -4363,12 +4704,12 @@ function resolveCountSelect(countSelectRaw, model) {
4363
4704
  return null;
4364
4705
  }
4365
4706
  function buildIncludeColumns(spec) {
4366
- var _a, _b;
4707
+ var _a3, _b;
4367
4708
  const { select, includes, dialect, model, schemas, from, params } = spec;
4368
4709
  const baseSelect = (select != null ? select : "").trim();
4369
4710
  let countCols = "";
4370
4711
  let countJoins = [];
4371
- const countSelectRaw = (_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count;
4712
+ const countSelectRaw = (_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count;
4372
4713
  if (countSelectRaw) {
4373
4714
  const resolvedCountSelect = resolveCountSelect(countSelectRaw, model);
4374
4715
  if (resolvedCountSelect && Object.keys(resolvedCountSelect).length > 0) {
@@ -4527,37 +4868,6 @@ function extractIncludeSpec(args) {
4527
4868
  function hasNestedIncludes(includeSpec) {
4528
4869
  return Object.keys(includeSpec).length > 0;
4529
4870
  }
4530
- function splitOrderByTerms(orderBy) {
4531
- const raw = orderBy.trim();
4532
- if (raw.length === 0) return [];
4533
- return raw.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim()).filter((s) => s.length > 0);
4534
- }
4535
- function hasIdInOrderBy(orderBy, fromAlias) {
4536
- const lower = orderBy.toLowerCase();
4537
- const aliasLower = fromAlias.toLowerCase();
4538
- return lower.includes(`${aliasLower}.id `) || lower.includes(`${aliasLower}."id"`);
4539
- }
4540
- function ensureIdTiebreakerOrderBy(orderBy, fromAlias, model) {
4541
- var _a, _b;
4542
- const idField = (_b = (_a = model == null ? void 0 : model.fields) == null ? void 0 : _a.find) == null ? void 0 : _b.call(
4543
- _a,
4544
- (f) => f.name === "id" && !f.isRelation
4545
- );
4546
- if (!idField) return orderBy;
4547
- if (hasIdInOrderBy(orderBy, fromAlias)) return orderBy;
4548
- const t = col(fromAlias, "id", model) + " ASC";
4549
- return isNonEmptyString(orderBy) ? orderBy + ", " + t : t;
4550
- }
4551
- function ensurePostgresDistinctOrderBy(args) {
4552
- const { orderBy, distinct, fromAlias, model } = args;
4553
- const distinctTerms = distinct.map((f) => col(fromAlias, f, model) + " ASC");
4554
- const existing = splitOrderByTerms(orderBy);
4555
- const canKeepAsIs = existing.length >= distinctTerms.length && distinctTerms.every(
4556
- (term, i) => existing[i].toLowerCase().startsWith(term.split(" ASC")[0].toLowerCase())
4557
- );
4558
- const merged = canKeepAsIs ? orderBy : [...distinctTerms, ...existing].join(SQL_SEPARATORS.ORDER_BY);
4559
- return ensureIdTiebreakerOrderBy(merged, fromAlias, model);
4560
- }
4561
4871
  function constructFinalSql(spec) {
4562
4872
  const {
4563
4873
  select,
@@ -4572,7 +4882,6 @@ function constructFinalSql(spec) {
4572
4882
  params,
4573
4883
  dialect,
4574
4884
  model,
4575
- includes,
4576
4885
  schemas,
4577
4886
  pagination,
4578
4887
  args
@@ -4584,7 +4893,24 @@ function constructFinalSql(spec) {
4584
4893
  const includeSpec = extractIncludeSpec(args);
4585
4894
  const hasIncludes = hasNestedIncludes(includeSpec);
4586
4895
  const hasPagination = isNotNullish(pagination.take);
4587
- const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec);
4896
+ const takeValue = typeof pagination.take === "number" ? pagination.take : null;
4897
+ const isLargeTake = takeValue !== null && takeValue > 50;
4898
+ const shouldUseArrayAgg = dialect === "postgres" && hasIncludes && method === "findMany" && hasPagination && isLargeTake && canUseArrayAggForAll(includeSpec, model, schemas);
4899
+ if (shouldUseArrayAgg) {
4900
+ const aaResult = buildArrayAggSql(spec);
4901
+ if (aaResult.sql) {
4902
+ const baseSqlResult = finalizeSql(aaResult.sql, params, dialect);
4903
+ return {
4904
+ sql: baseSqlResult.sql,
4905
+ params: baseSqlResult.params,
4906
+ paramMappings: baseSqlResult.paramMappings,
4907
+ requiresReduction: true,
4908
+ includeSpec: aaResult.includeSpec,
4909
+ isArrayAgg: true
4910
+ };
4911
+ }
4912
+ }
4913
+ const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec, model, schemas);
4588
4914
  if (shouldUseFlatJoin) {
4589
4915
  const flatResult = buildFlatJoinSql(spec);
4590
4916
  if (flatResult.sql) {
@@ -4630,12 +4956,13 @@ function constructFinalSql(spec) {
4630
4956
  pushWhere(parts, conditions);
4631
4957
  let finalOrderBy = orderBy;
4632
4958
  if (dialect === "postgres" && isNonEmptyArray(distinct)) {
4633
- finalOrderBy = ensurePostgresDistinctOrderBy({
4634
- orderBy: orderBy || "",
4959
+ const currentEntries = getOrderByEntries(spec);
4960
+ const mergedEntries = ensurePostgresDistinctOrderEntries({
4961
+ entries: currentEntries.length > 0 ? currentEntries : [],
4635
4962
  distinct: [...distinct],
4636
- fromAlias: from.alias,
4637
4963
  model
4638
4964
  });
4965
+ finalOrderBy = renderOrderBySql(mergedEntries, from.alias, dialect, model);
4639
4966
  }
4640
4967
  if (isNonEmptyString(finalOrderBy))
4641
4968
  parts.push(SQL_TEMPLATES.ORDER_BY, finalOrderBy);
@@ -4661,11 +4988,11 @@ function mapFirstOrderByByField(existing) {
4661
4988
  return m;
4662
4989
  }
4663
4990
  function buildPostgresDistinctOrderBy(distinctFields, existing) {
4664
- var _a;
4991
+ var _a3;
4665
4992
  const firstByField = mapFirstOrderByByField(existing);
4666
4993
  const next = [];
4667
4994
  for (const f of distinctFields) {
4668
- next.push((_a = firstByField.get(f)) != null ? _a : { [f]: "asc" });
4995
+ next.push((_a3 = firstByField.get(f)) != null ? _a3 : { [f]: "asc" });
4669
4996
  }
4670
4997
  const distinctSet = new Set(distinctFields);
4671
4998
  for (const obj of existing) {
@@ -5491,10 +5818,10 @@ function isPrismaMethod(v) {
5491
5818
  return v === "findMany" || v === "findFirst" || v === "findUnique" || v === "aggregate" || v === "groupBy" || v === "count";
5492
5819
  }
5493
5820
  function resolveMethod(directive) {
5494
- var _a, _b;
5821
+ var _a3, _b;
5495
5822
  const m = directive == null ? void 0 : directive.method;
5496
5823
  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;
5824
+ const pm = (_b = (_a3 = directive == null ? void 0 : directive.query) == null ? void 0 : _a3.processed) == null ? void 0 : _b.method;
5498
5825
  if (isPrismaMethod(pm)) return pm;
5499
5826
  return "findMany";
5500
5827
  }
@@ -5655,7 +5982,7 @@ function extractIncludeSpec2(processed, modelDef) {
5655
5982
  return includeSpec;
5656
5983
  }
5657
5984
  function buildAndNormalizeSql(args) {
5658
- var _a;
5985
+ var _a3;
5659
5986
  const {
5660
5987
  method,
5661
5988
  processed,
@@ -5681,13 +6008,15 @@ function buildAndNormalizeSql(args) {
5681
6008
  sqlResult.paramMappings,
5682
6009
  dialect
5683
6010
  );
5684
- const includeSpec = (_a = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a : extractIncludeSpec2(processed, modelDef);
6011
+ const includeSpec = (_a3 = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a3 : extractIncludeSpec2(processed, modelDef);
5685
6012
  const requiresReduction = sqlResult.requiresReduction === true;
6013
+ const isArrayAgg = sqlResult.isArrayAgg === true;
5686
6014
  return {
5687
6015
  sql: normalized.sql,
5688
6016
  paramMappings: normalized.paramMappings,
5689
6017
  requiresReduction,
5690
- includeSpec
6018
+ includeSpec,
6019
+ isArrayAgg
5691
6020
  };
5692
6021
  }
5693
6022
  function finalizeDirective(args) {
@@ -5698,11 +6027,12 @@ function finalizeDirective(args) {
5698
6027
  normalizedMappings,
5699
6028
  dialect,
5700
6029
  requiresReduction,
5701
- includeSpec
6030
+ includeSpec,
6031
+ isArrayAgg
5702
6032
  } = args;
5703
6033
  const params = normalizedMappings.map((m) => {
5704
- var _a;
5705
- return (_a = m.value) != null ? _a : void 0;
6034
+ var _a3;
6035
+ return (_a3 = m.value) != null ? _a3 : void 0;
5706
6036
  });
5707
6037
  validateParamConsistencyByDialect(normalizedSql, params, dialect);
5708
6038
  const { staticParams, dynamicKeys, paramOrder } = buildParamsFromMappings(normalizedMappings);
@@ -5715,6 +6045,7 @@ function finalizeDirective(args) {
5715
6045
  paramMappings: normalizedMappings,
5716
6046
  requiresReduction,
5717
6047
  includeSpec,
6048
+ isArrayAgg,
5718
6049
  originalDirective: directive
5719
6050
  };
5720
6051
  }
@@ -5748,7 +6079,8 @@ function generateSQL(directive) {
5748
6079
  normalizedMappings: built.paramMappings,
5749
6080
  dialect,
5750
6081
  requiresReduction: built.requiresReduction,
5751
- includeSpec: built.includeSpec
6082
+ includeSpec: built.includeSpec,
6083
+ isArrayAgg: built.isArrayAgg
5752
6084
  });
5753
6085
  }
5754
6086
 
@@ -6355,7 +6687,8 @@ function buildSQLFull(model, models, method, args, dialect) {
6355
6687
  return __spreadProps(__spreadValues({}, sqlResult), {
6356
6688
  paramMappings: result.paramMappings,
6357
6689
  requiresReduction: result.requiresReduction,
6358
- includeSpec: result.includeSpec
6690
+ includeSpec: result.includeSpec,
6691
+ isArrayAgg: result.isArrayAgg
6359
6692
  });
6360
6693
  }
6361
6694
  function buildSQLWithCache(model, models, method, args, dialect) {
@@ -6368,7 +6701,8 @@ function buildSQLWithCache(model, models, method, args, dialect) {
6368
6701
  params: [...cached.params],
6369
6702
  paramMappings: cached.paramMappings,
6370
6703
  requiresReduction: cached.requiresReduction,
6371
- includeSpec: cached.includeSpec
6704
+ includeSpec: cached.includeSpec,
6705
+ isArrayAgg: cached.isArrayAgg
6372
6706
  };
6373
6707
  }
6374
6708
  queryCacheStats.miss();
@@ -6386,7 +6720,8 @@ function buildSQLWithCache(model, models, method, args, dialect) {
6386
6720
  params: [...result.params],
6387
6721
  paramMappings: result.paramMappings,
6388
6722
  requiresReduction: result.requiresReduction,
6389
- includeSpec: result.includeSpec
6723
+ includeSpec: result.includeSpec,
6724
+ isArrayAgg: result.isArrayAgg
6390
6725
  });
6391
6726
  return result;
6392
6727
  }
@@ -6460,10 +6795,10 @@ function getRowTransformer(method) {
6460
6795
 
6461
6796
  // src/result-transformers.ts
6462
6797
  function transformQueryResults(method, results) {
6463
- var _a, _b;
6798
+ var _a3, _b;
6464
6799
  if (method === "findFirst" || method === "findUnique") {
6465
6800
  if (Array.isArray(results)) {
6466
- return (_a = results[0]) != null ? _a : null;
6801
+ return (_a3 = results[0]) != null ? _a3 : null;
6467
6802
  }
6468
6803
  }
6469
6804
  if (method === "aggregate") {
@@ -6710,9 +7045,9 @@ function wrapQueryForMethod(method, cteName, resultAlias) {
6710
7045
  }
6711
7046
  }
6712
7047
  function isAllCountQueries(queries, keys) {
6713
- var _a;
7048
+ var _a3;
6714
7049
  for (const key of keys) {
6715
- if (((_a = queries[key]) == null ? void 0 : _a.method) !== "count") return false;
7050
+ if (((_a3 = queries[key]) == null ? void 0 : _a3.method) !== "count") return false;
6716
7051
  }
6717
7052
  return true;
6718
7053
  }
@@ -6951,8 +7286,8 @@ function buildMergedCountBatchSql(queries, keys, aliasesByKey, modelMap, models,
6951
7286
  const fromSql = rewrittenSubs.join(" CROSS JOIN ");
6952
7287
  const sql = `SELECT ${selectParts.join(", ")} FROM ${fromSql}`;
6953
7288
  const aliases = keys.map((k) => {
6954
- var _a;
6955
- return (_a = aliasesByKey.get(k)) != null ? _a : "";
7289
+ var _a3;
7290
+ return (_a3 = aliasesByKey.get(k)) != null ? _a3 : "";
6956
7291
  });
6957
7292
  return { sql, params: finalParams, keys, aliases };
6958
7293
  }
@@ -7320,11 +7655,11 @@ function parseBatchValue(rawValue, method, modelName, modelMap) {
7320
7655
  }
7321
7656
  }
7322
7657
  function parseBatchResults(row, keys, queries, aliases, modelMap) {
7323
- var _a;
7658
+ var _a3;
7324
7659
  const results = {};
7325
7660
  for (let i = 0; i < keys.length; i++) {
7326
7661
  const key = keys[i];
7327
- const columnKey = (_a = aliases == null ? void 0 : aliases[i]) != null ? _a : key;
7662
+ const columnKey = (_a3 = aliases == null ? void 0 : aliases[i]) != null ? _a3 : key;
7328
7663
  const rawValue = row[columnKey];
7329
7664
  const query = queries[key];
7330
7665
  results[key] = parseBatchValue(
@@ -7422,37 +7757,20 @@ function createTransactionExecutor(deps) {
7422
7757
  }
7423
7758
 
7424
7759
  // src/builder/shared/key-utils.ts
7425
- function buildCompositeKey(row, fields) {
7760
+ function buildKey(row, fields) {
7426
7761
  if (fields.length === 0) return null;
7427
7762
  if (fields.length === 1) {
7428
7763
  const val = row[fields[0]];
7429
- if (val == null) return null;
7430
- const t = typeof val;
7431
- if (t === "string") return `s:${val}`;
7432
- if (t === "number") return Number.isFinite(val) ? `n:${val}` : null;
7433
- if (t === "boolean") return val ? "b:1" : "b:0";
7434
- if (t === "bigint") return `i:${val}`;
7435
- return `o:${val}`;
7436
- }
7437
- const parts = new Array(fields.length);
7764
+ return val == null ? null : val;
7765
+ }
7766
+ let key = "";
7438
7767
  for (let i = 0; i < fields.length; i++) {
7439
7768
  const val = row[fields[i]];
7440
7769
  if (val == null) return null;
7441
- const t = typeof val;
7442
- if (t === "string") {
7443
- parts[i] = `s:${val}`;
7444
- } else if (t === "number") {
7445
- if (!Number.isFinite(val)) return null;
7446
- parts[i] = `n:${val}`;
7447
- } else if (t === "boolean") {
7448
- parts[i] = val ? "b:1" : "b:0";
7449
- } else if (t === "bigint") {
7450
- parts[i] = `i:${val}`;
7451
- } else {
7452
- parts[i] = `o:${val}`;
7453
- }
7770
+ if (i > 0) key += "";
7771
+ key += typeof val === "string" ? val : String(val);
7454
7772
  }
7455
- return parts.join("");
7773
+ return key;
7456
7774
  }
7457
7775
 
7458
7776
  // src/builder/select/reducer.ts
@@ -7469,6 +7787,14 @@ function buildRelationScalarCols(relModel, relPath, includeAllScalars, selectedS
7469
7787
  }
7470
7788
  return out;
7471
7789
  }
7790
+ function extractChildLimit(relArgs) {
7791
+ if (!isPlainObject(relArgs)) return void 0;
7792
+ const obj = relArgs;
7793
+ if ("take" in obj && typeof obj.take === "number" && obj.take > 0) {
7794
+ return obj.take;
7795
+ }
7796
+ return void 0;
7797
+ }
7472
7798
  function buildReducerConfig(parentModel, includeSpec, allModels, prefix = "", depth = 0) {
7473
7799
  if (depth > 10) {
7474
7800
  throw new Error(
@@ -7491,7 +7817,7 @@ function buildReducerConfig(parentModel, includeSpec, allModels, prefix = "", de
7491
7817
  `Related model '${field.relatedModel}' not found for relation '${incName}'`
7492
7818
  );
7493
7819
  }
7494
- const isList2 = typeof field.type === "string" && field.type.endsWith("[]");
7820
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
7495
7821
  const primaryKeyFields = getPrimaryKeyFields(relatedModel);
7496
7822
  const scalarSel = extractScalarSelection(incValue, relatedModel);
7497
7823
  const relPath = prefix ? `${prefix}.${incName}` : incName;
@@ -7513,14 +7839,16 @@ function buildReducerConfig(parentModel, includeSpec, allModels, prefix = "", de
7513
7839
  scalarSel.includeAllScalars,
7514
7840
  scalarSel.selectedScalarFields
7515
7841
  );
7842
+ const childLimit = isList ? extractChildLimit(incValue) : void 0;
7516
7843
  includedRelations.push({
7517
7844
  name: incName,
7518
- cardinality: isList2 ? "many" : "one",
7845
+ cardinality: isList ? "many" : "one",
7519
7846
  relatedModel,
7520
7847
  primaryKeyFields,
7521
7848
  includeAllScalars: scalarSel.includeAllScalars,
7522
7849
  selectedScalarFields: scalarSel.selectedScalarFields,
7523
7850
  nestedIncludes,
7851
+ childLimit,
7524
7852
  path: relPath,
7525
7853
  keyCols,
7526
7854
  scalarCols
@@ -7552,7 +7880,7 @@ function initNestedPlaceholders(obj, nested) {
7552
7880
  }
7553
7881
  }
7554
7882
  function materializeRelationObject(row, rel) {
7555
- const relKey = buildCompositeKey(row, rel.keyCols);
7883
+ const relKey = buildKey(row, rel.keyCols);
7556
7884
  if (relKey == null) return null;
7557
7885
  const obj = {};
7558
7886
  for (const c of rel.scalarCols) {
@@ -7568,7 +7896,7 @@ function processNestedRelations(obj, rel, row, manyStore) {
7568
7896
  }
7569
7897
  }
7570
7898
  function processRelation(parentObj, rel, row, manyStore) {
7571
- const relKey = buildCompositeKey(row, rel.keyCols);
7899
+ const relKey = buildKey(row, rel.keyCols);
7572
7900
  if (relKey == null) return;
7573
7901
  if (rel.cardinality === "one") {
7574
7902
  let current = parentObj[rel.name];
@@ -7582,6 +7910,9 @@ function processRelation(parentObj, rel, row, manyStore) {
7582
7910
  return;
7583
7911
  }
7584
7912
  const arr = parentObj[rel.name];
7913
+ if (rel.childLimit && arr.length >= rel.childLimit) {
7914
+ return;
7915
+ }
7585
7916
  const idx = getIndexForParent(manyStore, parentObj, rel.path);
7586
7917
  const existing = idx.get(relKey);
7587
7918
  if (existing) {
@@ -7615,7 +7946,7 @@ function reduceFlatRows(rows, config) {
7615
7946
  const manyStore = /* @__PURE__ */ new WeakMap();
7616
7947
  for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
7617
7948
  const row = rows[rowIdx];
7618
- const parentKey = buildCompositeKey(row, parentKeyCols);
7949
+ const parentKey = buildKey(row, parentKeyCols);
7619
7950
  if (parentKey == null) continue;
7620
7951
  let record = resultMap.get(parentKey);
7621
7952
  if (!record) {
@@ -7640,9 +7971,7 @@ function reduceFlatRows(rows, config) {
7640
7971
  }
7641
7972
 
7642
7973
  // src/builder/select/segment-planner.ts
7643
- var HARD_FANOUT_CAP = 5e3;
7644
- var MAX_ESTIMATED_ROWS = Number.MAX_SAFE_INTEGER / 1e3;
7645
- function isList(field) {
7974
+ function isListField(field) {
7646
7975
  return typeof field.type === "string" && field.type.endsWith("[]");
7647
7976
  }
7648
7977
  function resolveRelation(model, relName, allModels) {
@@ -7652,47 +7981,6 @@ function resolveRelation(model, relName, allModels) {
7652
7981
  if (!relModel) return null;
7653
7982
  return { field, relModel };
7654
7983
  }
7655
- function effectiveFanout(stats) {
7656
- return 1 + stats.coverage * (stats.avg - 1);
7657
- }
7658
- function estimateFlatRows(parentCount, relations, stats) {
7659
- var _a;
7660
- let rows = parentCount;
7661
- for (const rel of relations) {
7662
- const relStats = (_a = stats == null ? void 0 : stats[rel.modelName]) == null ? void 0 : _a[rel.relName];
7663
- const fanout = relStats ? effectiveFanout(relStats) : 10;
7664
- const next = rows * fanout;
7665
- if (next > MAX_ESTIMATED_ROWS) {
7666
- return MAX_ESTIMATED_ROWS;
7667
- }
7668
- rows = next;
7669
- }
7670
- return Math.ceil(rows);
7671
- }
7672
- function collectOneToManyRelations(entries, model, allModels) {
7673
- const out = [];
7674
- for (const entry of entries) {
7675
- const resolved = resolveRelation(model, entry.name, allModels);
7676
- if (!resolved) continue;
7677
- if (!isList(resolved.field)) continue;
7678
- out.push({
7679
- name: entry.name,
7680
- relArgs: entry.value,
7681
- field: resolved.field,
7682
- relModel: resolved.relModel,
7683
- hasPagination: hasChildPagination(entry.value)
7684
- });
7685
- }
7686
- return out;
7687
- }
7688
- function getParentCount(method, args) {
7689
- if (method === "findFirst" || method === "findUnique") return 1;
7690
- if ((args == null ? void 0 : args.take) !== void 0 && (args == null ? void 0 : args.take) !== null) {
7691
- const take = typeof args.take === "number" ? Math.abs(args.take) : null;
7692
- if (take !== null) return take;
7693
- }
7694
- return null;
7695
- }
7696
7984
  function buildWhereInSegment(name, relArgs, field, relModel) {
7697
7985
  const keys = resolveRelationKeys(field, "whereIn");
7698
7986
  if (keys.childKeys.length !== 1) return null;
@@ -7702,7 +7990,7 @@ function buildWhereInSegment(name, relArgs, field, relModel) {
7702
7990
  childModelName: relModel.name,
7703
7991
  fkFieldName: keys.childKeys[0],
7704
7992
  parentKeyFieldName: keys.parentKeys[0],
7705
- isList: true
7993
+ isList: isListField(field)
7706
7994
  };
7707
7995
  }
7708
7996
  function deepClone(obj) {
@@ -7736,74 +8024,154 @@ function removeRelationsFromArgs(args, names) {
7736
8024
  }
7737
8025
  return filtered;
7738
8026
  }
8027
+ function ensureParentKeysInSelect(args, segments) {
8028
+ if (!(args == null ? void 0 : args.select)) return { args, injectedKeys: [] };
8029
+ const injected = [];
8030
+ const newSelect = __spreadValues({}, args.select);
8031
+ for (const seg of segments) {
8032
+ if (!newSelect[seg.parentKeyFieldName]) {
8033
+ newSelect[seg.parentKeyFieldName] = true;
8034
+ injected.push(seg.parentKeyFieldName);
8035
+ }
8036
+ }
8037
+ if (injected.length === 0) return { args, injectedKeys: [] };
8038
+ return { args: __spreadProps(__spreadValues({}, args), { select: newSelect }), injectedKeys: injected };
8039
+ }
7739
8040
  function planQueryStrategy(params) {
7740
- const { model, method, args, allModels, relationStats } = params;
8041
+ const { model, args, allModels } = params;
8042
+ const emptyPlan = {
8043
+ filteredArgs: args,
8044
+ whereInSegments: [],
8045
+ injectedParentKeys: []
8046
+ };
7741
8047
  const entries = extractRelationEntries(args, model);
7742
8048
  if (entries.length === 0) {
7743
- return { filteredArgs: args, whereInSegments: [] };
7744
- }
7745
- const oneToManyRels = collectOneToManyRelations(entries, model, allModels);
7746
- const unpaginatedOneToMany = oneToManyRels.filter((r) => !r.hasPagination);
7747
- if (unpaginatedOneToMany.length === 0) {
7748
- return { filteredArgs: args, whereInSegments: [] };
8049
+ return emptyPlan;
7749
8050
  }
7750
- const parentCount = getParentCount(method, args);
7751
8051
  const whereInSegments = [];
7752
8052
  const toRemove = /* @__PURE__ */ new Set();
7753
- if (unpaginatedOneToMany.length > 1) {
7754
- for (const rel of unpaginatedOneToMany) {
7755
- const segment = buildWhereInSegment(
7756
- rel.name,
7757
- rel.relArgs,
7758
- rel.field,
7759
- rel.relModel
7760
- );
7761
- if (segment) {
7762
- whereInSegments.push(segment);
7763
- toRemove.add(rel.name);
7764
- }
8053
+ for (const entry of entries) {
8054
+ const resolved = resolveRelation(model, entry.name, allModels);
8055
+ if (!resolved) continue;
8056
+ if (isListField(resolved.field) && hasChildPagination(entry.value)) {
8057
+ continue;
7765
8058
  }
7766
- } else if (unpaginatedOneToMany.length === 1) {
7767
- const rel = unpaginatedOneToMany[0];
7768
- if (parentCount === null) {
7769
- const segment = buildWhereInSegment(
7770
- rel.name,
7771
- rel.relArgs,
7772
- rel.field,
7773
- rel.relModel
8059
+ const segment = buildWhereInSegment(
8060
+ entry.name,
8061
+ entry.value,
8062
+ resolved.field,
8063
+ resolved.relModel
8064
+ );
8065
+ if (segment) {
8066
+ whereInSegments.push(segment);
8067
+ toRemove.add(entry.name);
8068
+ }
8069
+ }
8070
+ if (toRemove.size === 0) {
8071
+ return emptyPlan;
8072
+ }
8073
+ const filteredArgs = removeRelationsFromArgs(args, toRemove);
8074
+ const { args: finalArgs, injectedKeys } = ensureParentKeysInSelect(
8075
+ filteredArgs,
8076
+ whereInSegments
8077
+ );
8078
+ return {
8079
+ filteredArgs: finalArgs,
8080
+ whereInSegments,
8081
+ injectedParentKeys: injectedKeys
8082
+ };
8083
+ }
8084
+
8085
+ // src/builder/select/array-agg-reducer.ts
8086
+ function buildArrayAggReducerConfig(parentModel, includeSpec, allModels) {
8087
+ const modelMap = new Map(allModels.map((m) => [m.name, m]));
8088
+ const parentJsonSet = getJsonFieldSet(parentModel);
8089
+ const parentScalarFields = getScalarFieldNames(parentModel);
8090
+ const relations = [];
8091
+ for (const [relName, relValue] of Object.entries(includeSpec)) {
8092
+ if (relValue === false) continue;
8093
+ const field = parentModel.fields.find((f) => f.name === relName);
8094
+ if (!field || !field.isRelation || !field.relatedModel) continue;
8095
+ const relModel = modelMap.get(field.relatedModel);
8096
+ if (!relModel) continue;
8097
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
8098
+ const indices = getFieldIndices(relModel);
8099
+ const scalarSel = extractScalarSelection(relValue, relModel);
8100
+ const pkFields = getPrimaryKeyFields(relModel);
8101
+ const relJsonSet = getJsonFieldSet(relModel);
8102
+ const selectedFields = scalarSel.includeAllScalars ? Array.from(indices.scalarFields.keys()) : [.../* @__PURE__ */ new Set([...pkFields, ...scalarSel.selectedScalarFields])];
8103
+ const scalarCols = selectedFields.map((fieldName) => {
8104
+ const f = indices.scalarFields.get(fieldName);
8105
+ if (!f) return null;
8106
+ return {
8107
+ fieldName: f.name,
8108
+ colName: `${relName}.${f.name}`,
8109
+ isJson: relJsonSet.has(f.name)
8110
+ };
8111
+ }).filter(Boolean);
8112
+ relations.push({
8113
+ name: relName,
8114
+ isList,
8115
+ scalarFields: scalarCols,
8116
+ pkFieldName: pkFields[0]
8117
+ });
8118
+ }
8119
+ return {
8120
+ parentModel,
8121
+ parentScalarFields,
8122
+ parentJsonSet,
8123
+ relations
8124
+ };
8125
+ }
8126
+ function reduceArrayAggRows(rows, config) {
8127
+ var _a3;
8128
+ if (rows.length === 0) return [];
8129
+ const { parentScalarFields, parentJsonSet, relations } = config;
8130
+ const results = new Array(rows.length);
8131
+ for (let i = 0; i < rows.length; i++) {
8132
+ const row = rows[i];
8133
+ const record = {};
8134
+ for (const fieldName of parentScalarFields) {
8135
+ if (!(fieldName in row)) continue;
8136
+ record[fieldName] = maybeParseJson(
8137
+ row[fieldName],
8138
+ parentJsonSet,
8139
+ fieldName
7774
8140
  );
7775
- if (segment) {
7776
- whereInSegments.push(segment);
7777
- toRemove.add(rel.name);
8141
+ }
8142
+ for (const rel of relations) {
8143
+ const firstCol = rel.scalarFields[0];
8144
+ if (!firstCol) {
8145
+ record[rel.name] = rel.isList ? [] : null;
8146
+ continue;
7778
8147
  }
7779
- } else {
7780
- const estimated = estimateFlatRows(
7781
- parentCount,
7782
- [{ modelName: model.name, relName: rel.name, field: rel.field }],
7783
- relationStats
7784
- );
7785
- if (estimated > HARD_FANOUT_CAP) {
7786
- const segment = buildWhereInSegment(
7787
- rel.name,
7788
- rel.relArgs,
7789
- rel.field,
7790
- rel.relModel
7791
- );
7792
- if (segment) {
7793
- whereInSegments.push(segment);
7794
- toRemove.add(rel.name);
8148
+ const arr = row[firstCol.colName];
8149
+ if (!Array.isArray(arr) || arr.length === 0) {
8150
+ record[rel.name] = rel.isList ? [] : null;
8151
+ continue;
8152
+ }
8153
+ const len = arr.length;
8154
+ const children = new Array(len);
8155
+ for (let j = 0; j < len; j++) {
8156
+ const child = {};
8157
+ for (const col2 of rel.scalarFields) {
8158
+ const values = row[col2.colName];
8159
+ child[col2.fieldName] = parseJsonIfNeeded(
8160
+ col2.isJson,
8161
+ Array.isArray(values) ? values[j] : null
8162
+ );
7795
8163
  }
8164
+ children[j] = child;
7796
8165
  }
8166
+ record[rel.name] = rel.isList ? children : (_a3 = children[0]) != null ? _a3 : null;
7797
8167
  }
8168
+ results[i] = record;
7798
8169
  }
7799
- if (toRemove.size === 0) {
7800
- return { filteredArgs: args, whereInSegments: [] };
7801
- }
7802
- const filteredArgs = removeRelationsFromArgs(args, toRemove);
7803
- return { filteredArgs, whereInSegments };
8170
+ return results;
7804
8171
  }
7805
8172
 
7806
8173
  // src/builder/shared/where-in-executor-base.ts
8174
+ var MAX_RECURSIVE_DEPTH = 10;
7807
8175
  function getParamLimit(dialect) {
7808
8176
  return dialect === "postgres" ? 32e3 : 900;
7809
8177
  }
@@ -7856,8 +8224,14 @@ function stitchResults(parentRows, segment, childRows, stripFk) {
7856
8224
  }
7857
8225
  }
7858
8226
  }
7859
- function executeSegmentBase(segment, parentRows, allModels, modelMap, dialect, execute) {
8227
+ function executeSingleSegment(segment, parentRows, allModels, modelMap, dialect, execute, depth) {
7860
8228
  return __async(this, null, function* () {
8229
+ if (depth > MAX_RECURSIVE_DEPTH) {
8230
+ for (const parent of parentRows) {
8231
+ parent[segment.relationName] = segment.isList ? [] : null;
8232
+ }
8233
+ return;
8234
+ }
7861
8235
  const parentIds = parentRows.map((r) => r[segment.parentKeyFieldName]).filter((v) => v != null);
7862
8236
  if (parentIds.length === 0) {
7863
8237
  for (const parent of parentRows) {
@@ -7877,23 +8251,41 @@ function executeSegmentBase(segment, parentRows, allModels, modelMap, dialect, e
7877
8251
  }
7878
8252
  const allChildRows = [];
7879
8253
  let needsStripFk = false;
8254
+ let nestedSegments = [];
7880
8255
  for (const chunk of chunks) {
7881
8256
  const childArgs = buildChildArgs(
7882
8257
  segment.relArgs,
7883
8258
  segment.fkFieldName,
7884
8259
  chunk
7885
8260
  );
7886
- const stripFk = ensureFkInSelect(childArgs, segment.fkFieldName);
8261
+ const childPlan = planQueryStrategy({
8262
+ model: childModel,
8263
+ args: childArgs,
8264
+ allModels});
8265
+ if (nestedSegments.length === 0 && childPlan.whereInSegments.length > 0) {
8266
+ nestedSegments = childPlan.whereInSegments;
8267
+ }
8268
+ const stripFk = ensureFkInSelect(
8269
+ childPlan.filteredArgs,
8270
+ segment.fkFieldName
8271
+ );
7887
8272
  if (stripFk) needsStripFk = true;
7888
8273
  const result = buildSQL(
7889
8274
  childModel,
7890
8275
  allModels,
7891
8276
  "findMany",
7892
- childArgs,
8277
+ childPlan.filteredArgs,
7893
8278
  dialect
7894
8279
  );
7895
8280
  let rows = yield execute(result.sql, result.params);
7896
- if (result.requiresReduction && result.includeSpec) {
8281
+ if (result.isArrayAgg && result.includeSpec) {
8282
+ const config = buildArrayAggReducerConfig(
8283
+ childModel,
8284
+ result.includeSpec,
8285
+ allModels
8286
+ );
8287
+ rows = reduceArrayAggRows(rows, config);
8288
+ } else if (result.requiresReduction && result.includeSpec) {
7897
8289
  const config = buildReducerConfig(
7898
8290
  childModel,
7899
8291
  result.includeSpec,
@@ -7905,28 +8297,440 @@ function executeSegmentBase(segment, parentRows, allModels, modelMap, dialect, e
7905
8297
  allChildRows.push(row);
7906
8298
  }
7907
8299
  }
8300
+ if (nestedSegments.length > 0 && allChildRows.length > 0) {
8301
+ for (const row of allChildRows) {
8302
+ for (const nestedSeg of nestedSegments) {
8303
+ row[nestedSeg.relationName] = nestedSeg.isList ? [] : null;
8304
+ }
8305
+ }
8306
+ yield resolveSegmentsIntelligent(
8307
+ nestedSegments,
8308
+ allChildRows,
8309
+ allModels,
8310
+ modelMap,
8311
+ dialect,
8312
+ execute,
8313
+ depth + 1
8314
+ );
8315
+ }
7908
8316
  stitchResults(parentRows, segment, allChildRows, needsStripFk);
7909
8317
  });
7910
8318
  }
8319
+ function resolveSegmentsIntelligent(segments, parentRows, allModels, modelMap, dialect, execute, depth) {
8320
+ return __async(this, null, function* () {
8321
+ if (depth > MAX_RECURSIVE_DEPTH) return;
8322
+ if (segments.length === 0) return;
8323
+ if (segments.length === 1) {
8324
+ yield executeSingleSegment(
8325
+ segments[0],
8326
+ parentRows,
8327
+ allModels,
8328
+ modelMap,
8329
+ dialect,
8330
+ execute,
8331
+ depth
8332
+ );
8333
+ return;
8334
+ }
8335
+ yield Promise.all(
8336
+ segments.map(
8337
+ (seg) => executeSingleSegment(
8338
+ seg,
8339
+ parentRows,
8340
+ allModels,
8341
+ modelMap,
8342
+ dialect,
8343
+ execute,
8344
+ depth
8345
+ )
8346
+ )
8347
+ );
8348
+ });
8349
+ }
8350
+ function executeSegmentBase(segment, parentRows, allModels, modelMap, dialect, execute, depth = 0) {
8351
+ return __async(this, null, function* () {
8352
+ yield executeSingleSegment(
8353
+ segment,
8354
+ parentRows,
8355
+ allModels,
8356
+ modelMap,
8357
+ dialect,
8358
+ execute,
8359
+ depth
8360
+ );
8361
+ });
8362
+ }
7911
8363
 
7912
8364
  // src/builder/where-in-executor.ts
8365
+ var ADAPTIVE_PARENT_THRESHOLD = 15;
8366
+ var ADAPTIVE_DEPTH_THRESHOLD = 2;
8367
+ function measureRelArgsDepth(relArgs) {
8368
+ if (!relArgs || relArgs === true || typeof relArgs !== "object") return 0;
8369
+ const args = relArgs;
8370
+ const nested = args.include || args.select;
8371
+ if (!nested || typeof nested !== "object") return 0;
8372
+ let maxChildDepth = 0;
8373
+ for (const val of Object.values(nested)) {
8374
+ if (val === false) continue;
8375
+ if (val === true) {
8376
+ maxChildDepth = Math.max(maxChildDepth, 1);
8377
+ continue;
8378
+ }
8379
+ if (val && typeof val === "object") {
8380
+ maxChildDepth = Math.max(maxChildDepth, 1 + measureRelArgsDepth(val));
8381
+ }
8382
+ }
8383
+ return maxChildDepth;
8384
+ }
8385
+ function measureSegmentNestingDepth(segments) {
8386
+ let maxDepth = 0;
8387
+ for (const seg of segments) {
8388
+ const depth = 1 + measureRelArgsDepth(seg.relArgs);
8389
+ maxDepth = Math.max(maxDepth, depth);
8390
+ }
8391
+ return maxDepth;
8392
+ }
8393
+ function shouldAdaptivelySwitch(actualParentCount, segments) {
8394
+ if (actualParentCount > ADAPTIVE_PARENT_THRESHOLD) return false;
8395
+ if (segments.length === 0) return false;
8396
+ const depth = measureSegmentNestingDepth(segments);
8397
+ return depth >= ADAPTIVE_DEPTH_THRESHOLD;
8398
+ }
8399
+ function executeCorrelatedFallback(parentRows, parentModel, allModels, dialect, execute, originalArgs, method, segments) {
8400
+ return __async(this, null, function* () {
8401
+ const pkField = getPrimaryKeyField(parentModel);
8402
+ const pks = parentRows.map((r) => r[pkField]).filter(Boolean);
8403
+ if (pks.length === 0) {
8404
+ for (const parent of parentRows) {
8405
+ for (const seg of segments) {
8406
+ parent[seg.relationName] = seg.isList ? [] : null;
8407
+ }
8408
+ }
8409
+ return;
8410
+ }
8411
+ const fallbackArgs = __spreadValues({}, originalArgs);
8412
+ delete fallbackArgs.take;
8413
+ delete fallbackArgs.skip;
8414
+ delete fallbackArgs.cursor;
8415
+ fallbackArgs.where = { [pkField]: { in: pks } };
8416
+ if (originalArgs.orderBy) {
8417
+ fallbackArgs.orderBy = originalArgs.orderBy;
8418
+ }
8419
+ const result = buildSQL(
8420
+ parentModel,
8421
+ allModels,
8422
+ method,
8423
+ fallbackArgs,
8424
+ dialect
8425
+ );
8426
+ let rows = yield execute(result.sql, result.params);
8427
+ if (result.isArrayAgg && result.includeSpec) {
8428
+ const config = buildArrayAggReducerConfig(
8429
+ parentModel,
8430
+ result.includeSpec,
8431
+ allModels
8432
+ );
8433
+ rows = reduceArrayAggRows(rows, config);
8434
+ } else if (result.requiresReduction && result.includeSpec) {
8435
+ const config = buildReducerConfig(
8436
+ parentModel,
8437
+ result.includeSpec,
8438
+ allModels
8439
+ );
8440
+ rows = reduceFlatRows(rows, config);
8441
+ }
8442
+ const rowsByPk = /* @__PURE__ */ new Map();
8443
+ for (const row of rows) {
8444
+ rowsByPk.set(row[pkField], row);
8445
+ }
8446
+ for (const parent of parentRows) {
8447
+ const pk = parent[pkField];
8448
+ const fullRow = rowsByPk.get(pk);
8449
+ if (fullRow) {
8450
+ for (const seg of segments) {
8451
+ parent[seg.relationName] = fullRow[seg.relationName];
8452
+ }
8453
+ } else {
8454
+ for (const seg of segments) {
8455
+ parent[seg.relationName] = seg.isList ? [] : null;
8456
+ }
8457
+ }
8458
+ }
8459
+ });
8460
+ }
7913
8461
  function executeWhereInSegments(params) {
7914
8462
  return __async(this, null, function* () {
7915
- const { segments, parentRows, allModels, modelMap, dialect, execute } = params;
7916
- if (segments.length === 0) return;
7917
- if (parentRows.length === 0) return;
7918
- for (const segment of segments) {
8463
+ const {
8464
+ segments,
8465
+ parentRows,
8466
+ parentModel,
8467
+ allModels,
8468
+ modelMap,
8469
+ dialect,
8470
+ execute,
8471
+ originalArgs,
8472
+ method
8473
+ } = params;
8474
+ if (originalArgs && method && parentModel && shouldAdaptivelySwitch(parentRows.length, segments)) {
8475
+ yield executeCorrelatedFallback(
8476
+ parentRows,
8477
+ parentModel,
8478
+ allModels,
8479
+ dialect,
8480
+ execute,
8481
+ originalArgs,
8482
+ method,
8483
+ segments
8484
+ );
8485
+ return;
8486
+ }
8487
+ if (segments.length === 1) {
7919
8488
  yield executeSegmentBase(
7920
- segment,
8489
+ segments[0],
8490
+ parentRows,
8491
+ allModels,
8492
+ modelMap,
8493
+ dialect,
8494
+ execute,
8495
+ 0
8496
+ );
8497
+ return;
8498
+ }
8499
+ yield Promise.all(
8500
+ segments.map(
8501
+ (segment) => executeSegmentBase(
8502
+ segment,
8503
+ parentRows,
8504
+ allModels,
8505
+ modelMap,
8506
+ dialect,
8507
+ execute,
8508
+ 0
8509
+ )
8510
+ )
8511
+ );
8512
+ });
8513
+ }
8514
+
8515
+ // src/builder/select/streaming-where-in-executor.ts
8516
+ var MAX_RECURSIVE_DEPTH2 = 10;
8517
+ function buildParentKeyIndex(parentRows, parentKeyFieldName) {
8518
+ const index = /* @__PURE__ */ new Map();
8519
+ for (const parent of parentRows) {
8520
+ const keyVal = parent[parentKeyFieldName];
8521
+ if (keyVal == null) continue;
8522
+ let arr = index.get(keyVal);
8523
+ if (!arr) {
8524
+ arr = [];
8525
+ index.set(keyVal, arr);
8526
+ }
8527
+ arr.push(parent);
8528
+ }
8529
+ return index;
8530
+ }
8531
+ function stitchChildrenToParents(children, segment, parentKeyIndex) {
8532
+ for (const child of children) {
8533
+ const childKey = child[segment.fkFieldName];
8534
+ const matchingParents = parentKeyIndex.get(childKey);
8535
+ if (!matchingParents) continue;
8536
+ for (const parent of matchingParents) {
8537
+ if (segment.isList) {
8538
+ if (!Array.isArray(parent[segment.relationName])) {
8539
+ parent[segment.relationName] = [];
8540
+ }
8541
+ parent[segment.relationName].push(child);
8542
+ } else {
8543
+ parent[segment.relationName] = child;
8544
+ }
8545
+ }
8546
+ }
8547
+ }
8548
+ function ensureFkInSelect2(childArgs, fkFieldName) {
8549
+ if (!childArgs.select) return false;
8550
+ if (childArgs.select[fkFieldName]) return false;
8551
+ childArgs.select = __spreadProps(__spreadValues({}, childArgs.select), { [fkFieldName]: true });
8552
+ return true;
8553
+ }
8554
+ function executeWhereInSegmentsStreaming(params) {
8555
+ return __async(this, null, function* () {
8556
+ const {
8557
+ segments,
8558
+ parentSql,
8559
+ parentParams,
8560
+ parentModel,
8561
+ allModels,
8562
+ modelMap,
8563
+ dialect,
8564
+ execute
8565
+ } = params;
8566
+ if (segments.length === 0) {
8567
+ throw new Error("executeWhereInSegmentsStreaming requires segments");
8568
+ }
8569
+ if (dialect !== "postgres") {
8570
+ throw new Error("Streaming WHERE IN requires postgres dialect");
8571
+ }
8572
+ const parentRows = yield execute(parentSql, parentParams);
8573
+ if (parentRows.length === 0) return [];
8574
+ for (const row of parentRows) {
8575
+ for (const seg of segments) {
8576
+ row[seg.relationName] = seg.isList ? [] : null;
8577
+ }
8578
+ }
8579
+ yield resolveSegments(
8580
+ segments,
8581
+ parentRows,
8582
+ allModels,
8583
+ modelMap,
8584
+ dialect,
8585
+ execute,
8586
+ 0
8587
+ );
8588
+ return parentRows;
8589
+ });
8590
+ }
8591
+ function executeWithPreFetchedParents(params) {
8592
+ return __async(this, null, function* () {
8593
+ const {
8594
+ segments,
8595
+ parentRows,
8596
+ parentModel,
8597
+ allModels,
8598
+ modelMap,
8599
+ dialect,
8600
+ execute
8601
+ } = params;
8602
+ if (segments.length === 0) return parentRows;
8603
+ if (parentRows.length === 0) return [];
8604
+ for (const row of parentRows) {
8605
+ for (const seg of segments) {
8606
+ row[seg.relationName] = seg.isList ? [] : null;
8607
+ }
8608
+ }
8609
+ yield resolveSegments(
8610
+ segments,
8611
+ parentRows,
8612
+ allModels,
8613
+ modelMap,
8614
+ dialect,
8615
+ execute,
8616
+ 0
8617
+ );
8618
+ return parentRows;
8619
+ });
8620
+ }
8621
+ function resolveSegments(segments, parentRows, allModels, modelMap, dialect, execute, depth) {
8622
+ return __async(this, null, function* () {
8623
+ if (depth > MAX_RECURSIVE_DEPTH2) return;
8624
+ if (segments.length === 0) return;
8625
+ if (segments.length === 1) {
8626
+ yield resolveSingleSegment(
8627
+ segments[0],
7921
8628
  parentRows,
7922
8629
  allModels,
7923
8630
  modelMap,
7924
8631
  dialect,
7925
- execute
8632
+ execute,
8633
+ depth
8634
+ );
8635
+ return;
8636
+ }
8637
+ yield Promise.all(
8638
+ segments.map(
8639
+ (seg) => resolveSingleSegment(
8640
+ seg,
8641
+ parentRows,
8642
+ allModels,
8643
+ modelMap,
8644
+ dialect,
8645
+ execute,
8646
+ depth
8647
+ )
8648
+ )
8649
+ );
8650
+ });
8651
+ }
8652
+ function resolveSingleSegment(segment, parentRows, allModels, modelMap, dialect, execute, depth) {
8653
+ return __async(this, null, function* () {
8654
+ const childModel = modelMap.get(segment.childModelName);
8655
+ if (!childModel) {
8656
+ return;
8657
+ }
8658
+ const parentIds = parentRows.map((r) => r[segment.parentKeyFieldName]).filter((v) => v != null);
8659
+ if (parentIds.length === 0) {
8660
+ return;
8661
+ }
8662
+ const uniqueIds = [...new Set(parentIds)];
8663
+ const childArgs = buildChildArgs2(
8664
+ segment.relArgs,
8665
+ segment.fkFieldName,
8666
+ uniqueIds
8667
+ );
8668
+ const needsStripFk = ensureFkInSelect2(childArgs, segment.fkFieldName);
8669
+ const childPlan = planQueryStrategy({
8670
+ model: childModel,
8671
+ args: childArgs,
8672
+ allModels});
8673
+ const result = buildSQL(
8674
+ childModel,
8675
+ allModels,
8676
+ "findMany",
8677
+ childPlan.filteredArgs,
8678
+ dialect
8679
+ );
8680
+ let children = yield execute(result.sql, result.params);
8681
+ if (result.isArrayAgg && result.includeSpec) {
8682
+ const config = buildArrayAggReducerConfig(
8683
+ childModel,
8684
+ result.includeSpec,
8685
+ allModels
8686
+ );
8687
+ children = reduceArrayAggRows(children, config);
8688
+ } else if (result.requiresReduction && result.includeSpec) {
8689
+ const config = buildReducerConfig(childModel, result.includeSpec, allModels);
8690
+ children = reduceFlatRows(children, config);
8691
+ }
8692
+ if (childPlan.whereInSegments.length > 0 && children.length > 0) {
8693
+ for (const child of children) {
8694
+ for (const nestedSeg of childPlan.whereInSegments) {
8695
+ child[nestedSeg.relationName] = nestedSeg.isList ? [] : null;
8696
+ }
8697
+ }
8698
+ yield resolveSegments(
8699
+ childPlan.whereInSegments,
8700
+ children,
8701
+ allModels,
8702
+ modelMap,
8703
+ dialect,
8704
+ execute,
8705
+ depth + 1
7926
8706
  );
8707
+ if (childPlan.injectedParentKeys.length > 0) {
8708
+ for (const child of children) {
8709
+ for (const key of childPlan.injectedParentKeys) {
8710
+ delete child[key];
8711
+ }
8712
+ }
8713
+ }
8714
+ }
8715
+ const parentKeyIndex = buildParentKeyIndex(
8716
+ parentRows,
8717
+ segment.parentKeyFieldName
8718
+ );
8719
+ stitchChildrenToParents(children, segment, parentKeyIndex);
8720
+ if (needsStripFk) {
8721
+ for (const child of children) {
8722
+ delete child[segment.fkFieldName];
8723
+ }
7927
8724
  }
7928
8725
  });
7929
8726
  }
8727
+ function buildChildArgs2(relArgs, fkFieldName, parentIds) {
8728
+ const base = relArgs === true || typeof relArgs !== "object" || relArgs === null ? {} : __spreadValues({}, relArgs);
8729
+ const existingWhere = base.where;
8730
+ const inCondition = { [fkFieldName]: { in: parentIds } };
8731
+ base.where = existingWhere ? { AND: [existingWhere, inCondition] } : inCondition;
8732
+ return base;
8733
+ }
7930
8734
 
7931
8735
  // src/builder/select/core-reducer.ts
7932
8736
  var getOrCreateRelationMap = (relationMaps, parent) => {
@@ -7969,10 +8773,6 @@ var createChildObject = (row, rel) => {
7969
8773
  }
7970
8774
  return child;
7971
8775
  };
7972
- var extractChildKey = (row, rel) => {
7973
- const cols = rel.primaryKeyFields.map((f) => `${rel.path}.${f}`);
7974
- return buildCompositeKey(row, cols);
7975
- };
7976
8776
  var attachChildToParent = (parent, child, rel) => {
7977
8777
  if (rel.cardinality === "many") {
7978
8778
  parent[rel.name].push(child);
@@ -7980,17 +8780,25 @@ var attachChildToParent = (parent, child, rel) => {
7980
8780
  parent[rel.name] = child;
7981
8781
  }
7982
8782
  };
8783
+ function prepareRelations(relations) {
8784
+ return relations.map((rel) => ({
8785
+ rel,
8786
+ prefixedPkFields: rel.primaryKeyFields.map((f) => `${rel.path}.${f}`),
8787
+ nested: rel.nestedIncludes ? prepareRelations(rel.nestedIncludes.includedRelations) : null
8788
+ }));
8789
+ }
7983
8790
  var createRelationProcessor = (relationMaps) => {
7984
- const processRelation2 = (parent, rel, row) => {
7985
- const childKey = extractChildKey(row, rel);
7986
- if (!childKey) return;
8791
+ const processRelation2 = (parent, prepared, row) => {
8792
+ const { rel, prefixedPkFields, nested } = prepared;
8793
+ const childKey = buildKey(row, prefixedPkFields);
8794
+ if (childKey == null) return;
7987
8795
  const relMap = getOrCreateRelationMap(relationMaps, parent);
7988
8796
  const childMap = getOrCreateChildMap(relMap, rel.path);
7989
8797
  if (childMap.has(childKey)) {
7990
- const existing = childMap.get(childKey);
7991
- if (rel.nestedIncludes) {
7992
- for (const nested of rel.nestedIncludes.includedRelations) {
7993
- processRelation2(existing, nested, row);
8798
+ if (nested) {
8799
+ const existing = childMap.get(childKey);
8800
+ for (const nestedPrepared of nested) {
8801
+ processRelation2(existing, nestedPrepared, row);
7994
8802
  }
7995
8803
  }
7996
8804
  return;
@@ -7998,9 +8806,9 @@ var createRelationProcessor = (relationMaps) => {
7998
8806
  const child = createChildObject(row, rel);
7999
8807
  childMap.set(childKey, child);
8000
8808
  attachChildToParent(parent, child, rel);
8001
- if (rel.nestedIncludes) {
8002
- for (const nested of rel.nestedIncludes.includedRelations) {
8003
- processRelation2(child, nested, row);
8809
+ if (nested) {
8810
+ for (const nestedPrepared of nested) {
8811
+ processRelation2(child, nestedPrepared, row);
8004
8812
  }
8005
8813
  }
8006
8814
  };
@@ -8013,31 +8821,28 @@ var createCoreReducer = (config) => {
8013
8821
  const jsonSet = getJsonFieldSet(config.parentModel);
8014
8822
  const parentPkFields = getPrimaryKeyFields(config.parentModel);
8015
8823
  const includedRelations = config.includedRelations;
8016
- const extractParentKey = (row) => buildCompositeKey(row, parentPkFields);
8824
+ const preparedRelations = prepareRelations(includedRelations);
8017
8825
  const processRelation2 = createRelationProcessor(relationMaps);
8018
8826
  const processRow = (row) => {
8019
- const parentKey = extractParentKey(row);
8020
- if (!parentKey) return null;
8021
- const parent = parentMap.has(parentKey) ? parentMap.get(parentKey) : (() => {
8022
- const newParent = createParentObject(
8023
- row,
8024
- scalarFields,
8025
- jsonSet,
8026
- includedRelations
8027
- );
8028
- parentMap.set(parentKey, newParent);
8029
- return newParent;
8030
- })();
8031
- for (const rel of includedRelations) {
8032
- processRelation2(parent, rel, row);
8827
+ const parentKey = buildKey(row, parentPkFields);
8828
+ if (parentKey == null) return null;
8829
+ let parent;
8830
+ if (parentMap.has(parentKey)) {
8831
+ parent = parentMap.get(parentKey);
8832
+ } else {
8833
+ parent = createParentObject(row, scalarFields, jsonSet, includedRelations);
8834
+ parentMap.set(parentKey, parent);
8835
+ }
8836
+ for (const prepared of preparedRelations) {
8837
+ processRelation2(parent, prepared, row);
8033
8838
  }
8034
8839
  return parentKey;
8035
8840
  };
8036
8841
  return {
8037
8842
  processRow,
8038
8843
  getParent: (key) => {
8039
- var _a;
8040
- return (_a = parentMap.get(key)) != null ? _a : null;
8844
+ var _a3;
8845
+ return (_a3 = parentMap.get(key)) != null ? _a3 : null;
8041
8846
  },
8042
8847
  getAllParents: () => Array.from(parentMap.values()),
8043
8848
  getParentMap: () => parentMap
@@ -8097,135 +8902,9 @@ function createProgressiveReducer(config) {
8097
8902
  };
8098
8903
  }
8099
8904
 
8100
- // src/builder/select/streaming-where-in-executor.ts
8101
- function executeWhereInSegmentsStreaming(params) {
8102
- return __async(this, null, function* () {
8103
- const {
8104
- segments,
8105
- parentSql,
8106
- parentParams,
8107
- parentModel,
8108
- allModels,
8109
- modelMap,
8110
- dialect,
8111
- execute,
8112
- batchSize = 100,
8113
- maxConcurrency = 10
8114
- } = params;
8115
- if (segments.length === 0) {
8116
- throw new Error("executeWhereInSegmentsStreaming requires segments");
8117
- }
8118
- if (dialect !== "postgres") {
8119
- throw new Error("Streaming WHERE IN requires postgres dialect");
8120
- }
8121
- const parentMap = /* @__PURE__ */ new Map();
8122
- const batches = /* @__PURE__ */ new Map();
8123
- const inFlightMap = /* @__PURE__ */ new Map();
8124
- for (const seg of segments) {
8125
- batches.set(seg.relationName, []);
8126
- }
8127
- const pkField = getPrimaryKeyField(parentModel);
8128
- const parentRows = yield execute(parentSql, parentParams);
8129
- for (const row of parentRows) {
8130
- const pk = row[pkField];
8131
- parentMap.set(pk, __spreadValues({}, row));
8132
- for (const seg of segments) {
8133
- row[seg.relationName] = seg.isList ? [] : null;
8134
- }
8135
- for (const seg of segments) {
8136
- const batch = batches.get(seg.relationName);
8137
- const parentKey = row[seg.parentKeyFieldName];
8138
- batch.push(parentKey);
8139
- if (batch.length >= batchSize) {
8140
- const idsToFetch = [...batch];
8141
- batch.length = 0;
8142
- const promise = fetchAndAttachChildren(
8143
- seg,
8144
- idsToFetch,
8145
- parentMap,
8146
- allModels,
8147
- modelMap,
8148
- dialect,
8149
- execute
8150
- );
8151
- inFlightMap.set(promise, seg.relationName);
8152
- promise.finally(() => {
8153
- inFlightMap.delete(promise);
8154
- });
8155
- if (inFlightMap.size >= maxConcurrency) {
8156
- yield Promise.race(inFlightMap.keys());
8157
- }
8158
- }
8159
- }
8160
- }
8161
- for (const seg of segments) {
8162
- const batch = batches.get(seg.relationName);
8163
- if (batch.length > 0) {
8164
- const promise = fetchAndAttachChildren(
8165
- seg,
8166
- batch,
8167
- parentMap,
8168
- allModels,
8169
- modelMap,
8170
- dialect,
8171
- execute
8172
- );
8173
- inFlightMap.set(promise, seg.relationName);
8174
- promise.finally(() => {
8175
- inFlightMap.delete(promise);
8176
- });
8177
- }
8178
- }
8179
- yield Promise.all(inFlightMap.keys());
8180
- return Array.from(parentMap.values());
8181
- });
8182
- }
8183
- function fetchAndAttachChildren(segment, parentIds, parentMap, allModels, modelMap, dialect, execute) {
8184
- return __async(this, null, function* () {
8185
- const childModel = modelMap.get(segment.childModelName);
8186
- if (!childModel) return;
8187
- const childArgs = buildChildArgs2(
8188
- segment.relArgs,
8189
- segment.fkFieldName,
8190
- parentIds
8191
- );
8192
- const result = buildSQL(
8193
- childModel,
8194
- allModels,
8195
- "findMany",
8196
- childArgs,
8197
- dialect
8198
- );
8199
- let children = yield execute(result.sql, result.params);
8200
- if (result.requiresReduction && result.includeSpec) {
8201
- const config = buildReducerConfig(childModel, result.includeSpec, allModels);
8202
- children = reduceFlatRows(children, config);
8203
- }
8204
- for (const child of children) {
8205
- const fkValue = child[segment.fkFieldName];
8206
- const parent = parentMap.get(fkValue);
8207
- if (!parent) continue;
8208
- if (segment.isList) {
8209
- if (!Array.isArray(parent[segment.relationName])) {
8210
- parent[segment.relationName] = [];
8211
- }
8212
- parent[segment.relationName].push(child);
8213
- } else {
8214
- parent[segment.relationName] = child;
8215
- }
8216
- }
8217
- });
8218
- }
8219
- function buildChildArgs2(relArgs, fkFieldName, parentIds) {
8220
- const base = relArgs === true || typeof relArgs !== "object" || relArgs === null ? {} : __spreadValues({}, relArgs);
8221
- const existingWhere = base.where;
8222
- const inCondition = { [fkFieldName]: { in: parentIds } };
8223
- base.where = existingWhere ? { AND: [existingWhere, inCondition] } : inCondition;
8224
- return base;
8225
- }
8226
-
8227
8905
  // src/generated-runtime.ts
8228
8906
  var SQLITE_STMT_CACHE = /* @__PURE__ */ new WeakMap();
8907
+ var STMT_CACHE_LIMIT = 1e3;
8229
8908
  function getOrPrepareStatement(client, sql) {
8230
8909
  let cache = SQLITE_STMT_CACHE.get(client);
8231
8910
  if (!cache) {
@@ -8233,13 +8912,16 @@ function getOrPrepareStatement(client, sql) {
8233
8912
  SQLITE_STMT_CACHE.set(client, cache);
8234
8913
  }
8235
8914
  let stmt = cache.get(sql);
8236
- if (!stmt) {
8237
- stmt = client.prepare(sql);
8915
+ if (stmt) {
8916
+ cache.delete(sql);
8238
8917
  cache.set(sql, stmt);
8239
- if (cache.size > 1e3) {
8240
- const firstKey = cache.keys().next().value;
8241
- cache.delete(firstKey);
8242
- }
8918
+ return stmt;
8919
+ }
8920
+ stmt = client.prepare(sql);
8921
+ cache.set(sql, stmt);
8922
+ if (cache.size > STMT_CACHE_LIMIT) {
8923
+ const firstKey = cache.keys().next().value;
8924
+ cache.delete(firstKey);
8243
8925
  }
8244
8926
  return stmt;
8245
8927
  }
@@ -8249,22 +8931,44 @@ function shouldSqliteUseGet(method) {
8249
8931
  function normalizeParams(params) {
8250
8932
  return params.map((p) => normalizeValue(p));
8251
8933
  }
8252
- function executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, allModels) {
8934
+ function executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, allModels, isArrayAgg) {
8253
8935
  return __async(this, null, function* () {
8254
8936
  const normalizedParams = normalizeParams(params);
8255
- const rowTransformer = getRowTransformer(method);
8937
+ if (isArrayAgg && includeSpec) {
8938
+ const config = buildArrayAggReducerConfig(model, includeSpec, allModels);
8939
+ const results2 = [];
8940
+ yield client.unsafe(sql, normalizedParams).forEach((row) => {
8941
+ results2.push(row);
8942
+ });
8943
+ return reduceArrayAggRows(results2, config);
8944
+ }
8256
8945
  if (requiresReduction && includeSpec) {
8257
8946
  const config = buildReducerConfig(model, includeSpec, allModels);
8258
8947
  const reducer = createStreamingReducer(config);
8259
8948
  yield client.unsafe(sql, normalizedParams).forEach((row) => {
8260
- reducer.processRow(rowTransformer ? rowTransformer(row) : row);
8949
+ reducer.processRow(row);
8261
8950
  });
8262
8951
  return reducer.getResults();
8263
8952
  }
8953
+ const needsTransform = method === "groupBy" || method === "aggregate" || method === "count";
8954
+ if (!needsTransform) {
8955
+ const results2 = [];
8956
+ yield client.unsafe(sql, normalizedParams).forEach((row) => {
8957
+ results2.push(row);
8958
+ });
8959
+ return results2;
8960
+ }
8961
+ const rowTransformer = getRowTransformer(method);
8264
8962
  const results = [];
8265
- yield client.unsafe(sql, normalizedParams).forEach((row) => {
8266
- results.push(rowTransformer ? rowTransformer(row) : row);
8267
- });
8963
+ if (rowTransformer) {
8964
+ yield client.unsafe(sql, normalizedParams).forEach((row) => {
8965
+ results.push(rowTransformer(row));
8966
+ });
8967
+ } else {
8968
+ yield client.unsafe(sql, normalizedParams).forEach((row) => {
8969
+ results.push(row);
8970
+ });
8971
+ }
8268
8972
  return results;
8269
8973
  });
8270
8974
  }
@@ -8398,6 +9102,7 @@ function generateSQLByModel(directives) {
8398
9102
  return byModel;
8399
9103
  }
8400
9104
 
9105
+ exports.buildArrayAggReducerConfig = buildArrayAggReducerConfig;
8401
9106
  exports.buildBatchCountSql = buildBatchCountSql;
8402
9107
  exports.buildBatchSql = buildBatchSql;
8403
9108
  exports.buildReducerConfig = buildReducerConfig;
@@ -8412,17 +9117,20 @@ exports.executeRaw = executeRaw;
8412
9117
  exports.executeSqliteQuery = executeSqliteQuery;
8413
9118
  exports.executeWhereInSegments = executeWhereInSegments;
8414
9119
  exports.executeWhereInSegmentsStreaming = executeWhereInSegmentsStreaming;
9120
+ exports.executeWithPreFetchedParents = executeWithPreFetchedParents;
8415
9121
  exports.extractCountValue = extractCountValue;
8416
9122
  exports.generateAllSQL = generateAllSQL;
8417
9123
  exports.generateSQL = generateSQL2;
8418
9124
  exports.generateSQLByModel = generateSQLByModel;
8419
9125
  exports.getOrPrepareStatement = getOrPrepareStatement;
9126
+ exports.getPrimaryKeyField = getPrimaryKeyField;
8420
9127
  exports.getRowTransformer = getRowTransformer;
8421
9128
  exports.normalizeParams = normalizeParams;
8422
9129
  exports.normalizeValue = normalizeValue;
8423
9130
  exports.parseBatchCountResults = parseBatchCountResults;
8424
9131
  exports.parseBatchResults = parseBatchResults;
8425
9132
  exports.planQueryStrategy = planQueryStrategy;
9133
+ exports.reduceArrayAggRows = reduceArrayAggRows;
8426
9134
  exports.reduceFlatRows = reduceFlatRows;
8427
9135
  exports.shouldSqliteUseGet = shouldSqliteUseGet;
8428
9136
  exports.transformAggregateRow = transformAggregateRow;