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