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.
@@ -2323,7 +2323,7 @@ var require_package = __commonJS({
2323
2323
  "package.json"(exports$1, module) {
2324
2324
  module.exports = {
2325
2325
  name: "prisma-sql",
2326
- version: "1.67.0",
2326
+ version: "1.68.0",
2327
2327
  description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
2328
2328
  main: "dist/index.cjs",
2329
2329
  module: "dist/index.js",
@@ -2804,6 +2804,8 @@ var LIMITS = Object.freeze({
2804
2804
  MAX_STRING_LENGTH: 1e4,
2805
2805
  MAX_HAVING_DEPTH: 50
2806
2806
  });
2807
+ var _a;
2808
+ var DEBUG_PARAMS = typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.DEBUG_PARAMS) === "1";
2807
2809
 
2808
2810
  // src/builder/shared/validators/type-guards.ts
2809
2811
  function isNotNullish(value) {
@@ -3347,7 +3349,7 @@ function normalizeField(field) {
3347
3349
  return field;
3348
3350
  }
3349
3351
  function getFieldIndices(model) {
3350
- var _a;
3352
+ var _a3;
3351
3353
  let cached = FIELD_INDICES_CACHE.get(model);
3352
3354
  if (cached) return cached;
3353
3355
  const scalarFields = /* @__PURE__ */ new Map();
@@ -3366,7 +3368,7 @@ function getFieldIndices(model) {
3366
3368
  } else {
3367
3369
  scalarFields.set(field.name, field);
3368
3370
  scalarNames.push(field.name);
3369
- const fieldType = String((_a = field.type) != null ? _a : "").toLowerCase();
3371
+ const fieldType = String((_a3 = field.type) != null ? _a3 : "").toLowerCase();
3370
3372
  if (fieldType === "json") {
3371
3373
  jsonFields.add(field.name);
3372
3374
  }
@@ -3464,13 +3466,13 @@ function getModelByName(schemas, name) {
3464
3466
  return schemas.find((m) => m.name === name);
3465
3467
  }
3466
3468
  function normalizeIntLike(name, v, opts = {}) {
3467
- var _a, _b;
3469
+ var _a3, _b;
3468
3470
  if (!isNotNullish(v)) return void 0;
3469
3471
  if (schemaParser.isDynamicParameter(v)) return v;
3470
3472
  if (typeof v !== "number" || !Number.isFinite(v) || !Number.isInteger(v)) {
3471
3473
  throw new Error(`${name} must be an integer`);
3472
3474
  }
3473
- const min = (_a = opts.min) != null ? _a : 0;
3475
+ const min = (_a3 = opts.min) != null ? _a3 : 0;
3474
3476
  const allowZero = (_b = opts.allowZero) != null ? _b : true;
3475
3477
  if (!allowZero && v === 0) {
3476
3478
  throw new Error(`${name} must be > 0`);
@@ -3492,7 +3494,9 @@ function scopeName(scope, dynamicName) {
3492
3494
  function addAutoScoped(params, value, scope) {
3493
3495
  if (schemaParser.isDynamicParameter(value)) {
3494
3496
  const dn = schemaParser.extractDynamicName(value);
3495
- console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
3497
+ if (DEBUG_PARAMS) {
3498
+ console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
3499
+ }
3496
3500
  return params.add(void 0, scopeName(scope, dn));
3497
3501
  }
3498
3502
  return params.add(value);
@@ -3933,7 +3937,7 @@ function assertCursorAndOrderFieldsScalar(model, cursor, orderEntries) {
3933
3937
  }
3934
3938
  }
3935
3939
  function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
3936
- var _a;
3940
+ var _a3;
3937
3941
  assertSafeTableRef(tableName);
3938
3942
  assertSafeAlias(alias);
3939
3943
  const d = dialect != null ? dialect : getGlobalDialect();
@@ -3948,6 +3952,33 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
3948
3952
  }
3949
3953
  if (cursorEntries.length === 0)
3950
3954
  throw new Error("cursor must have at least one field with defined value");
3955
+ const orderEntries = normalizeAndValidateOrderBy(
3956
+ orderBy,
3957
+ model,
3958
+ parseOrderByValue
3959
+ );
3960
+ if (cursorEntries.length === 1 && orderEntries.length === 0) {
3961
+ const [field, value] = cursorEntries[0];
3962
+ const ph = addAutoScoped(params, value, `cursor.${field}`);
3963
+ const c = col(alias, field, model);
3964
+ return {
3965
+ cte: "",
3966
+ condition: `${c} >= ${ph}`
3967
+ };
3968
+ }
3969
+ if (cursorEntries.length === 1 && orderEntries.length === 1) {
3970
+ const [cursorField, cursorValue] = cursorEntries[0];
3971
+ const orderEntry = orderEntries[0];
3972
+ if (orderEntry.field === cursorField) {
3973
+ const ph = addAutoScoped(params, cursorValue, `cursor.${cursorField}`);
3974
+ const c = col(alias, cursorField, model);
3975
+ const op = orderEntry.direction === "asc" ? ">=" : "<=";
3976
+ return {
3977
+ cte: "",
3978
+ condition: `${c} ${op} ${ph}`
3979
+ };
3980
+ }
3981
+ }
3951
3982
  const { cteName, srcAlias } = buildCursorNames(alias);
3952
3983
  assertSafeAlias(cteName);
3953
3984
  assertSafeAlias(srcAlias);
@@ -3956,49 +3987,52 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
3956
3987
  model,
3957
3988
  parseValue: parseOrderByValue
3958
3989
  });
3959
- let orderEntries = normalizeAndValidateOrderBy(
3990
+ let finalOrderEntries = normalizeAndValidateOrderBy(
3960
3991
  orderBy,
3961
3992
  model,
3962
3993
  parseOrderByValue
3963
3994
  );
3964
- if (orderEntries.length === 0) {
3965
- orderEntries = cursorEntries.map(([field]) => ({
3995
+ if (finalOrderEntries.length === 0) {
3996
+ finalOrderEntries = cursorEntries.map(([field]) => ({
3966
3997
  field,
3967
3998
  direction: "asc"
3968
3999
  }));
3969
4000
  } else {
3970
- orderEntries = ensureCursorFieldsInOrder(orderEntries, cursorEntries);
4001
+ finalOrderEntries = ensureCursorFieldsInOrder(
4002
+ finalOrderEntries,
4003
+ cursorEntries
4004
+ );
3971
4005
  }
3972
- assertCursorAndOrderFieldsScalar(model, cursor, orderEntries);
4006
+ assertCursorAndOrderFieldsScalar(model, cursor, finalOrderEntries);
3973
4007
  const { whereSql: cursorWhereSql } = buildCursorFilterParts(
3974
4008
  cursor,
3975
4009
  srcAlias,
3976
4010
  params,
3977
4011
  model
3978
4012
  );
3979
- const cursorOrderBy = orderEntries.map(
4013
+ const cursorOrderBy = finalOrderEntries.map(
3980
4014
  (e) => srcAlias + "." + quoteColumn(model, e.field) + " " + e.direction.toUpperCase()
3981
4015
  ).join(", ");
3982
4016
  const selectList = buildCursorCteSelectList(
3983
4017
  cursorEntries,
3984
- orderEntries,
4018
+ finalOrderEntries,
3985
4019
  model
3986
4020
  );
3987
4021
  const cte = cteName + " AS (\n SELECT " + selectList + " FROM " + tableName + " " + srcAlias + "\n WHERE " + cursorWhereSql + "\n ORDER BY " + cursorOrderBy + "\n LIMIT 1\n )";
3988
4022
  const existsExpr = "EXISTS (SELECT 1 FROM " + cteName + ")";
3989
4023
  const orClauses = [];
3990
- for (let level = 0; level < orderEntries.length; level++) {
4024
+ for (let level = 0; level < finalOrderEntries.length; level++) {
3991
4025
  const andParts = [];
3992
4026
  for (let i = 0; i < level; i++) {
3993
- const e2 = orderEntries[i];
4027
+ const e2 = finalOrderEntries[i];
3994
4028
  const c2 = col(alias, e2.field, model);
3995
4029
  const cursorField2 = cteName + "." + quoteColumn(model, e2.field);
3996
4030
  andParts.push(buildCursorEqualityExpr(c2, cursorField2));
3997
4031
  }
3998
- const e = orderEntries[level];
4032
+ const e = finalOrderEntries[level];
3999
4033
  const c = col(alias, e.field, model);
4000
4034
  const cursorField = cteName + "." + quoteColumn(model, e.field);
4001
- const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
4035
+ const nulls = (_a3 = e.nulls) != null ? _a3 : defaultNullsFor(d, e.direction);
4002
4036
  andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, cursorField));
4003
4037
  orClauses.push("(" + andParts.join(SQL_SEPARATORS.CONDITION_AND) + ")");
4004
4038
  }
@@ -4544,6 +4578,16 @@ function handleJsonWildcard(expr, op, val, params, wildcards, dialect) {
4544
4578
 
4545
4579
  // src/builder/where/relations.ts
4546
4580
  var NO_JOINS = [];
4581
+ var SCHEMA_MAP_CACHE = /* @__PURE__ */ new WeakMap();
4582
+ function getSchemaByName(schemas) {
4583
+ let map = SCHEMA_MAP_CACHE.get(schemas);
4584
+ if (!map) {
4585
+ map = /* @__PURE__ */ new Map();
4586
+ for (const m of schemas) map.set(m.name, m);
4587
+ SCHEMA_MAP_CACHE.set(schemas, map);
4588
+ }
4589
+ return map;
4590
+ }
4547
4591
  function isListRelation(fieldType) {
4548
4592
  return typeof fieldType === "string" && fieldType.endsWith("[]");
4549
4593
  }
@@ -4743,7 +4787,8 @@ function buildRelation(fieldName, value, ctx, whereBuilder) {
4743
4787
  modelName: ctx.model.name
4744
4788
  });
4745
4789
  }
4746
- const relModel = ctx.schemaModels.find((m) => m.name === field.relatedModel);
4790
+ const schemaMap = getSchemaByName(ctx.schemaModels);
4791
+ const relModel = schemaMap.get(field.relatedModel);
4747
4792
  if (!isNotNullish(relModel)) {
4748
4793
  throw createError(
4749
4794
  `Related model '${field.relatedModel}' not found in schema. Available models: ${ctx.schemaModels.map((m) => m.name).join(", ")}`,
@@ -5074,6 +5119,8 @@ function createAliasGenerator(maxAliases = 1e4) {
5074
5119
  };
5075
5120
  }
5076
5121
  var MAX_PARAM_INDEX = Number.MAX_SAFE_INTEGER - 1e3;
5122
+ var _a2;
5123
+ var IS_PRODUCTION2 = typeof process !== "undefined" && ((_a2 = process.env) == null ? void 0 : _a2.NODE_ENV) === "production";
5077
5124
  function assertSameLength(params, mappings) {
5078
5125
  if (params.length !== mappings.length) {
5079
5126
  throw new Error(
@@ -5133,6 +5180,11 @@ function validateMappings(mappings) {
5133
5180
  }
5134
5181
  }
5135
5182
  function validateState(params, mappings, index) {
5183
+ if (IS_PRODUCTION2) {
5184
+ assertSameLength(params, mappings);
5185
+ assertValidNextIndex(index);
5186
+ return;
5187
+ }
5136
5188
  assertSameLength(params, mappings);
5137
5189
  assertValidNextIndex(index);
5138
5190
  if (mappings.length === 0) return;
@@ -5287,10 +5339,10 @@ function toPublicResult(clause, joins, params) {
5287
5339
 
5288
5340
  // src/builder/where.ts
5289
5341
  function buildWhereClause(where, options) {
5290
- var _a, _b, _c, _d, _e;
5342
+ var _a3, _b, _c, _d, _e;
5291
5343
  assertSafeAlias(options.alias);
5292
5344
  const dialect = options.dialect || getGlobalDialect();
5293
- const params = (_a = options.params) != null ? _a : createParamStore(1, dialect);
5345
+ const params = (_a3 = options.params) != null ? _a3 : createParamStore(1, dialect);
5294
5346
  const ctx = {
5295
5347
  alias: options.alias,
5296
5348
  model: options.model,
@@ -5349,8 +5401,8 @@ function buildDefaultScalarFields(model, alias) {
5349
5401
  return out;
5350
5402
  }
5351
5403
  function getDefaultSelectCached(model, alias) {
5352
- var _a;
5353
- return (_a = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a.get(alias);
5404
+ var _a3;
5405
+ return (_a3 = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a3.get(alias);
5354
5406
  }
5355
5407
  function cacheDefaultSelect(model, alias, sql) {
5356
5408
  let cache = DEFAULT_SELECT_CACHE.get(model);
@@ -5447,7 +5499,8 @@ function buildRelationSelect(relArgs, relModel, relAlias) {
5447
5499
  }
5448
5500
 
5449
5501
  // src/builder/shared/relation-key-utils.ts
5450
- function resolveRelationKeys(field, context = "include") {
5502
+ var RELATION_KEYS_CACHE = /* @__PURE__ */ new WeakMap();
5503
+ function computeRelationKeys(field, context) {
5451
5504
  const fkFields = normalizeKeyList(field.foreignKey);
5452
5505
  if (fkFields.length === 0) {
5453
5506
  throw new Error(
@@ -5465,6 +5518,13 @@ function resolveRelationKeys(field, context = "include") {
5465
5518
  const parentKeys = field.isForeignKeyLocal ? fkFields : refFields;
5466
5519
  return { childKeys, parentKeys };
5467
5520
  }
5521
+ function resolveRelationKeys(field, context = "include") {
5522
+ let cached = RELATION_KEYS_CACHE.get(field);
5523
+ if (cached) return cached;
5524
+ cached = computeRelationKeys(field, context);
5525
+ RELATION_KEYS_CACHE.set(field, cached);
5526
+ return cached;
5527
+ }
5468
5528
 
5469
5529
  // src/builder/shared/relation-extraction-utils.ts
5470
5530
  function extractRelationEntries(args, model) {
@@ -5494,6 +5554,18 @@ function extractRelationEntries(args, model) {
5494
5554
  var MAX_INCLUDE_DEPTH = 5;
5495
5555
  var MAX_INCLUDES_PER_LEVEL = 10;
5496
5556
  var MAX_TOTAL_SUBQUERIES = 100;
5557
+ var FIELD_BY_NAME_CACHE2 = /* @__PURE__ */ new WeakMap();
5558
+ function getFieldMap(model) {
5559
+ let map = FIELD_BY_NAME_CACHE2.get(model);
5560
+ if (!map) {
5561
+ map = /* @__PURE__ */ new Map();
5562
+ for (const f of model.fields) {
5563
+ map.set(f.name, f);
5564
+ }
5565
+ FIELD_BY_NAME_CACHE2.set(model, map);
5566
+ }
5567
+ return map;
5568
+ }
5497
5569
  function buildIncludeScope(includePath) {
5498
5570
  if (includePath.length === 0) return "include";
5499
5571
  let scope = "include";
@@ -5513,7 +5585,8 @@ function getRelationTableReference(relModel, dialect) {
5513
5585
  );
5514
5586
  }
5515
5587
  function resolveRelationOrThrow(model, schemaByName, relName) {
5516
- const field = model.fields.find((f) => f.name === relName);
5588
+ const fieldMap = getFieldMap(model);
5589
+ const field = fieldMap.get(relName);
5517
5590
  if (!isNotNullish(field)) {
5518
5591
  throw new Error(
5519
5592
  `Unknown relation '${relName}' on model ${model.name}. Available relation fields: ${model.fields.filter((f) => f.isRelation).map((f) => f.name).join(", ")}`
@@ -5630,11 +5703,22 @@ function finalizeOrderByForInclude(args) {
5630
5703
  }
5631
5704
  function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
5632
5705
  let relSelect = buildRelationSelect(relArgs, relModel, relAlias);
5633
- const nestedIncludes = isPlainObject(relArgs) ? buildIncludeSqlInternal(relArgs, __spreadProps(__spreadValues({}, ctx), {
5634
- model: relModel,
5635
- parentAlias: relAlias,
5636
- depth: ctx.depth + 1
5637
- })) : [];
5706
+ let nestedIncludes = [];
5707
+ if (isPlainObject(relArgs)) {
5708
+ const prevModel = ctx.model;
5709
+ const prevParentAlias = ctx.parentAlias;
5710
+ const prevDepth = ctx.depth;
5711
+ ctx.model = relModel;
5712
+ ctx.parentAlias = relAlias;
5713
+ ctx.depth = prevDepth + 1;
5714
+ try {
5715
+ nestedIncludes = buildIncludeSqlInternal(relArgs, ctx);
5716
+ } finally {
5717
+ ctx.model = prevModel;
5718
+ ctx.parentAlias = prevParentAlias;
5719
+ ctx.depth = prevDepth;
5720
+ }
5721
+ }
5638
5722
  if (isNonEmptyArray(nestedIncludes)) {
5639
5723
  const emptyJson = ctx.dialect === "postgres" ? `'[]'::json` : `json('[]')`;
5640
5724
  const nestedSelects = nestedIncludes.map(
@@ -6031,16 +6115,22 @@ function buildIncludeSqlInternal(args, ctx) {
6031
6115
  `Circular include detected: ${Array.from(ctx.visitSet).join(" -> ")} -> ${relationPath}. Relation '${relationPath}' creates an infinite loop.`
6032
6116
  );
6033
6117
  }
6034
- const nextIncludePath = [...ctx.includePath, relName];
6035
- const nextVisitSet = new Set(ctx.visitSet);
6036
- nextVisitSet.add(relationPath);
6037
- includes.push(
6038
- buildSingleInclude(relName, relArgs, resolved.field, resolved.relModel, __spreadProps(__spreadValues({}, ctx), {
6039
- includePath: nextIncludePath,
6040
- visitSet: nextVisitSet,
6041
- depth
6042
- }))
6043
- );
6118
+ ctx.includePath.push(relName);
6119
+ ctx.visitSet.add(relationPath);
6120
+ try {
6121
+ includes.push(
6122
+ buildSingleInclude(
6123
+ relName,
6124
+ relArgs,
6125
+ resolved.field,
6126
+ resolved.relModel,
6127
+ ctx
6128
+ )
6129
+ );
6130
+ } finally {
6131
+ ctx.includePath.pop();
6132
+ ctx.visitSet.delete(relationPath);
6133
+ }
6044
6134
  }
6045
6135
  return includes;
6046
6136
  }
@@ -6324,10 +6414,19 @@ function canUseNestedFlatJoin(relArgs, depth) {
6324
6414
  }
6325
6415
  return true;
6326
6416
  }
6327
- function canUseFlatJoinForAll(includeSpec) {
6328
- for (const value of Object.values(includeSpec)) {
6417
+ function canUseFlatJoinForAll(includeSpec, parentModel, schemas) {
6418
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
6419
+ for (const [relName, value] of Object.entries(includeSpec)) {
6329
6420
  if (value === false) continue;
6421
+ const field = parentModel.fields.find((f) => f.name === relName);
6422
+ if (!field || !field.isRelation) continue;
6330
6423
  if (!canUseNestedFlatJoin(value, 0)) return false;
6424
+ const relModel = modelMap.get(field.relatedModel);
6425
+ if (!relModel) continue;
6426
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
6427
+ if (Object.keys(nestedSpec).length > 0) {
6428
+ if (!canUseFlatJoinForAll(nestedSpec, relModel, schemas)) return false;
6429
+ }
6331
6430
  }
6332
6431
  return true;
6333
6432
  }
@@ -6424,7 +6523,7 @@ function buildFlatJoinSql(spec) {
6424
6523
  if (Object.keys(includeSpec).length === 0) {
6425
6524
  return { sql: "", requiresReduction: false, includeSpec: {} };
6426
6525
  }
6427
- if (!canUseFlatJoinForAll(includeSpec)) {
6526
+ if (!canUseFlatJoinForAll(includeSpec, model, schemas)) {
6428
6527
  return { sql: "", requiresReduction: false, includeSpec: {} };
6429
6528
  }
6430
6529
  const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
@@ -6470,6 +6569,217 @@ function buildFlatJoinSql(spec) {
6470
6569
  `.trim();
6471
6570
  return { sql, requiresReduction: true, includeSpec };
6472
6571
  }
6572
+
6573
+ // src/builder/select/array-agg.ts
6574
+ function canUseArrayAggForAll(includeSpec, parentModel, schemas) {
6575
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
6576
+ for (const [relName, value] of Object.entries(includeSpec)) {
6577
+ if (value === false) continue;
6578
+ const field = parentModel.fields.find((f) => f.name === relName);
6579
+ if (!field || !field.isRelation) continue;
6580
+ if (isPlainObject(value) && hasChildPagination(value)) return false;
6581
+ const relModel = modelMap.get(field.relatedModel);
6582
+ if (!relModel) continue;
6583
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
6584
+ if (Object.keys(nestedSpec).length > 0) return false;
6585
+ }
6586
+ return true;
6587
+ }
6588
+ function getRelationModel2(parentModel, relationName, schemas) {
6589
+ const field = parentModel.fields.find((f) => f.name === relationName);
6590
+ if (!(field == null ? void 0 : field.isRelation) || !field.relatedModel) {
6591
+ throw new Error(`Invalid relation ${relationName} on ${parentModel.name}`);
6592
+ }
6593
+ const relModel = schemas.find((m) => m.name === field.relatedModel);
6594
+ if (!relModel) {
6595
+ throw new Error(`Related model ${field.relatedModel} not found`);
6596
+ }
6597
+ return relModel;
6598
+ }
6599
+ function buildSubqueryRawSelect2(model, alias) {
6600
+ const cols = [];
6601
+ for (const f of model.fields) {
6602
+ if (f.isRelation) continue;
6603
+ cols.push(`${alias}.${quoteColumn(model, f.name)}`);
6604
+ }
6605
+ return cols.length > 0 ? cols.join(SQL_SEPARATORS.FIELD_LIST) : "*";
6606
+ }
6607
+ function readWhereInput2(relArgs) {
6608
+ if (!isPlainObject(relArgs)) return {};
6609
+ const obj = relArgs;
6610
+ if (!("where" in obj)) return {};
6611
+ const w = obj.where;
6612
+ return isPlainObject(w) ? w : {};
6613
+ }
6614
+ function buildArrayAggRelation(args) {
6615
+ const {
6616
+ relationName,
6617
+ relArgs,
6618
+ field,
6619
+ relModel,
6620
+ parentModel,
6621
+ parentAlias,
6622
+ schemas,
6623
+ dialect,
6624
+ aliasCounter,
6625
+ params
6626
+ } = args;
6627
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
6628
+ const { childKeys: relKeyFields, parentKeys: parentKeyFields } = resolveRelationKeys(field, "include");
6629
+ if (relKeyFields.length === 0) return null;
6630
+ const innerAlias = `__aa_r${aliasCounter.count++}`;
6631
+ const joinAlias = `__aa_j${aliasCounter.count++}`;
6632
+ const indices = getFieldIndices(relModel);
6633
+ const scalarSel = extractScalarSelection(relArgs, relModel);
6634
+ const pkFields = getPrimaryKeyFields(relModel);
6635
+ const selectedFields = scalarSel.includeAllScalars ? Array.from(indices.scalarFields.keys()) : [.../* @__PURE__ */ new Set([...pkFields, ...scalarSel.selectedScalarFields])];
6636
+ const pkOrderExpr = pkFields.map((f) => `${innerAlias}.${quoteColumn(relModel, f)}`).join(SQL_SEPARATORS.FIELD_LIST);
6637
+ const pkFilterExpr = `${innerAlias}.${quoteColumn(relModel, pkFields[0])}`;
6638
+ const fkSelectParts = relKeyFields.map(
6639
+ (f, i) => `${innerAlias}.${quoteColumn(relModel, f)} AS "__fk${i}"`
6640
+ );
6641
+ const aggParts = selectedFields.map((fieldName) => {
6642
+ const f = indices.scalarFields.get(fieldName);
6643
+ if (!f) return null;
6644
+ const colRef = `${innerAlias}.${quoteColumn(relModel, fieldName)}`;
6645
+ const alias = `"${relationName}.${f.name}"`;
6646
+ return `array_agg(${colRef} ORDER BY ${pkOrderExpr}) FILTER (WHERE ${pkFilterExpr} IS NOT NULL) AS ${alias}`;
6647
+ }).filter(Boolean);
6648
+ const fkGroupByParts = relKeyFields.map(
6649
+ (f) => `${innerAlias}.${quoteColumn(relModel, f)}`
6650
+ );
6651
+ const relTable = buildTableReference(
6652
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
6653
+ relModel.tableName,
6654
+ dialect
6655
+ );
6656
+ const whereInput = readWhereInput2(relArgs);
6657
+ let whereJoinsSql = "";
6658
+ let whereClauseSql = "";
6659
+ if (Object.keys(whereInput).length > 0) {
6660
+ const aliasGen = createAliasGenerator();
6661
+ const whereResult = buildWhereClause(whereInput, {
6662
+ alias: innerAlias,
6663
+ schemaModels: schemas,
6664
+ model: relModel,
6665
+ params,
6666
+ isSubquery: true,
6667
+ aliasGen,
6668
+ dialect
6669
+ });
6670
+ if (whereResult.joins.length > 0) {
6671
+ whereJoinsSql = " " + whereResult.joins.join(" ");
6672
+ }
6673
+ if (isValidWhereClause(whereResult.clause)) {
6674
+ whereClauseSql = ` ${SQL_TEMPLATES.WHERE} ${whereResult.clause}`;
6675
+ }
6676
+ }
6677
+ 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)}`;
6678
+ const onParts = parentKeyFields.map(
6679
+ (f, i) => `${joinAlias}."__fk${i}" = ${parentAlias}.${quoteColumn(parentModel, f)}`
6680
+ );
6681
+ const onCondition = onParts.length === 1 ? onParts[0] : `(${onParts.join(" AND ")})`;
6682
+ const joinSql = `LEFT JOIN (${subquery}) ${joinAlias} ON ${onCondition}`;
6683
+ const selectExprs = selectedFields.map((fieldName) => {
6684
+ const f = indices.scalarFields.get(fieldName);
6685
+ if (!f) return null;
6686
+ return `${joinAlias}."${relationName}.${f.name}"`;
6687
+ }).filter(Boolean);
6688
+ return {
6689
+ joinSql,
6690
+ selectExprs,
6691
+ relationName,
6692
+ isList,
6693
+ scalarFieldNames: selectedFields
6694
+ };
6695
+ }
6696
+ function buildArrayAggSql(spec) {
6697
+ const {
6698
+ select: select2,
6699
+ from,
6700
+ whereClause,
6701
+ whereJoins,
6702
+ orderBy,
6703
+ dialect,
6704
+ model,
6705
+ schemas,
6706
+ args,
6707
+ params
6708
+ } = spec;
6709
+ const entries = extractRelationEntries(args, model);
6710
+ const includeSpec = {};
6711
+ for (const e of entries) {
6712
+ includeSpec[e.name] = e.value;
6713
+ }
6714
+ if (Object.keys(includeSpec).length === 0) {
6715
+ return {
6716
+ sql: "",
6717
+ requiresReduction: false,
6718
+ includeSpec: {},
6719
+ isArrayAgg: false
6720
+ };
6721
+ }
6722
+ if (!canUseArrayAggForAll(includeSpec, model, schemas)) {
6723
+ return {
6724
+ sql: "",
6725
+ requiresReduction: false,
6726
+ includeSpec: {},
6727
+ isArrayAgg: false
6728
+ };
6729
+ }
6730
+ const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
6731
+ const baseWhere = whereClause && whereClause !== "1=1" ? `WHERE ${whereClause}` : "";
6732
+ const baseOrderBy = orderBy ? `ORDER BY ${orderBy}` : "";
6733
+ const subqueryScalarCols = buildSubqueryRawSelect2(model, from.alias);
6734
+ let baseSubquery = `SELECT ${subqueryScalarCols} FROM ${from.table} ${from.alias}` + (baseJoins ? ` ${baseJoins}` : "") + (baseWhere ? ` ${baseWhere}` : "") + (baseOrderBy ? ` ${baseOrderBy}` : "");
6735
+ baseSubquery = appendPagination(baseSubquery.trim(), spec);
6736
+ const aliasCounter = { count: 0 };
6737
+ const joins = [];
6738
+ const arraySelectExprs = [];
6739
+ for (const [relName, relValue] of Object.entries(includeSpec)) {
6740
+ if (relValue === false) continue;
6741
+ const field = model.fields.find((f) => f.name === relName);
6742
+ if (!field || !isValidRelationField(field)) continue;
6743
+ const relModel = getRelationModel2(model, relName, schemas);
6744
+ const built = buildArrayAggRelation({
6745
+ relationName: relName,
6746
+ relArgs: relValue,
6747
+ field,
6748
+ relModel,
6749
+ parentModel: model,
6750
+ parentAlias: from.alias,
6751
+ schemas,
6752
+ dialect,
6753
+ aliasCounter,
6754
+ params
6755
+ });
6756
+ if (!built) continue;
6757
+ joins.push(built.joinSql);
6758
+ arraySelectExprs.push(...built.selectExprs);
6759
+ }
6760
+ if (joins.length === 0) {
6761
+ return {
6762
+ sql: "",
6763
+ requiresReduction: false,
6764
+ includeSpec: {},
6765
+ isArrayAgg: false
6766
+ };
6767
+ }
6768
+ const baseSelect = (select2 != null ? select2 : "").trim();
6769
+ const allSelects = [baseSelect, ...arraySelectExprs].filter((s) => s && s.trim().length > 0).join(SQL_SEPARATORS.FIELD_LIST);
6770
+ if (!allSelects) {
6771
+ throw new Error("Array-agg SELECT requires at least one selected field");
6772
+ }
6773
+ const pkField = getPrimaryKeyField(model);
6774
+ const pkOrder = `${from.alias}.${quoteColumn(model, pkField)} ASC`;
6775
+ const sql = `
6776
+ SELECT ${allSelects}
6777
+ FROM (${baseSubquery}) ${from.alias}
6778
+ ${joins.join(" ")}
6779
+ ORDER BY ${pkOrder}
6780
+ `.trim();
6781
+ return { sql, requiresReduction: true, includeSpec, isArrayAgg: true };
6782
+ }
6473
6783
  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;
6474
6784
  function buildWhereSql(conditions) {
6475
6785
  if (!isNonEmptyArray(conditions)) return "";
@@ -6557,47 +6867,45 @@ function buildOutputColumns(scalarNames, includeNames, hasCount) {
6557
6867
  }
6558
6868
  return formatted;
6559
6869
  }
6560
- function buildWindowOrder(args) {
6561
- const { baseOrder, idField, fromAlias, model } = args;
6562
- const fromLower = String(fromAlias).toLowerCase();
6563
- const orderFields = baseOrder.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim().toLowerCase().replace(/\s+/g, " "));
6564
- const hasIdInOrder = orderFields.some((f) => {
6565
- return f.includes(`${fromLower}.id`) || f.includes(`${fromLower}."id"`);
6566
- });
6567
- if (hasIdInOrder) return baseOrder;
6568
- const idTiebreaker = idField ? ", " + col(fromAlias, "id", model) + " ASC" : "";
6569
- return baseOrder + idTiebreaker;
6570
- }
6571
- function extractDistinctOrderEntries(spec) {
6572
- if (isNotNullish(spec.args.orderBy)) {
6573
- const normalized = normalizeOrderByInput(
6574
- spec.args.orderBy,
6575
- parseOrderByValue
6576
- );
6577
- const entries = [];
6578
- for (const item of normalized) {
6579
- for (const field in item) {
6580
- if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
6581
- const value = item[field];
6582
- if (typeof value === "string") {
6583
- entries.push({ field, direction: value });
6584
- continue;
6585
- }
6586
- const obj = value;
6587
- entries.push({ field, direction: obj.direction, nulls: obj.nulls });
6870
+ function getOrderByEntries(spec) {
6871
+ if (!isNotNullish(spec.args.orderBy)) return [];
6872
+ const normalized = normalizeOrderByInput(spec.args.orderBy, parseOrderByValue);
6873
+ const entries = [];
6874
+ for (const item of normalized) {
6875
+ for (const field in item) {
6876
+ if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
6877
+ const value = item[field];
6878
+ if (typeof value === "string") {
6879
+ entries.push({ field, direction: value });
6880
+ continue;
6588
6881
  }
6882
+ const obj = value;
6883
+ entries.push({ field, direction: obj.direction, nulls: obj.nulls });
6589
6884
  }
6590
- if (entries.length > 0) return entries;
6591
6885
  }
6592
- if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
6593
- return [...spec.distinct].map((f) => ({
6594
- field: f,
6595
- direction: "asc"
6596
- }));
6886
+ return entries;
6887
+ }
6888
+ function renderOrderBySql(entries, alias, dialect, model) {
6889
+ if (entries.length === 0) return "";
6890
+ const out = [];
6891
+ for (const e of entries) {
6892
+ const dir = e.direction.toUpperCase();
6893
+ const c = col(alias, e.field, model);
6894
+ if (dialect === "postgres") {
6895
+ const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
6896
+ out.push(c + " " + dir + nulls);
6897
+ } else if (isNotNullish(e.nulls)) {
6898
+ const isNullExpr = `(${c} IS NULL)`;
6899
+ const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
6900
+ out.push(isNullExpr + " " + nullRankDir);
6901
+ out.push(c + " " + dir);
6902
+ } else {
6903
+ out.push(c + " " + dir);
6904
+ }
6597
6905
  }
6598
- return [];
6906
+ return out.join(SQL_SEPARATORS.ORDER_BY);
6599
6907
  }
6600
- function buildFieldNameOrderBy(entries, alias) {
6908
+ function renderOrderBySimple(entries, alias) {
6601
6909
  if (entries.length === 0) return "";
6602
6910
  const out = [];
6603
6911
  for (const e of entries) {
@@ -6608,40 +6916,73 @@ function buildFieldNameOrderBy(entries, alias) {
6608
6916
  const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
6609
6917
  out.push(isNullExpr + " " + nullRankDir);
6610
6918
  out.push(c + " " + dir);
6611
- continue;
6919
+ } else {
6920
+ out.push(c + " " + dir);
6612
6921
  }
6613
- out.push(c + " " + dir);
6614
6922
  }
6615
6923
  return out.join(SQL_SEPARATORS.ORDER_BY);
6616
6924
  }
6925
+ function ensureIdTiebreakerEntries(entries, model) {
6926
+ var _a3, _b;
6927
+ const idField = (_b = (_a3 = model == null ? void 0 : model.fields) == null ? void 0 : _a3.find) == null ? void 0 : _b.call(
6928
+ _a3,
6929
+ (f) => f.name === "id" && !f.isRelation
6930
+ );
6931
+ if (!idField) return entries;
6932
+ if (entries.some((e) => e.field === "id")) return entries;
6933
+ return [...entries, { field: "id", direction: "asc" }];
6934
+ }
6935
+ function ensurePostgresDistinctOrderEntries(args) {
6936
+ const { entries, distinct, model } = args;
6937
+ const distinctEntries = [...distinct].map((f) => ({
6938
+ field: f,
6939
+ direction: "asc"
6940
+ }));
6941
+ const canKeepAsIs = entries.length >= distinctEntries.length && distinctEntries.every((de, i) => entries[i].field === de.field);
6942
+ const merged = canKeepAsIs ? entries : [...distinctEntries, ...entries];
6943
+ return ensureIdTiebreakerEntries(merged, model);
6944
+ }
6945
+ function extractDistinctOrderEntries(spec) {
6946
+ const entries = getOrderByEntries(spec);
6947
+ if (entries.length > 0) return entries;
6948
+ if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
6949
+ return [...spec.distinct].map((f) => ({
6950
+ field: f,
6951
+ direction: "asc"
6952
+ }));
6953
+ }
6954
+ return [];
6955
+ }
6617
6956
  function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
6618
- var _a, _b;
6619
- const { includes, from, whereClause, whereJoins, orderBy, distinct, model } = spec;
6957
+ var _a3, _b;
6958
+ const { includes, from, whereClause, whereJoins, distinct, model } = spec;
6620
6959
  if (!isNotNullish(distinct) || !isNonEmptyArray(distinct)) {
6621
6960
  throw new Error("buildSqliteDistinctQuery requires distinct fields");
6622
6961
  }
6623
6962
  const scalarNames = parseSimpleScalarSelect(spec.select, from.alias);
6624
6963
  const includeNames = includes.map((i) => i.name);
6625
- const hasCount = Boolean((_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count);
6964
+ const hasCount = Boolean((_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count);
6626
6965
  const outerSelectCols = buildOutputColumns(
6627
6966
  scalarNames,
6628
6967
  includeNames,
6629
6968
  hasCount
6630
6969
  );
6631
6970
  const distinctCols = buildDistinctColumns([...distinct], from.alias, model);
6632
- const fallbackOrder = [...distinct].map((f) => col(from.alias, f, model) + " ASC").join(SQL_SEPARATORS.FIELD_LIST);
6633
- const idField = model.fields.find(
6634
- (f) => f.name === "id" && !f.isRelation
6635
- );
6636
- const baseOrder = isNonEmptyString(orderBy) ? orderBy : fallbackOrder;
6637
- const windowOrder = buildWindowOrder({
6638
- baseOrder,
6639
- idField,
6640
- fromAlias: from.alias,
6971
+ const baseEntries = getOrderByEntries(spec);
6972
+ const fallbackEntries = [...distinct].map((f) => ({
6973
+ field: f,
6974
+ direction: "asc"
6975
+ }));
6976
+ const resolvedEntries = baseEntries.length > 0 ? baseEntries : fallbackEntries;
6977
+ const windowEntries = ensureIdTiebreakerEntries(resolvedEntries, model);
6978
+ const windowOrder = renderOrderBySql(
6979
+ windowEntries,
6980
+ from.alias,
6981
+ "sqlite",
6641
6982
  model
6642
- });
6983
+ );
6643
6984
  const outerEntries = extractDistinctOrderEntries(spec);
6644
- const outerOrder = buildFieldNameOrderBy(outerEntries, '"__tp_distinct"');
6985
+ const outerOrder = renderOrderBySimple(outerEntries, '"__tp_distinct"');
6645
6986
  const joins = buildJoinsSql(whereJoins, countJoins);
6646
6987
  const conditions = [];
6647
6988
  if (whereClause && whereClause !== "1=1") conditions.push(whereClause);
@@ -6692,12 +7033,12 @@ function resolveCountSelect(countSelectRaw, model) {
6692
7033
  return null;
6693
7034
  }
6694
7035
  function buildIncludeColumns(spec) {
6695
- var _a, _b;
7036
+ var _a3, _b;
6696
7037
  const { select: select2, includes, dialect, model, schemas, from, params } = spec;
6697
7038
  const baseSelect = (select2 != null ? select2 : "").trim();
6698
7039
  let countCols = "";
6699
7040
  let countJoins = [];
6700
- const countSelectRaw = (_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count;
7041
+ const countSelectRaw = (_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count;
6701
7042
  if (countSelectRaw) {
6702
7043
  const resolvedCountSelect = resolveCountSelect(countSelectRaw, model);
6703
7044
  if (resolvedCountSelect && Object.keys(resolvedCountSelect).length > 0) {
@@ -6856,37 +7197,6 @@ function extractIncludeSpec(args) {
6856
7197
  function hasNestedIncludes(includeSpec) {
6857
7198
  return Object.keys(includeSpec).length > 0;
6858
7199
  }
6859
- function splitOrderByTerms(orderBy) {
6860
- const raw = orderBy.trim();
6861
- if (raw.length === 0) return [];
6862
- return raw.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim()).filter((s) => s.length > 0);
6863
- }
6864
- function hasIdInOrderBy(orderBy, fromAlias) {
6865
- const lower = orderBy.toLowerCase();
6866
- const aliasLower = fromAlias.toLowerCase();
6867
- return lower.includes(`${aliasLower}.id `) || lower.includes(`${aliasLower}."id"`);
6868
- }
6869
- function ensureIdTiebreakerOrderBy(orderBy, fromAlias, model) {
6870
- var _a, _b;
6871
- const idField = (_b = (_a = model == null ? void 0 : model.fields) == null ? void 0 : _a.find) == null ? void 0 : _b.call(
6872
- _a,
6873
- (f) => f.name === "id" && !f.isRelation
6874
- );
6875
- if (!idField) return orderBy;
6876
- if (hasIdInOrderBy(orderBy, fromAlias)) return orderBy;
6877
- const t = col(fromAlias, "id", model) + " ASC";
6878
- return isNonEmptyString(orderBy) ? orderBy + ", " + t : t;
6879
- }
6880
- function ensurePostgresDistinctOrderBy(args) {
6881
- const { orderBy, distinct, fromAlias, model } = args;
6882
- const distinctTerms = distinct.map((f) => col(fromAlias, f, model) + " ASC");
6883
- const existing = splitOrderByTerms(orderBy);
6884
- const canKeepAsIs = existing.length >= distinctTerms.length && distinctTerms.every(
6885
- (term, i) => existing[i].toLowerCase().startsWith(term.split(" ASC")[0].toLowerCase())
6886
- );
6887
- const merged = canKeepAsIs ? orderBy : [...distinctTerms, ...existing].join(SQL_SEPARATORS.ORDER_BY);
6888
- return ensureIdTiebreakerOrderBy(merged, fromAlias, model);
6889
- }
6890
7200
  function constructFinalSql(spec) {
6891
7201
  const {
6892
7202
  select: select2,
@@ -6901,7 +7211,6 @@ function constructFinalSql(spec) {
6901
7211
  params,
6902
7212
  dialect,
6903
7213
  model,
6904
- includes,
6905
7214
  schemas,
6906
7215
  pagination,
6907
7216
  args
@@ -6913,7 +7222,24 @@ function constructFinalSql(spec) {
6913
7222
  const includeSpec = extractIncludeSpec(args);
6914
7223
  const hasIncludes = hasNestedIncludes(includeSpec);
6915
7224
  const hasPagination = isNotNullish(pagination.take);
6916
- const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec);
7225
+ const takeValue = typeof pagination.take === "number" ? pagination.take : null;
7226
+ const isLargeTake = takeValue !== null && takeValue > 50;
7227
+ const shouldUseArrayAgg = dialect === "postgres" && hasIncludes && method === "findMany" && hasPagination && isLargeTake && canUseArrayAggForAll(includeSpec, model, schemas);
7228
+ if (shouldUseArrayAgg) {
7229
+ const aaResult = buildArrayAggSql(spec);
7230
+ if (aaResult.sql) {
7231
+ const baseSqlResult = finalizeSql(aaResult.sql, params, dialect);
7232
+ return {
7233
+ sql: baseSqlResult.sql,
7234
+ params: baseSqlResult.params,
7235
+ paramMappings: baseSqlResult.paramMappings,
7236
+ requiresReduction: true,
7237
+ includeSpec: aaResult.includeSpec,
7238
+ isArrayAgg: true
7239
+ };
7240
+ }
7241
+ }
7242
+ const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec, model, schemas);
6917
7243
  if (shouldUseFlatJoin) {
6918
7244
  const flatResult = buildFlatJoinSql(spec);
6919
7245
  if (flatResult.sql) {
@@ -6959,12 +7285,13 @@ function constructFinalSql(spec) {
6959
7285
  pushWhere(parts, conditions);
6960
7286
  let finalOrderBy = orderBy;
6961
7287
  if (dialect === "postgres" && isNonEmptyArray(distinct)) {
6962
- finalOrderBy = ensurePostgresDistinctOrderBy({
6963
- orderBy: orderBy || "",
7288
+ const currentEntries = getOrderByEntries(spec);
7289
+ const mergedEntries = ensurePostgresDistinctOrderEntries({
7290
+ entries: currentEntries.length > 0 ? currentEntries : [],
6964
7291
  distinct: [...distinct],
6965
- fromAlias: from.alias,
6966
7292
  model
6967
7293
  });
7294
+ finalOrderBy = renderOrderBySql(mergedEntries, from.alias, dialect, model);
6968
7295
  }
6969
7296
  if (isNonEmptyString(finalOrderBy))
6970
7297
  parts.push(SQL_TEMPLATES.ORDER_BY, finalOrderBy);
@@ -6990,11 +7317,11 @@ function mapFirstOrderByByField(existing) {
6990
7317
  return m;
6991
7318
  }
6992
7319
  function buildPostgresDistinctOrderBy(distinctFields, existing) {
6993
- var _a;
7320
+ var _a3;
6994
7321
  const firstByField = mapFirstOrderByByField(existing);
6995
7322
  const next = [];
6996
7323
  for (const f of distinctFields) {
6997
- next.push((_a = firstByField.get(f)) != null ? _a : { [f]: "asc" });
7324
+ next.push((_a3 = firstByField.get(f)) != null ? _a3 : { [f]: "asc" });
6998
7325
  }
6999
7326
  const distinctSet = new Set(distinctFields);
7000
7327
  for (const obj of existing) {
@@ -7820,10 +8147,10 @@ function isPrismaMethod(v) {
7820
8147
  return v === "findMany" || v === "findFirst" || v === "findUnique" || v === "aggregate" || v === "groupBy" || v === "count";
7821
8148
  }
7822
8149
  function resolveMethod(directive) {
7823
- var _a, _b;
8150
+ var _a3, _b;
7824
8151
  const m = directive == null ? void 0 : directive.method;
7825
8152
  if (isPrismaMethod(m)) return m;
7826
- const pm = (_b = (_a = directive == null ? void 0 : directive.query) == null ? void 0 : _a.processed) == null ? void 0 : _b.method;
8153
+ const pm = (_b = (_a3 = directive == null ? void 0 : directive.query) == null ? void 0 : _a3.processed) == null ? void 0 : _b.method;
7827
8154
  if (isPrismaMethod(pm)) return pm;
7828
8155
  return "findMany";
7829
8156
  }
@@ -7984,7 +8311,7 @@ function extractIncludeSpec2(processed, modelDef) {
7984
8311
  return includeSpec;
7985
8312
  }
7986
8313
  function buildAndNormalizeSql(args) {
7987
- var _a;
8314
+ var _a3;
7988
8315
  const {
7989
8316
  method,
7990
8317
  processed,
@@ -8010,13 +8337,15 @@ function buildAndNormalizeSql(args) {
8010
8337
  sqlResult.paramMappings,
8011
8338
  dialect
8012
8339
  );
8013
- const includeSpec = (_a = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a : extractIncludeSpec2(processed, modelDef);
8340
+ const includeSpec = (_a3 = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a3 : extractIncludeSpec2(processed, modelDef);
8014
8341
  const requiresReduction = sqlResult.requiresReduction === true;
8342
+ const isArrayAgg = sqlResult.isArrayAgg === true;
8015
8343
  return {
8016
8344
  sql: normalized.sql,
8017
8345
  paramMappings: normalized.paramMappings,
8018
8346
  requiresReduction,
8019
- includeSpec
8347
+ includeSpec,
8348
+ isArrayAgg
8020
8349
  };
8021
8350
  }
8022
8351
  function finalizeDirective(args) {
@@ -8027,11 +8356,12 @@ function finalizeDirective(args) {
8027
8356
  normalizedMappings,
8028
8357
  dialect,
8029
8358
  requiresReduction,
8030
- includeSpec
8359
+ includeSpec,
8360
+ isArrayAgg
8031
8361
  } = args;
8032
8362
  const params = normalizedMappings.map((m) => {
8033
- var _a;
8034
- return (_a = m.value) != null ? _a : void 0;
8363
+ var _a3;
8364
+ return (_a3 = m.value) != null ? _a3 : void 0;
8035
8365
  });
8036
8366
  validateParamConsistencyByDialect(normalizedSql, params, dialect);
8037
8367
  const { staticParams, dynamicKeys, paramOrder } = buildParamsFromMappings(normalizedMappings);
@@ -8044,6 +8374,7 @@ function finalizeDirective(args) {
8044
8374
  paramMappings: normalizedMappings,
8045
8375
  requiresReduction,
8046
8376
  includeSpec,
8377
+ isArrayAgg,
8047
8378
  originalDirective: directive
8048
8379
  };
8049
8380
  }
@@ -8077,7 +8408,8 @@ function generateSQL(directive) {
8077
8408
  normalizedMappings: built.paramMappings,
8078
8409
  dialect,
8079
8410
  requiresReduction: built.requiresReduction,
8080
- includeSpec: built.includeSpec
8411
+ includeSpec: built.includeSpec,
8412
+ isArrayAgg: built.isArrayAgg
8081
8413
  });
8082
8414
  }
8083
8415
 
@@ -8732,7 +9064,8 @@ function processModelDirectives(modelName, result, config) {
8732
9064
  dynamicKeys: sqlDirective.dynamicKeys,
8733
9065
  paramMappings: sqlDirective.paramMappings,
8734
9066
  requiresReduction: sqlDirective.requiresReduction || false,
8735
- includeSpec: sqlDirective.includeSpec || {}
9067
+ includeSpec: sqlDirective.includeSpec || {},
9068
+ isArrayAgg: sqlDirective.isArrayAgg || false
8736
9069
  });
8737
9070
  } catch (error) {
8738
9071
  if (!config.skipInvalid) throw error;
@@ -8760,9 +9093,9 @@ function processAllModelDirectives(directiveResults, config) {
8760
9093
  }
8761
9094
  function generateClient(options) {
8762
9095
  return __async(this, null, function* () {
8763
- var _a;
9096
+ var _a3;
8764
9097
  const { datamodel, outputDir, config, datasourceUrl } = options;
8765
- const runtimeImportPath = (_a = options.runtimeImportPath) != null ? _a : "prisma-sql";
9098
+ const runtimeImportPath = (_a3 = options.runtimeImportPath) != null ? _a3 : "prisma-sql";
8766
9099
  setGlobalDialect(config.dialect);
8767
9100
  const models = schemaParser.convertDMMFToModels(datamodel);
8768
9101
  const directiveResults = schemaParser.processAllDirectives(
@@ -8842,8 +9175,6 @@ function generateClient(options) {
8842
9175
  }
8843
9176
  function generateImports(runtimeImportPath) {
8844
9177
  return `import {
8845
- transformAggregateRow,
8846
- extractCountValue,
8847
9178
  buildSQL,
8848
9179
  buildBatchSql,
8849
9180
  parseBatchResults,
@@ -8855,7 +9186,6 @@ function generateImports(runtimeImportPath) {
8855
9186
  planQueryStrategy,
8856
9187
  executeWhereInSegments,
8857
9188
  buildReducerConfig,
8858
- reduceFlatRows,
8859
9189
  type PrismaMethod,
8860
9190
  type Model,
8861
9191
  type BatchQuery,
@@ -8863,13 +9193,11 @@ function generateImports(runtimeImportPath) {
8863
9193
  type TransactionQuery,
8864
9194
  type TransactionOptions,
8865
9195
  getOrPrepareStatement,
8866
- shouldSqliteUseGet,
8867
9196
  normalizeParams,
8868
9197
  executePostgresQuery,
8869
9198
  executeSqliteQuery,
8870
9199
  executeRaw,
8871
- } from ${JSON.stringify(runtimeImportPath)}
8872
- import { RELATION_STATS } from './planner.generated'`;
9200
+ } from ${JSON.stringify(runtimeImportPath)}`;
8873
9201
  }
8874
9202
  function generateCoreTypes() {
8875
9203
  return `class DeferredQuery {
@@ -8998,6 +9326,7 @@ const QUERIES: Record<string, Record<string, Record<string, {
8998
9326
  paramMappings: any[]
8999
9327
  requiresReduction: boolean
9000
9328
  includeSpec: Record<string, any>
9329
+ isArrayAgg: boolean
9001
9330
  }>>> = ${formatQueries(queries)}
9002
9331
 
9003
9332
  const DIALECT = ${JSON.stringify(dialect)}
@@ -9220,9 +9549,10 @@ function generateExtension(runtimeImportPath) {
9220
9549
  requiresReduction: boolean,
9221
9550
  includeSpec: Record<string, any> | undefined,
9222
9551
  model: any | undefined,
9552
+ isArrayAgg?: boolean,
9223
9553
  ): Promise<unknown[]> {
9224
9554
  if (DIALECT === 'postgres') {
9225
- return executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS)
9555
+ return executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS, isArrayAgg)
9226
9556
  }
9227
9557
 
9228
9558
  return executeSqliteQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS)
@@ -9293,7 +9623,6 @@ function generateExtension(runtimeImportPath) {
9293
9623
  method,
9294
9624
  args: transformedArgs,
9295
9625
  allModels: MODELS,
9296
- relationStats: RELATION_STATS as any,
9297
9626
  dialect: DIALECT,
9298
9627
  })
9299
9628
 
@@ -9304,6 +9633,7 @@ function generateExtension(runtimeImportPath) {
9304
9633
  let prebaked = false
9305
9634
  let requiresReduction = false
9306
9635
  let includeSpec: Record<string, any> | undefined
9636
+ let isArrayAgg = false
9307
9637
 
9308
9638
  if (prebakedQuery) {
9309
9639
  sql = prebakedQuery.sql
@@ -9311,17 +9641,19 @@ function generateExtension(runtimeImportPath) {
9311
9641
  prebaked = true
9312
9642
  requiresReduction = prebakedQuery.requiresReduction || false
9313
9643
  includeSpec = prebakedQuery.includeSpec
9644
+ isArrayAgg = prebakedQuery.isArrayAgg || false
9314
9645
  } else {
9315
9646
  const result = buildSQL(model, MODELS, method, plan.filteredArgs, DIALECT)
9316
9647
  sql = result.sql
9317
9648
  params = result.params as unknown[]
9318
9649
  requiresReduction = result.requiresReduction || false
9319
9650
  includeSpec = result.includeSpec
9651
+ isArrayAgg = result.isArrayAgg || false
9320
9652
  }
9321
9653
 
9322
9654
  if (debug) {
9323
9655
  const strategy = DIALECT === 'postgres'
9324
- ? (requiresReduction ? 'STREAMING REDUCTION' : 'STREAMING')
9656
+ ? (isArrayAgg ? 'ARRAY AGG' : requiresReduction ? 'STREAMING REDUCTION' : 'STREAMING')
9325
9657
  : (requiresReduction ? 'BUFFERED REDUCTION' : 'DIRECT')
9326
9658
 
9327
9659
  const whereInMode = plan.whereInSegments.length > 0
@@ -9334,63 +9666,75 @@ function generateExtension(runtimeImportPath) {
9334
9666
  console.log(' Params:', params)
9335
9667
  }
9336
9668
 
9337
- let results = await executeQuery(sql, params, method, requiresReduction, includeSpec, model)
9338
-
9339
- const duration = Date.now() - startTime
9669
+ if (plan.whereInSegments.length > 0) {
9670
+ if (DIALECT === 'postgres') {
9671
+ const { executeWhereInSegmentsStreaming } = await import(${JSON.stringify(runtimeImportPath)})
9672
+
9673
+ const results = await executeWhereInSegmentsStreaming({
9674
+ segments: plan.whereInSegments,
9675
+ parentSql: sql,
9676
+ parentParams: normalizeParams(params),
9677
+ parentModel: model,
9678
+ allModels: MODELS,
9679
+ modelMap: MODEL_MAP,
9680
+ dialect: DIALECT,
9681
+ execute: async (sql: string, params: unknown[]) => {
9682
+ const results: any[] = []
9683
+ await client.unsafe(sql, normalizeParams(params)).forEach((row: any) => {
9684
+ results.push(row)
9685
+ })
9686
+ return results
9687
+ },
9688
+ })
9340
9689
 
9341
- onQuery?.({
9342
- model: modelName,
9343
- method,
9344
- sql,
9345
- params,
9346
- duration,
9347
- prebaked,
9348
- })
9690
+ if (plan.injectedParentKeys.length > 0) {
9691
+ for (const row of results) {
9692
+ for (const key of plan.injectedParentKeys) {
9693
+ delete row[key]
9694
+ }
9695
+ }
9696
+ }
9349
9697
 
9350
- let transformed = transformQueryResults(method, results)
9698
+ const duration = Date.now() - startTime
9699
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9351
9700
 
9352
- if (plan.whereInSegments.length > 0) {
9353
- const resultArray = Array.isArray(transformed) ? transformed : [transformed]
9701
+ return transformQueryResults(method, results)
9702
+ } else {
9703
+ const parentRows = await executeQuery(sql, params, method, requiresReduction, includeSpec, model, isArrayAgg) as any[]
9354
9704
 
9355
- if (resultArray.length > 0 && resultArray[0] != null) {
9356
- if (DIALECT === 'postgres') {
9357
- const { executeWhereInSegmentsStreaming } = await import(${JSON.stringify(runtimeImportPath)})
9358
-
9359
- const streamResults = await executeWhereInSegmentsStreaming({
9360
- segments: plan.whereInSegments,
9361
- parentSql: sql,
9362
- parentParams: params,
9363
- parentModel: model,
9364
- allModels: MODELS,
9365
- modelMap: MODEL_MAP,
9366
- dialect: DIALECT,
9367
- execute: async (sql: string, params: unknown[]) => {
9368
- const results: any[] = []
9369
- await client.unsafe(sql, normalizeParams(params)).forEach((row: any) => {
9370
- results.push(row)
9371
- })
9372
- return results
9373
- },
9374
- batchSize: 100,
9375
- maxConcurrency: 10
9376
- })
9377
-
9378
- transformed = Array.isArray(transformed) ? streamResults : streamResults[0]
9379
- } else {
9705
+ if (parentRows.length > 0) {
9380
9706
  await executeWhereInSegments({
9381
9707
  segments: plan.whereInSegments,
9382
- parentRows: resultArray,
9708
+ parentRows,
9383
9709
  parentModel: model,
9384
9710
  allModels: MODELS,
9385
9711
  modelMap: MODEL_MAP,
9386
9712
  dialect: DIALECT,
9387
9713
  execute: executeWhereInQuery,
9388
9714
  })
9715
+
9716
+ if (plan.injectedParentKeys.length > 0) {
9717
+ for (const row of parentRows) {
9718
+ for (const key of plan.injectedParentKeys) {
9719
+ delete row[key]
9720
+ }
9721
+ }
9722
+ }
9389
9723
  }
9724
+
9725
+ const duration = Date.now() - startTime
9726
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9727
+
9728
+ return transformQueryResults(method, parentRows)
9390
9729
  }
9391
9730
  }
9392
9731
 
9393
- return transformed
9732
+ const results = await executeQuery(sql, params, method, requiresReduction, includeSpec, model, isArrayAgg)
9733
+
9734
+ const duration = Date.now() - startTime
9735
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9736
+
9737
+ return transformQueryResults(method, results)
9394
9738
  } catch (error) {
9395
9739
  const msg = error instanceof Error ? error.message : String(error)
9396
9740
  console.warn(\`[prisma-sql] \${modelName}.\${method} acceleration failed: \${msg}\`)
@@ -9431,7 +9775,6 @@ function generateExtension(runtimeImportPath) {
9431
9775
  method: 'findMany',
9432
9776
  args: transformedArgs,
9433
9777
  allModels: MODELS,
9434
- relationStats: RELATION_STATS as any,
9435
9778
  dialect: DIALECT,
9436
9779
  })
9437
9780
 
@@ -9442,23 +9785,39 @@ function generateExtension(runtimeImportPath) {
9442
9785
  let params: unknown[]
9443
9786
  let requiresReduction = false
9444
9787
  let includeSpec: Record<string, any> | undefined
9788
+ let isArrayAgg = false
9445
9789
 
9446
9790
  if (prebakedQuery) {
9447
9791
  sql = prebakedQuery.sql
9448
9792
  params = resolveParamsFromMappings(plan.filteredArgs, prebakedQuery.paramMappings)
9449
9793
  requiresReduction = prebakedQuery.requiresReduction
9450
9794
  includeSpec = prebakedQuery.includeSpec
9795
+ isArrayAgg = prebakedQuery.isArrayAgg || false
9451
9796
  } else {
9452
9797
  const result = buildSQL(model, MODELS, 'findMany', plan.filteredArgs, DIALECT)
9453
9798
  sql = result.sql
9454
9799
  params = result.params as unknown[]
9455
9800
  requiresReduction = result.requiresReduction || false
9456
9801
  includeSpec = result.includeSpec
9802
+ isArrayAgg = result.isArrayAgg || false
9457
9803
  }
9458
9804
 
9459
9805
  const normalizedParams = normalizeParams(params)
9460
9806
 
9461
- if (requiresReduction && includeSpec) {
9807
+ if (isArrayAgg && includeSpec) {
9808
+ const { buildArrayAggReducerConfig, reduceArrayAggRows } = await import(${JSON.stringify(runtimeImportPath)})
9809
+ const config = buildArrayAggReducerConfig(model, includeSpec, MODELS)
9810
+ const results: any[] = []
9811
+
9812
+ await client.unsafe(sql, normalizedParams).forEach((row: any) => {
9813
+ results.push(row)
9814
+ })
9815
+
9816
+ const reduced = reduceArrayAggRows(results, config)
9817
+ for (const item of reduced) {
9818
+ yield item
9819
+ }
9820
+ } else if (requiresReduction && includeSpec) {
9462
9821
  const { createProgressiveReducer } = await import(${JSON.stringify(runtimeImportPath)})
9463
9822
  const config = buildReducerConfig(model, includeSpec, MODELS)
9464
9823
  const reducer = createProgressiveReducer(config)
@@ -9721,8 +10080,7 @@ function generateCode(models, queries, dialect, datamodel, runtimeImportPath) {
9721
10080
  generateDataConstants(cleanModels, mappings, fieldTypes, queries, dialect),
9722
10081
  generateTransformLogic(),
9723
10082
  generateExtension(runtimeImportPath),
9724
- generateTypeExports(),
9725
- `export * from './planner.generated'`
10083
+ generateTypeExports()
9726
10084
  ].join("\n\n");
9727
10085
  }
9728
10086
  function formatQueries(queries) {
@@ -9742,6 +10100,7 @@ function formatQueries(queries) {
9742
10100
  paramMappings: ${JSON.stringify(query.paramMappings)},
9743
10101
  requiresReduction: ${query.requiresReduction || false},
9744
10102
  includeSpec: ${JSON.stringify(query.includeSpec || {})},
10103
+ isArrayAgg: ${query.isArrayAgg || false},
9745
10104
  }`);
9746
10105
  }
9747
10106
  methodEntries.push(` ${JSON.stringify(method)}: {
@@ -9767,9 +10126,9 @@ function getDialectFromProvider(provider) {
9767
10126
  );
9768
10127
  }
9769
10128
  function getOutputDir(options) {
9770
- var _a, _b;
10129
+ var _a3, _b;
9771
10130
  const schemaDir = path.dirname(options.schemaPath);
9772
- if ((_a = options.generator.output) == null ? void 0 : _a.value) {
10131
+ if ((_a3 = options.generator.output) == null ? void 0 : _a3.value) {
9773
10132
  return path.resolve(schemaDir, options.generator.output.value);
9774
10133
  }
9775
10134
  const clientGenerator = options.otherGenerators.find(