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/generator.js CHANGED
@@ -2312,7 +2312,7 @@ var require_package = __commonJS({
2312
2312
  "package.json"(exports$1, module) {
2313
2313
  module.exports = {
2314
2314
  name: "prisma-sql",
2315
- version: "1.67.0",
2315
+ version: "1.68.0",
2316
2316
  description: "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
2317
2317
  main: "dist/index.cjs",
2318
2318
  module: "dist/index.js",
@@ -2793,6 +2793,8 @@ var LIMITS = Object.freeze({
2793
2793
  MAX_STRING_LENGTH: 1e4,
2794
2794
  MAX_HAVING_DEPTH: 50
2795
2795
  });
2796
+ var _a;
2797
+ var DEBUG_PARAMS = typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.DEBUG_PARAMS) === "1";
2796
2798
 
2797
2799
  // src/builder/shared/validators/type-guards.ts
2798
2800
  function isNotNullish(value) {
@@ -3336,7 +3338,7 @@ function normalizeField(field) {
3336
3338
  return field;
3337
3339
  }
3338
3340
  function getFieldIndices(model) {
3339
- var _a;
3341
+ var _a3;
3340
3342
  let cached = FIELD_INDICES_CACHE.get(model);
3341
3343
  if (cached) return cached;
3342
3344
  const scalarFields = /* @__PURE__ */ new Map();
@@ -3355,7 +3357,7 @@ function getFieldIndices(model) {
3355
3357
  } else {
3356
3358
  scalarFields.set(field.name, field);
3357
3359
  scalarNames.push(field.name);
3358
- const fieldType = String((_a = field.type) != null ? _a : "").toLowerCase();
3360
+ const fieldType = String((_a3 = field.type) != null ? _a3 : "").toLowerCase();
3359
3361
  if (fieldType === "json") {
3360
3362
  jsonFields.add(field.name);
3361
3363
  }
@@ -3453,13 +3455,13 @@ function getModelByName(schemas, name) {
3453
3455
  return schemas.find((m) => m.name === name);
3454
3456
  }
3455
3457
  function normalizeIntLike(name, v, opts = {}) {
3456
- var _a, _b;
3458
+ var _a3, _b;
3457
3459
  if (!isNotNullish(v)) return void 0;
3458
3460
  if (isDynamicParameter(v)) return v;
3459
3461
  if (typeof v !== "number" || !Number.isFinite(v) || !Number.isInteger(v)) {
3460
3462
  throw new Error(`${name} must be an integer`);
3461
3463
  }
3462
- const min = (_a = opts.min) != null ? _a : 0;
3464
+ const min = (_a3 = opts.min) != null ? _a3 : 0;
3463
3465
  const allowZero = (_b = opts.allowZero) != null ? _b : true;
3464
3466
  if (!allowZero && v === 0) {
3465
3467
  throw new Error(`${name} must be > 0`);
@@ -3481,7 +3483,9 @@ function scopeName(scope, dynamicName) {
3481
3483
  function addAutoScoped(params, value, scope) {
3482
3484
  if (isDynamicParameter(value)) {
3483
3485
  const dn = extractDynamicName(value);
3484
- console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
3486
+ if (DEBUG_PARAMS) {
3487
+ console.log(`[PARAM] ${scope} = ${JSON.stringify(value)}`);
3488
+ }
3485
3489
  return params.add(void 0, scopeName(scope, dn));
3486
3490
  }
3487
3491
  return params.add(value);
@@ -3922,7 +3926,7 @@ function assertCursorAndOrderFieldsScalar(model, cursor, orderEntries) {
3922
3926
  }
3923
3927
  }
3924
3928
  function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect, model) {
3925
- var _a;
3929
+ var _a3;
3926
3930
  assertSafeTableRef(tableName);
3927
3931
  assertSafeAlias(alias);
3928
3932
  const d = dialect != null ? dialect : getGlobalDialect();
@@ -3937,6 +3941,33 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
3937
3941
  }
3938
3942
  if (cursorEntries.length === 0)
3939
3943
  throw new Error("cursor must have at least one field with defined value");
3944
+ const orderEntries = normalizeAndValidateOrderBy(
3945
+ orderBy,
3946
+ model,
3947
+ parseOrderByValue
3948
+ );
3949
+ if (cursorEntries.length === 1 && orderEntries.length === 0) {
3950
+ const [field, value] = cursorEntries[0];
3951
+ const ph = addAutoScoped(params, value, `cursor.${field}`);
3952
+ const c = col(alias, field, model);
3953
+ return {
3954
+ cte: "",
3955
+ condition: `${c} >= ${ph}`
3956
+ };
3957
+ }
3958
+ if (cursorEntries.length === 1 && orderEntries.length === 1) {
3959
+ const [cursorField, cursorValue] = cursorEntries[0];
3960
+ const orderEntry = orderEntries[0];
3961
+ if (orderEntry.field === cursorField) {
3962
+ const ph = addAutoScoped(params, cursorValue, `cursor.${cursorField}`);
3963
+ const c = col(alias, cursorField, model);
3964
+ const op = orderEntry.direction === "asc" ? ">=" : "<=";
3965
+ return {
3966
+ cte: "",
3967
+ condition: `${c} ${op} ${ph}`
3968
+ };
3969
+ }
3970
+ }
3940
3971
  const { cteName, srcAlias } = buildCursorNames(alias);
3941
3972
  assertSafeAlias(cteName);
3942
3973
  assertSafeAlias(srcAlias);
@@ -3945,49 +3976,52 @@ function buildCursorCondition(cursor, orderBy, tableName, alias, params, dialect
3945
3976
  model,
3946
3977
  parseValue: parseOrderByValue
3947
3978
  });
3948
- let orderEntries = normalizeAndValidateOrderBy(
3979
+ let finalOrderEntries = normalizeAndValidateOrderBy(
3949
3980
  orderBy,
3950
3981
  model,
3951
3982
  parseOrderByValue
3952
3983
  );
3953
- if (orderEntries.length === 0) {
3954
- orderEntries = cursorEntries.map(([field]) => ({
3984
+ if (finalOrderEntries.length === 0) {
3985
+ finalOrderEntries = cursorEntries.map(([field]) => ({
3955
3986
  field,
3956
3987
  direction: "asc"
3957
3988
  }));
3958
3989
  } else {
3959
- orderEntries = ensureCursorFieldsInOrder(orderEntries, cursorEntries);
3990
+ finalOrderEntries = ensureCursorFieldsInOrder(
3991
+ finalOrderEntries,
3992
+ cursorEntries
3993
+ );
3960
3994
  }
3961
- assertCursorAndOrderFieldsScalar(model, cursor, orderEntries);
3995
+ assertCursorAndOrderFieldsScalar(model, cursor, finalOrderEntries);
3962
3996
  const { whereSql: cursorWhereSql } = buildCursorFilterParts(
3963
3997
  cursor,
3964
3998
  srcAlias,
3965
3999
  params,
3966
4000
  model
3967
4001
  );
3968
- const cursorOrderBy = orderEntries.map(
4002
+ const cursorOrderBy = finalOrderEntries.map(
3969
4003
  (e) => srcAlias + "." + quoteColumn(model, e.field) + " " + e.direction.toUpperCase()
3970
4004
  ).join(", ");
3971
4005
  const selectList = buildCursorCteSelectList(
3972
4006
  cursorEntries,
3973
- orderEntries,
4007
+ finalOrderEntries,
3974
4008
  model
3975
4009
  );
3976
4010
  const cte = cteName + " AS (\n SELECT " + selectList + " FROM " + tableName + " " + srcAlias + "\n WHERE " + cursorWhereSql + "\n ORDER BY " + cursorOrderBy + "\n LIMIT 1\n )";
3977
4011
  const existsExpr = "EXISTS (SELECT 1 FROM " + cteName + ")";
3978
4012
  const orClauses = [];
3979
- for (let level = 0; level < orderEntries.length; level++) {
4013
+ for (let level = 0; level < finalOrderEntries.length; level++) {
3980
4014
  const andParts = [];
3981
4015
  for (let i = 0; i < level; i++) {
3982
- const e2 = orderEntries[i];
4016
+ const e2 = finalOrderEntries[i];
3983
4017
  const c2 = col(alias, e2.field, model);
3984
4018
  const cursorField2 = cteName + "." + quoteColumn(model, e2.field);
3985
4019
  andParts.push(buildCursorEqualityExpr(c2, cursorField2));
3986
4020
  }
3987
- const e = orderEntries[level];
4021
+ const e = finalOrderEntries[level];
3988
4022
  const c = col(alias, e.field, model);
3989
4023
  const cursorField = cteName + "." + quoteColumn(model, e.field);
3990
- const nulls = (_a = e.nulls) != null ? _a : defaultNullsFor(d, e.direction);
4024
+ const nulls = (_a3 = e.nulls) != null ? _a3 : defaultNullsFor(d, e.direction);
3991
4025
  andParts.push(buildCursorInequalityExpr(c, e.direction, nulls, cursorField));
3992
4026
  orClauses.push("(" + andParts.join(SQL_SEPARATORS.CONDITION_AND) + ")");
3993
4027
  }
@@ -4533,6 +4567,16 @@ function handleJsonWildcard(expr, op, val, params, wildcards, dialect) {
4533
4567
 
4534
4568
  // src/builder/where/relations.ts
4535
4569
  var NO_JOINS = [];
4570
+ var SCHEMA_MAP_CACHE = /* @__PURE__ */ new WeakMap();
4571
+ function getSchemaByName(schemas) {
4572
+ let map = SCHEMA_MAP_CACHE.get(schemas);
4573
+ if (!map) {
4574
+ map = /* @__PURE__ */ new Map();
4575
+ for (const m of schemas) map.set(m.name, m);
4576
+ SCHEMA_MAP_CACHE.set(schemas, map);
4577
+ }
4578
+ return map;
4579
+ }
4536
4580
  function isListRelation(fieldType) {
4537
4581
  return typeof fieldType === "string" && fieldType.endsWith("[]");
4538
4582
  }
@@ -4732,7 +4776,8 @@ function buildRelation(fieldName, value, ctx, whereBuilder) {
4732
4776
  modelName: ctx.model.name
4733
4777
  });
4734
4778
  }
4735
- const relModel = ctx.schemaModels.find((m) => m.name === field.relatedModel);
4779
+ const schemaMap = getSchemaByName(ctx.schemaModels);
4780
+ const relModel = schemaMap.get(field.relatedModel);
4736
4781
  if (!isNotNullish(relModel)) {
4737
4782
  throw createError(
4738
4783
  `Related model '${field.relatedModel}' not found in schema. Available models: ${ctx.schemaModels.map((m) => m.name).join(", ")}`,
@@ -5063,6 +5108,8 @@ function createAliasGenerator(maxAliases = 1e4) {
5063
5108
  };
5064
5109
  }
5065
5110
  var MAX_PARAM_INDEX = Number.MAX_SAFE_INTEGER - 1e3;
5111
+ var _a2;
5112
+ var IS_PRODUCTION2 = typeof process !== "undefined" && ((_a2 = process.env) == null ? void 0 : _a2.NODE_ENV) === "production";
5066
5113
  function assertSameLength(params, mappings) {
5067
5114
  if (params.length !== mappings.length) {
5068
5115
  throw new Error(
@@ -5122,6 +5169,11 @@ function validateMappings(mappings) {
5122
5169
  }
5123
5170
  }
5124
5171
  function validateState(params, mappings, index) {
5172
+ if (IS_PRODUCTION2) {
5173
+ assertSameLength(params, mappings);
5174
+ assertValidNextIndex(index);
5175
+ return;
5176
+ }
5125
5177
  assertSameLength(params, mappings);
5126
5178
  assertValidNextIndex(index);
5127
5179
  if (mappings.length === 0) return;
@@ -5276,10 +5328,10 @@ function toPublicResult(clause, joins, params) {
5276
5328
 
5277
5329
  // src/builder/where.ts
5278
5330
  function buildWhereClause(where, options) {
5279
- var _a, _b, _c, _d, _e;
5331
+ var _a3, _b, _c, _d, _e;
5280
5332
  assertSafeAlias(options.alias);
5281
5333
  const dialect = options.dialect || getGlobalDialect();
5282
- const params = (_a = options.params) != null ? _a : createParamStore(1, dialect);
5334
+ const params = (_a3 = options.params) != null ? _a3 : createParamStore(1, dialect);
5283
5335
  const ctx = {
5284
5336
  alias: options.alias,
5285
5337
  model: options.model,
@@ -5338,8 +5390,8 @@ function buildDefaultScalarFields(model, alias) {
5338
5390
  return out;
5339
5391
  }
5340
5392
  function getDefaultSelectCached(model, alias) {
5341
- var _a;
5342
- return (_a = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a.get(alias);
5393
+ var _a3;
5394
+ return (_a3 = DEFAULT_SELECT_CACHE.get(model)) == null ? void 0 : _a3.get(alias);
5343
5395
  }
5344
5396
  function cacheDefaultSelect(model, alias, sql) {
5345
5397
  let cache = DEFAULT_SELECT_CACHE.get(model);
@@ -5436,7 +5488,8 @@ function buildRelationSelect(relArgs, relModel, relAlias) {
5436
5488
  }
5437
5489
 
5438
5490
  // src/builder/shared/relation-key-utils.ts
5439
- function resolveRelationKeys(field, context = "include") {
5491
+ var RELATION_KEYS_CACHE = /* @__PURE__ */ new WeakMap();
5492
+ function computeRelationKeys(field, context) {
5440
5493
  const fkFields = normalizeKeyList(field.foreignKey);
5441
5494
  if (fkFields.length === 0) {
5442
5495
  throw new Error(
@@ -5454,6 +5507,13 @@ function resolveRelationKeys(field, context = "include") {
5454
5507
  const parentKeys = field.isForeignKeyLocal ? fkFields : refFields;
5455
5508
  return { childKeys, parentKeys };
5456
5509
  }
5510
+ function resolveRelationKeys(field, context = "include") {
5511
+ let cached = RELATION_KEYS_CACHE.get(field);
5512
+ if (cached) return cached;
5513
+ cached = computeRelationKeys(field, context);
5514
+ RELATION_KEYS_CACHE.set(field, cached);
5515
+ return cached;
5516
+ }
5457
5517
 
5458
5518
  // src/builder/shared/relation-extraction-utils.ts
5459
5519
  function extractRelationEntries(args, model) {
@@ -5483,6 +5543,18 @@ function extractRelationEntries(args, model) {
5483
5543
  var MAX_INCLUDE_DEPTH = 5;
5484
5544
  var MAX_INCLUDES_PER_LEVEL = 10;
5485
5545
  var MAX_TOTAL_SUBQUERIES = 100;
5546
+ var FIELD_BY_NAME_CACHE2 = /* @__PURE__ */ new WeakMap();
5547
+ function getFieldMap(model) {
5548
+ let map = FIELD_BY_NAME_CACHE2.get(model);
5549
+ if (!map) {
5550
+ map = /* @__PURE__ */ new Map();
5551
+ for (const f of model.fields) {
5552
+ map.set(f.name, f);
5553
+ }
5554
+ FIELD_BY_NAME_CACHE2.set(model, map);
5555
+ }
5556
+ return map;
5557
+ }
5486
5558
  function buildIncludeScope(includePath) {
5487
5559
  if (includePath.length === 0) return "include";
5488
5560
  let scope = "include";
@@ -5502,7 +5574,8 @@ function getRelationTableReference(relModel, dialect) {
5502
5574
  );
5503
5575
  }
5504
5576
  function resolveRelationOrThrow(model, schemaByName, relName) {
5505
- const field = model.fields.find((f) => f.name === relName);
5577
+ const fieldMap = getFieldMap(model);
5578
+ const field = fieldMap.get(relName);
5506
5579
  if (!isNotNullish(field)) {
5507
5580
  throw new Error(
5508
5581
  `Unknown relation '${relName}' on model ${model.name}. Available relation fields: ${model.fields.filter((f) => f.isRelation).map((f) => f.name).join(", ")}`
@@ -5619,11 +5692,22 @@ function finalizeOrderByForInclude(args) {
5619
5692
  }
5620
5693
  function buildSelectWithNestedIncludes(relArgs, relModel, relAlias, ctx) {
5621
5694
  let relSelect = buildRelationSelect(relArgs, relModel, relAlias);
5622
- const nestedIncludes = isPlainObject(relArgs) ? buildIncludeSqlInternal(relArgs, __spreadProps(__spreadValues({}, ctx), {
5623
- model: relModel,
5624
- parentAlias: relAlias,
5625
- depth: ctx.depth + 1
5626
- })) : [];
5695
+ let nestedIncludes = [];
5696
+ if (isPlainObject(relArgs)) {
5697
+ const prevModel = ctx.model;
5698
+ const prevParentAlias = ctx.parentAlias;
5699
+ const prevDepth = ctx.depth;
5700
+ ctx.model = relModel;
5701
+ ctx.parentAlias = relAlias;
5702
+ ctx.depth = prevDepth + 1;
5703
+ try {
5704
+ nestedIncludes = buildIncludeSqlInternal(relArgs, ctx);
5705
+ } finally {
5706
+ ctx.model = prevModel;
5707
+ ctx.parentAlias = prevParentAlias;
5708
+ ctx.depth = prevDepth;
5709
+ }
5710
+ }
5627
5711
  if (isNonEmptyArray(nestedIncludes)) {
5628
5712
  const emptyJson = ctx.dialect === "postgres" ? `'[]'::json` : `json('[]')`;
5629
5713
  const nestedSelects = nestedIncludes.map(
@@ -6020,16 +6104,22 @@ function buildIncludeSqlInternal(args, ctx) {
6020
6104
  `Circular include detected: ${Array.from(ctx.visitSet).join(" -> ")} -> ${relationPath}. Relation '${relationPath}' creates an infinite loop.`
6021
6105
  );
6022
6106
  }
6023
- const nextIncludePath = [...ctx.includePath, relName];
6024
- const nextVisitSet = new Set(ctx.visitSet);
6025
- nextVisitSet.add(relationPath);
6026
- includes.push(
6027
- buildSingleInclude(relName, relArgs, resolved.field, resolved.relModel, __spreadProps(__spreadValues({}, ctx), {
6028
- includePath: nextIncludePath,
6029
- visitSet: nextVisitSet,
6030
- depth
6031
- }))
6032
- );
6107
+ ctx.includePath.push(relName);
6108
+ ctx.visitSet.add(relationPath);
6109
+ try {
6110
+ includes.push(
6111
+ buildSingleInclude(
6112
+ relName,
6113
+ relArgs,
6114
+ resolved.field,
6115
+ resolved.relModel,
6116
+ ctx
6117
+ )
6118
+ );
6119
+ } finally {
6120
+ ctx.includePath.pop();
6121
+ ctx.visitSet.delete(relationPath);
6122
+ }
6033
6123
  }
6034
6124
  return includes;
6035
6125
  }
@@ -6313,10 +6403,19 @@ function canUseNestedFlatJoin(relArgs, depth) {
6313
6403
  }
6314
6404
  return true;
6315
6405
  }
6316
- function canUseFlatJoinForAll(includeSpec) {
6317
- for (const value of Object.values(includeSpec)) {
6406
+ function canUseFlatJoinForAll(includeSpec, parentModel, schemas) {
6407
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
6408
+ for (const [relName, value] of Object.entries(includeSpec)) {
6318
6409
  if (value === false) continue;
6410
+ const field = parentModel.fields.find((f) => f.name === relName);
6411
+ if (!field || !field.isRelation) continue;
6319
6412
  if (!canUseNestedFlatJoin(value, 0)) return false;
6413
+ const relModel = modelMap.get(field.relatedModel);
6414
+ if (!relModel) continue;
6415
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
6416
+ if (Object.keys(nestedSpec).length > 0) {
6417
+ if (!canUseFlatJoinForAll(nestedSpec, relModel, schemas)) return false;
6418
+ }
6320
6419
  }
6321
6420
  return true;
6322
6421
  }
@@ -6413,7 +6512,7 @@ function buildFlatJoinSql(spec) {
6413
6512
  if (Object.keys(includeSpec).length === 0) {
6414
6513
  return { sql: "", requiresReduction: false, includeSpec: {} };
6415
6514
  }
6416
- if (!canUseFlatJoinForAll(includeSpec)) {
6515
+ if (!canUseFlatJoinForAll(includeSpec, model, schemas)) {
6417
6516
  return { sql: "", requiresReduction: false, includeSpec: {} };
6418
6517
  }
6419
6518
  const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
@@ -6459,6 +6558,217 @@ function buildFlatJoinSql(spec) {
6459
6558
  `.trim();
6460
6559
  return { sql, requiresReduction: true, includeSpec };
6461
6560
  }
6561
+
6562
+ // src/builder/select/array-agg.ts
6563
+ function canUseArrayAggForAll(includeSpec, parentModel, schemas) {
6564
+ const modelMap = new Map(schemas.map((m) => [m.name, m]));
6565
+ for (const [relName, value] of Object.entries(includeSpec)) {
6566
+ if (value === false) continue;
6567
+ const field = parentModel.fields.find((f) => f.name === relName);
6568
+ if (!field || !field.isRelation) continue;
6569
+ if (isPlainObject(value) && hasChildPagination(value)) return false;
6570
+ const relModel = modelMap.get(field.relatedModel);
6571
+ if (!relModel) continue;
6572
+ const nestedSpec = extractNestedIncludeSpec(value, relModel);
6573
+ if (Object.keys(nestedSpec).length > 0) return false;
6574
+ }
6575
+ return true;
6576
+ }
6577
+ function getRelationModel2(parentModel, relationName, schemas) {
6578
+ const field = parentModel.fields.find((f) => f.name === relationName);
6579
+ if (!(field == null ? void 0 : field.isRelation) || !field.relatedModel) {
6580
+ throw new Error(`Invalid relation ${relationName} on ${parentModel.name}`);
6581
+ }
6582
+ const relModel = schemas.find((m) => m.name === field.relatedModel);
6583
+ if (!relModel) {
6584
+ throw new Error(`Related model ${field.relatedModel} not found`);
6585
+ }
6586
+ return relModel;
6587
+ }
6588
+ function buildSubqueryRawSelect2(model, alias) {
6589
+ const cols = [];
6590
+ for (const f of model.fields) {
6591
+ if (f.isRelation) continue;
6592
+ cols.push(`${alias}.${quoteColumn(model, f.name)}`);
6593
+ }
6594
+ return cols.length > 0 ? cols.join(SQL_SEPARATORS.FIELD_LIST) : "*";
6595
+ }
6596
+ function readWhereInput2(relArgs) {
6597
+ if (!isPlainObject(relArgs)) return {};
6598
+ const obj = relArgs;
6599
+ if (!("where" in obj)) return {};
6600
+ const w = obj.where;
6601
+ return isPlainObject(w) ? w : {};
6602
+ }
6603
+ function buildArrayAggRelation(args) {
6604
+ const {
6605
+ relationName,
6606
+ relArgs,
6607
+ field,
6608
+ relModel,
6609
+ parentModel,
6610
+ parentAlias,
6611
+ schemas,
6612
+ dialect,
6613
+ aliasCounter,
6614
+ params
6615
+ } = args;
6616
+ const isList = typeof field.type === "string" && field.type.endsWith("[]");
6617
+ const { childKeys: relKeyFields, parentKeys: parentKeyFields } = resolveRelationKeys(field, "include");
6618
+ if (relKeyFields.length === 0) return null;
6619
+ const innerAlias = `__aa_r${aliasCounter.count++}`;
6620
+ const joinAlias = `__aa_j${aliasCounter.count++}`;
6621
+ const indices = getFieldIndices(relModel);
6622
+ const scalarSel = extractScalarSelection(relArgs, relModel);
6623
+ const pkFields = getPrimaryKeyFields(relModel);
6624
+ const selectedFields = scalarSel.includeAllScalars ? Array.from(indices.scalarFields.keys()) : [.../* @__PURE__ */ new Set([...pkFields, ...scalarSel.selectedScalarFields])];
6625
+ const pkOrderExpr = pkFields.map((f) => `${innerAlias}.${quoteColumn(relModel, f)}`).join(SQL_SEPARATORS.FIELD_LIST);
6626
+ const pkFilterExpr = `${innerAlias}.${quoteColumn(relModel, pkFields[0])}`;
6627
+ const fkSelectParts = relKeyFields.map(
6628
+ (f, i) => `${innerAlias}.${quoteColumn(relModel, f)} AS "__fk${i}"`
6629
+ );
6630
+ const aggParts = selectedFields.map((fieldName) => {
6631
+ const f = indices.scalarFields.get(fieldName);
6632
+ if (!f) return null;
6633
+ const colRef = `${innerAlias}.${quoteColumn(relModel, fieldName)}`;
6634
+ const alias = `"${relationName}.${f.name}"`;
6635
+ return `array_agg(${colRef} ORDER BY ${pkOrderExpr}) FILTER (WHERE ${pkFilterExpr} IS NOT NULL) AS ${alias}`;
6636
+ }).filter(Boolean);
6637
+ const fkGroupByParts = relKeyFields.map(
6638
+ (f) => `${innerAlias}.${quoteColumn(relModel, f)}`
6639
+ );
6640
+ const relTable = buildTableReference(
6641
+ SQL_TEMPLATES.PUBLIC_SCHEMA,
6642
+ relModel.tableName,
6643
+ dialect
6644
+ );
6645
+ const whereInput = readWhereInput2(relArgs);
6646
+ let whereJoinsSql = "";
6647
+ let whereClauseSql = "";
6648
+ if (Object.keys(whereInput).length > 0) {
6649
+ const aliasGen = createAliasGenerator();
6650
+ const whereResult = buildWhereClause(whereInput, {
6651
+ alias: innerAlias,
6652
+ schemaModels: schemas,
6653
+ model: relModel,
6654
+ params,
6655
+ isSubquery: true,
6656
+ aliasGen,
6657
+ dialect
6658
+ });
6659
+ if (whereResult.joins.length > 0) {
6660
+ whereJoinsSql = " " + whereResult.joins.join(" ");
6661
+ }
6662
+ if (isValidWhereClause(whereResult.clause)) {
6663
+ whereClauseSql = ` ${SQL_TEMPLATES.WHERE} ${whereResult.clause}`;
6664
+ }
6665
+ }
6666
+ 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)}`;
6667
+ const onParts = parentKeyFields.map(
6668
+ (f, i) => `${joinAlias}."__fk${i}" = ${parentAlias}.${quoteColumn(parentModel, f)}`
6669
+ );
6670
+ const onCondition = onParts.length === 1 ? onParts[0] : `(${onParts.join(" AND ")})`;
6671
+ const joinSql = `LEFT JOIN (${subquery}) ${joinAlias} ON ${onCondition}`;
6672
+ const selectExprs = selectedFields.map((fieldName) => {
6673
+ const f = indices.scalarFields.get(fieldName);
6674
+ if (!f) return null;
6675
+ return `${joinAlias}."${relationName}.${f.name}"`;
6676
+ }).filter(Boolean);
6677
+ return {
6678
+ joinSql,
6679
+ selectExprs,
6680
+ relationName,
6681
+ isList,
6682
+ scalarFieldNames: selectedFields
6683
+ };
6684
+ }
6685
+ function buildArrayAggSql(spec) {
6686
+ const {
6687
+ select: select2,
6688
+ from,
6689
+ whereClause,
6690
+ whereJoins,
6691
+ orderBy,
6692
+ dialect,
6693
+ model,
6694
+ schemas,
6695
+ args,
6696
+ params
6697
+ } = spec;
6698
+ const entries = extractRelationEntries(args, model);
6699
+ const includeSpec = {};
6700
+ for (const e of entries) {
6701
+ includeSpec[e.name] = e.value;
6702
+ }
6703
+ if (Object.keys(includeSpec).length === 0) {
6704
+ return {
6705
+ sql: "",
6706
+ requiresReduction: false,
6707
+ includeSpec: {},
6708
+ isArrayAgg: false
6709
+ };
6710
+ }
6711
+ if (!canUseArrayAggForAll(includeSpec, model, schemas)) {
6712
+ return {
6713
+ sql: "",
6714
+ requiresReduction: false,
6715
+ includeSpec: {},
6716
+ isArrayAgg: false
6717
+ };
6718
+ }
6719
+ const baseJoins = whereJoins.length > 0 ? whereJoins.join(" ") : "";
6720
+ const baseWhere = whereClause && whereClause !== "1=1" ? `WHERE ${whereClause}` : "";
6721
+ const baseOrderBy = orderBy ? `ORDER BY ${orderBy}` : "";
6722
+ const subqueryScalarCols = buildSubqueryRawSelect2(model, from.alias);
6723
+ let baseSubquery = `SELECT ${subqueryScalarCols} FROM ${from.table} ${from.alias}` + (baseJoins ? ` ${baseJoins}` : "") + (baseWhere ? ` ${baseWhere}` : "") + (baseOrderBy ? ` ${baseOrderBy}` : "");
6724
+ baseSubquery = appendPagination(baseSubquery.trim(), spec);
6725
+ const aliasCounter = { count: 0 };
6726
+ const joins = [];
6727
+ const arraySelectExprs = [];
6728
+ for (const [relName, relValue] of Object.entries(includeSpec)) {
6729
+ if (relValue === false) continue;
6730
+ const field = model.fields.find((f) => f.name === relName);
6731
+ if (!field || !isValidRelationField(field)) continue;
6732
+ const relModel = getRelationModel2(model, relName, schemas);
6733
+ const built = buildArrayAggRelation({
6734
+ relationName: relName,
6735
+ relArgs: relValue,
6736
+ field,
6737
+ relModel,
6738
+ parentModel: model,
6739
+ parentAlias: from.alias,
6740
+ schemas,
6741
+ dialect,
6742
+ aliasCounter,
6743
+ params
6744
+ });
6745
+ if (!built) continue;
6746
+ joins.push(built.joinSql);
6747
+ arraySelectExprs.push(...built.selectExprs);
6748
+ }
6749
+ if (joins.length === 0) {
6750
+ return {
6751
+ sql: "",
6752
+ requiresReduction: false,
6753
+ includeSpec: {},
6754
+ isArrayAgg: false
6755
+ };
6756
+ }
6757
+ const baseSelect = (select2 != null ? select2 : "").trim();
6758
+ const allSelects = [baseSelect, ...arraySelectExprs].filter((s) => s && s.trim().length > 0).join(SQL_SEPARATORS.FIELD_LIST);
6759
+ if (!allSelects) {
6760
+ throw new Error("Array-agg SELECT requires at least one selected field");
6761
+ }
6762
+ const pkField = getPrimaryKeyField(model);
6763
+ const pkOrder = `${from.alias}.${quoteColumn(model, pkField)} ASC`;
6764
+ const sql = `
6765
+ SELECT ${allSelects}
6766
+ FROM (${baseSubquery}) ${from.alias}
6767
+ ${joins.join(" ")}
6768
+ ORDER BY ${pkOrder}
6769
+ `.trim();
6770
+ return { sql, requiresReduction: true, includeSpec, isArrayAgg: true };
6771
+ }
6462
6772
  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;
6463
6773
  function buildWhereSql(conditions) {
6464
6774
  if (!isNonEmptyArray(conditions)) return "";
@@ -6546,47 +6856,45 @@ function buildOutputColumns(scalarNames, includeNames, hasCount) {
6546
6856
  }
6547
6857
  return formatted;
6548
6858
  }
6549
- function buildWindowOrder(args) {
6550
- const { baseOrder, idField, fromAlias, model } = args;
6551
- const fromLower = String(fromAlias).toLowerCase();
6552
- const orderFields = baseOrder.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim().toLowerCase().replace(/\s+/g, " "));
6553
- const hasIdInOrder = orderFields.some((f) => {
6554
- return f.includes(`${fromLower}.id`) || f.includes(`${fromLower}."id"`);
6555
- });
6556
- if (hasIdInOrder) return baseOrder;
6557
- const idTiebreaker = idField ? ", " + col(fromAlias, "id", model) + " ASC" : "";
6558
- return baseOrder + idTiebreaker;
6559
- }
6560
- function extractDistinctOrderEntries(spec) {
6561
- if (isNotNullish(spec.args.orderBy)) {
6562
- const normalized = normalizeOrderByInput(
6563
- spec.args.orderBy,
6564
- parseOrderByValue
6565
- );
6566
- const entries = [];
6567
- for (const item of normalized) {
6568
- for (const field in item) {
6569
- if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
6570
- const value = item[field];
6571
- if (typeof value === "string") {
6572
- entries.push({ field, direction: value });
6573
- continue;
6574
- }
6575
- const obj = value;
6576
- entries.push({ field, direction: obj.direction, nulls: obj.nulls });
6859
+ function getOrderByEntries(spec) {
6860
+ if (!isNotNullish(spec.args.orderBy)) return [];
6861
+ const normalized = normalizeOrderByInput(spec.args.orderBy, parseOrderByValue);
6862
+ const entries = [];
6863
+ for (const item of normalized) {
6864
+ for (const field in item) {
6865
+ if (!Object.prototype.hasOwnProperty.call(item, field)) continue;
6866
+ const value = item[field];
6867
+ if (typeof value === "string") {
6868
+ entries.push({ field, direction: value });
6869
+ continue;
6577
6870
  }
6871
+ const obj = value;
6872
+ entries.push({ field, direction: obj.direction, nulls: obj.nulls });
6578
6873
  }
6579
- if (entries.length > 0) return entries;
6580
6874
  }
6581
- if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
6582
- return [...spec.distinct].map((f) => ({
6583
- field: f,
6584
- direction: "asc"
6585
- }));
6875
+ return entries;
6876
+ }
6877
+ function renderOrderBySql(entries, alias, dialect, model) {
6878
+ if (entries.length === 0) return "";
6879
+ const out = [];
6880
+ for (const e of entries) {
6881
+ const dir = e.direction.toUpperCase();
6882
+ const c = col(alias, e.field, model);
6883
+ if (dialect === "postgres") {
6884
+ const nulls = isNotNullish(e.nulls) ? ` NULLS ${e.nulls.toUpperCase()}` : "";
6885
+ out.push(c + " " + dir + nulls);
6886
+ } else if (isNotNullish(e.nulls)) {
6887
+ const isNullExpr = `(${c} IS NULL)`;
6888
+ const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
6889
+ out.push(isNullExpr + " " + nullRankDir);
6890
+ out.push(c + " " + dir);
6891
+ } else {
6892
+ out.push(c + " " + dir);
6893
+ }
6586
6894
  }
6587
- return [];
6895
+ return out.join(SQL_SEPARATORS.ORDER_BY);
6588
6896
  }
6589
- function buildFieldNameOrderBy(entries, alias) {
6897
+ function renderOrderBySimple(entries, alias) {
6590
6898
  if (entries.length === 0) return "";
6591
6899
  const out = [];
6592
6900
  for (const e of entries) {
@@ -6597,40 +6905,73 @@ function buildFieldNameOrderBy(entries, alias) {
6597
6905
  const nullRankDir = e.nulls === "first" ? "DESC" : "ASC";
6598
6906
  out.push(isNullExpr + " " + nullRankDir);
6599
6907
  out.push(c + " " + dir);
6600
- continue;
6908
+ } else {
6909
+ out.push(c + " " + dir);
6601
6910
  }
6602
- out.push(c + " " + dir);
6603
6911
  }
6604
6912
  return out.join(SQL_SEPARATORS.ORDER_BY);
6605
6913
  }
6914
+ function ensureIdTiebreakerEntries(entries, model) {
6915
+ var _a3, _b;
6916
+ const idField = (_b = (_a3 = model == null ? void 0 : model.fields) == null ? void 0 : _a3.find) == null ? void 0 : _b.call(
6917
+ _a3,
6918
+ (f) => f.name === "id" && !f.isRelation
6919
+ );
6920
+ if (!idField) return entries;
6921
+ if (entries.some((e) => e.field === "id")) return entries;
6922
+ return [...entries, { field: "id", direction: "asc" }];
6923
+ }
6924
+ function ensurePostgresDistinctOrderEntries(args) {
6925
+ const { entries, distinct, model } = args;
6926
+ const distinctEntries = [...distinct].map((f) => ({
6927
+ field: f,
6928
+ direction: "asc"
6929
+ }));
6930
+ const canKeepAsIs = entries.length >= distinctEntries.length && distinctEntries.every((de, i) => entries[i].field === de.field);
6931
+ const merged = canKeepAsIs ? entries : [...distinctEntries, ...entries];
6932
+ return ensureIdTiebreakerEntries(merged, model);
6933
+ }
6934
+ function extractDistinctOrderEntries(spec) {
6935
+ const entries = getOrderByEntries(spec);
6936
+ if (entries.length > 0) return entries;
6937
+ if (isNotNullish(spec.distinct) && isNonEmptyArray(spec.distinct)) {
6938
+ return [...spec.distinct].map((f) => ({
6939
+ field: f,
6940
+ direction: "asc"
6941
+ }));
6942
+ }
6943
+ return [];
6944
+ }
6606
6945
  function buildSqliteDistinctQuery(spec, selectWithIncludes, countJoins) {
6607
- var _a, _b;
6608
- const { includes, from, whereClause, whereJoins, orderBy, distinct, model } = spec;
6946
+ var _a3, _b;
6947
+ const { includes, from, whereClause, whereJoins, distinct, model } = spec;
6609
6948
  if (!isNotNullish(distinct) || !isNonEmptyArray(distinct)) {
6610
6949
  throw new Error("buildSqliteDistinctQuery requires distinct fields");
6611
6950
  }
6612
6951
  const scalarNames = parseSimpleScalarSelect(spec.select, from.alias);
6613
6952
  const includeNames = includes.map((i) => i.name);
6614
- const hasCount = Boolean((_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count);
6953
+ const hasCount = Boolean((_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count);
6615
6954
  const outerSelectCols = buildOutputColumns(
6616
6955
  scalarNames,
6617
6956
  includeNames,
6618
6957
  hasCount
6619
6958
  );
6620
6959
  const distinctCols = buildDistinctColumns([...distinct], from.alias, model);
6621
- const fallbackOrder = [...distinct].map((f) => col(from.alias, f, model) + " ASC").join(SQL_SEPARATORS.FIELD_LIST);
6622
- const idField = model.fields.find(
6623
- (f) => f.name === "id" && !f.isRelation
6624
- );
6625
- const baseOrder = isNonEmptyString(orderBy) ? orderBy : fallbackOrder;
6626
- const windowOrder = buildWindowOrder({
6627
- baseOrder,
6628
- idField,
6629
- fromAlias: from.alias,
6960
+ const baseEntries = getOrderByEntries(spec);
6961
+ const fallbackEntries = [...distinct].map((f) => ({
6962
+ field: f,
6963
+ direction: "asc"
6964
+ }));
6965
+ const resolvedEntries = baseEntries.length > 0 ? baseEntries : fallbackEntries;
6966
+ const windowEntries = ensureIdTiebreakerEntries(resolvedEntries, model);
6967
+ const windowOrder = renderOrderBySql(
6968
+ windowEntries,
6969
+ from.alias,
6970
+ "sqlite",
6630
6971
  model
6631
- });
6972
+ );
6632
6973
  const outerEntries = extractDistinctOrderEntries(spec);
6633
- const outerOrder = buildFieldNameOrderBy(outerEntries, '"__tp_distinct"');
6974
+ const outerOrder = renderOrderBySimple(outerEntries, '"__tp_distinct"');
6634
6975
  const joins = buildJoinsSql(whereJoins, countJoins);
6635
6976
  const conditions = [];
6636
6977
  if (whereClause && whereClause !== "1=1") conditions.push(whereClause);
@@ -6681,12 +7022,12 @@ function resolveCountSelect(countSelectRaw, model) {
6681
7022
  return null;
6682
7023
  }
6683
7024
  function buildIncludeColumns(spec) {
6684
- var _a, _b;
7025
+ var _a3, _b;
6685
7026
  const { select: select2, includes, dialect, model, schemas, from, params } = spec;
6686
7027
  const baseSelect = (select2 != null ? select2 : "").trim();
6687
7028
  let countCols = "";
6688
7029
  let countJoins = [];
6689
- const countSelectRaw = (_b = (_a = spec.args) == null ? void 0 : _a.select) == null ? void 0 : _b._count;
7030
+ const countSelectRaw = (_b = (_a3 = spec.args) == null ? void 0 : _a3.select) == null ? void 0 : _b._count;
6690
7031
  if (countSelectRaw) {
6691
7032
  const resolvedCountSelect = resolveCountSelect(countSelectRaw, model);
6692
7033
  if (resolvedCountSelect && Object.keys(resolvedCountSelect).length > 0) {
@@ -6845,37 +7186,6 @@ function extractIncludeSpec(args) {
6845
7186
  function hasNestedIncludes(includeSpec) {
6846
7187
  return Object.keys(includeSpec).length > 0;
6847
7188
  }
6848
- function splitOrderByTerms(orderBy) {
6849
- const raw = orderBy.trim();
6850
- if (raw.length === 0) return [];
6851
- return raw.split(SQL_SEPARATORS.ORDER_BY).map((s) => s.trim()).filter((s) => s.length > 0);
6852
- }
6853
- function hasIdInOrderBy(orderBy, fromAlias) {
6854
- const lower = orderBy.toLowerCase();
6855
- const aliasLower = fromAlias.toLowerCase();
6856
- return lower.includes(`${aliasLower}.id `) || lower.includes(`${aliasLower}."id"`);
6857
- }
6858
- function ensureIdTiebreakerOrderBy(orderBy, fromAlias, model) {
6859
- var _a, _b;
6860
- const idField = (_b = (_a = model == null ? void 0 : model.fields) == null ? void 0 : _a.find) == null ? void 0 : _b.call(
6861
- _a,
6862
- (f) => f.name === "id" && !f.isRelation
6863
- );
6864
- if (!idField) return orderBy;
6865
- if (hasIdInOrderBy(orderBy, fromAlias)) return orderBy;
6866
- const t = col(fromAlias, "id", model) + " ASC";
6867
- return isNonEmptyString(orderBy) ? orderBy + ", " + t : t;
6868
- }
6869
- function ensurePostgresDistinctOrderBy(args) {
6870
- const { orderBy, distinct, fromAlias, model } = args;
6871
- const distinctTerms = distinct.map((f) => col(fromAlias, f, model) + " ASC");
6872
- const existing = splitOrderByTerms(orderBy);
6873
- const canKeepAsIs = existing.length >= distinctTerms.length && distinctTerms.every(
6874
- (term, i) => existing[i].toLowerCase().startsWith(term.split(" ASC")[0].toLowerCase())
6875
- );
6876
- const merged = canKeepAsIs ? orderBy : [...distinctTerms, ...existing].join(SQL_SEPARATORS.ORDER_BY);
6877
- return ensureIdTiebreakerOrderBy(merged, fromAlias, model);
6878
- }
6879
7189
  function constructFinalSql(spec) {
6880
7190
  const {
6881
7191
  select: select2,
@@ -6890,7 +7200,6 @@ function constructFinalSql(spec) {
6890
7200
  params,
6891
7201
  dialect,
6892
7202
  model,
6893
- includes,
6894
7203
  schemas,
6895
7204
  pagination,
6896
7205
  args
@@ -6902,7 +7211,24 @@ function constructFinalSql(spec) {
6902
7211
  const includeSpec = extractIncludeSpec(args);
6903
7212
  const hasIncludes = hasNestedIncludes(includeSpec);
6904
7213
  const hasPagination = isNotNullish(pagination.take);
6905
- const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec);
7214
+ const takeValue = typeof pagination.take === "number" ? pagination.take : null;
7215
+ const isLargeTake = takeValue !== null && takeValue > 50;
7216
+ const shouldUseArrayAgg = dialect === "postgres" && hasIncludes && method === "findMany" && hasPagination && isLargeTake && canUseArrayAggForAll(includeSpec, model, schemas);
7217
+ if (shouldUseArrayAgg) {
7218
+ const aaResult = buildArrayAggSql(spec);
7219
+ if (aaResult.sql) {
7220
+ const baseSqlResult = finalizeSql(aaResult.sql, params, dialect);
7221
+ return {
7222
+ sql: baseSqlResult.sql,
7223
+ params: baseSqlResult.params,
7224
+ paramMappings: baseSqlResult.paramMappings,
7225
+ requiresReduction: true,
7226
+ includeSpec: aaResult.includeSpec,
7227
+ isArrayAgg: true
7228
+ };
7229
+ }
7230
+ }
7231
+ const shouldUseFlatJoin = dialect === "postgres" && hasPagination && hasIncludes && canUseFlatJoinForAll(includeSpec, model, schemas);
6906
7232
  if (shouldUseFlatJoin) {
6907
7233
  const flatResult = buildFlatJoinSql(spec);
6908
7234
  if (flatResult.sql) {
@@ -6948,12 +7274,13 @@ function constructFinalSql(spec) {
6948
7274
  pushWhere(parts, conditions);
6949
7275
  let finalOrderBy = orderBy;
6950
7276
  if (dialect === "postgres" && isNonEmptyArray(distinct)) {
6951
- finalOrderBy = ensurePostgresDistinctOrderBy({
6952
- orderBy: orderBy || "",
7277
+ const currentEntries = getOrderByEntries(spec);
7278
+ const mergedEntries = ensurePostgresDistinctOrderEntries({
7279
+ entries: currentEntries.length > 0 ? currentEntries : [],
6953
7280
  distinct: [...distinct],
6954
- fromAlias: from.alias,
6955
7281
  model
6956
7282
  });
7283
+ finalOrderBy = renderOrderBySql(mergedEntries, from.alias, dialect, model);
6957
7284
  }
6958
7285
  if (isNonEmptyString(finalOrderBy))
6959
7286
  parts.push(SQL_TEMPLATES.ORDER_BY, finalOrderBy);
@@ -6979,11 +7306,11 @@ function mapFirstOrderByByField(existing) {
6979
7306
  return m;
6980
7307
  }
6981
7308
  function buildPostgresDistinctOrderBy(distinctFields, existing) {
6982
- var _a;
7309
+ var _a3;
6983
7310
  const firstByField = mapFirstOrderByByField(existing);
6984
7311
  const next = [];
6985
7312
  for (const f of distinctFields) {
6986
- next.push((_a = firstByField.get(f)) != null ? _a : { [f]: "asc" });
7313
+ next.push((_a3 = firstByField.get(f)) != null ? _a3 : { [f]: "asc" });
6987
7314
  }
6988
7315
  const distinctSet = new Set(distinctFields);
6989
7316
  for (const obj of existing) {
@@ -7809,10 +8136,10 @@ function isPrismaMethod(v) {
7809
8136
  return v === "findMany" || v === "findFirst" || v === "findUnique" || v === "aggregate" || v === "groupBy" || v === "count";
7810
8137
  }
7811
8138
  function resolveMethod(directive) {
7812
- var _a, _b;
8139
+ var _a3, _b;
7813
8140
  const m = directive == null ? void 0 : directive.method;
7814
8141
  if (isPrismaMethod(m)) return m;
7815
- const pm = (_b = (_a = directive == null ? void 0 : directive.query) == null ? void 0 : _a.processed) == null ? void 0 : _b.method;
8142
+ const pm = (_b = (_a3 = directive == null ? void 0 : directive.query) == null ? void 0 : _a3.processed) == null ? void 0 : _b.method;
7816
8143
  if (isPrismaMethod(pm)) return pm;
7817
8144
  return "findMany";
7818
8145
  }
@@ -7973,7 +8300,7 @@ function extractIncludeSpec2(processed, modelDef) {
7973
8300
  return includeSpec;
7974
8301
  }
7975
8302
  function buildAndNormalizeSql(args) {
7976
- var _a;
8303
+ var _a3;
7977
8304
  const {
7978
8305
  method,
7979
8306
  processed,
@@ -7999,13 +8326,15 @@ function buildAndNormalizeSql(args) {
7999
8326
  sqlResult.paramMappings,
8000
8327
  dialect
8001
8328
  );
8002
- const includeSpec = (_a = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a : extractIncludeSpec2(processed, modelDef);
8329
+ const includeSpec = (_a3 = sqlResult.includeSpec && isPlainObject(sqlResult.includeSpec) ? sqlResult.includeSpec : null) != null ? _a3 : extractIncludeSpec2(processed, modelDef);
8003
8330
  const requiresReduction = sqlResult.requiresReduction === true;
8331
+ const isArrayAgg = sqlResult.isArrayAgg === true;
8004
8332
  return {
8005
8333
  sql: normalized.sql,
8006
8334
  paramMappings: normalized.paramMappings,
8007
8335
  requiresReduction,
8008
- includeSpec
8336
+ includeSpec,
8337
+ isArrayAgg
8009
8338
  };
8010
8339
  }
8011
8340
  function finalizeDirective(args) {
@@ -8016,11 +8345,12 @@ function finalizeDirective(args) {
8016
8345
  normalizedMappings,
8017
8346
  dialect,
8018
8347
  requiresReduction,
8019
- includeSpec
8348
+ includeSpec,
8349
+ isArrayAgg
8020
8350
  } = args;
8021
8351
  const params = normalizedMappings.map((m) => {
8022
- var _a;
8023
- return (_a = m.value) != null ? _a : void 0;
8352
+ var _a3;
8353
+ return (_a3 = m.value) != null ? _a3 : void 0;
8024
8354
  });
8025
8355
  validateParamConsistencyByDialect(normalizedSql, params, dialect);
8026
8356
  const { staticParams, dynamicKeys, paramOrder } = buildParamsFromMappings(normalizedMappings);
@@ -8033,6 +8363,7 @@ function finalizeDirective(args) {
8033
8363
  paramMappings: normalizedMappings,
8034
8364
  requiresReduction,
8035
8365
  includeSpec,
8366
+ isArrayAgg,
8036
8367
  originalDirective: directive
8037
8368
  };
8038
8369
  }
@@ -8066,7 +8397,8 @@ function generateSQL(directive) {
8066
8397
  normalizedMappings: built.paramMappings,
8067
8398
  dialect,
8068
8399
  requiresReduction: built.requiresReduction,
8069
- includeSpec: built.includeSpec
8400
+ includeSpec: built.includeSpec,
8401
+ isArrayAgg: built.isArrayAgg
8070
8402
  });
8071
8403
  }
8072
8404
 
@@ -8721,7 +9053,8 @@ function processModelDirectives(modelName, result, config) {
8721
9053
  dynamicKeys: sqlDirective.dynamicKeys,
8722
9054
  paramMappings: sqlDirective.paramMappings,
8723
9055
  requiresReduction: sqlDirective.requiresReduction || false,
8724
- includeSpec: sqlDirective.includeSpec || {}
9056
+ includeSpec: sqlDirective.includeSpec || {},
9057
+ isArrayAgg: sqlDirective.isArrayAgg || false
8725
9058
  });
8726
9059
  } catch (error) {
8727
9060
  if (!config.skipInvalid) throw error;
@@ -8749,9 +9082,9 @@ function processAllModelDirectives(directiveResults, config) {
8749
9082
  }
8750
9083
  function generateClient(options) {
8751
9084
  return __async(this, null, function* () {
8752
- var _a;
9085
+ var _a3;
8753
9086
  const { datamodel, outputDir, config, datasourceUrl } = options;
8754
- const runtimeImportPath = (_a = options.runtimeImportPath) != null ? _a : "prisma-sql";
9087
+ const runtimeImportPath = (_a3 = options.runtimeImportPath) != null ? _a3 : "prisma-sql";
8755
9088
  setGlobalDialect(config.dialect);
8756
9089
  const models = convertDMMFToModels(datamodel);
8757
9090
  const directiveResults = processAllDirectives(
@@ -8831,8 +9164,6 @@ function generateClient(options) {
8831
9164
  }
8832
9165
  function generateImports(runtimeImportPath) {
8833
9166
  return `import {
8834
- transformAggregateRow,
8835
- extractCountValue,
8836
9167
  buildSQL,
8837
9168
  buildBatchSql,
8838
9169
  parseBatchResults,
@@ -8844,7 +9175,6 @@ function generateImports(runtimeImportPath) {
8844
9175
  planQueryStrategy,
8845
9176
  executeWhereInSegments,
8846
9177
  buildReducerConfig,
8847
- reduceFlatRows,
8848
9178
  type PrismaMethod,
8849
9179
  type Model,
8850
9180
  type BatchQuery,
@@ -8852,13 +9182,11 @@ function generateImports(runtimeImportPath) {
8852
9182
  type TransactionQuery,
8853
9183
  type TransactionOptions,
8854
9184
  getOrPrepareStatement,
8855
- shouldSqliteUseGet,
8856
9185
  normalizeParams,
8857
9186
  executePostgresQuery,
8858
9187
  executeSqliteQuery,
8859
9188
  executeRaw,
8860
- } from ${JSON.stringify(runtimeImportPath)}
8861
- import { RELATION_STATS } from './planner.generated'`;
9189
+ } from ${JSON.stringify(runtimeImportPath)}`;
8862
9190
  }
8863
9191
  function generateCoreTypes() {
8864
9192
  return `class DeferredQuery {
@@ -8987,6 +9315,7 @@ const QUERIES: Record<string, Record<string, Record<string, {
8987
9315
  paramMappings: any[]
8988
9316
  requiresReduction: boolean
8989
9317
  includeSpec: Record<string, any>
9318
+ isArrayAgg: boolean
8990
9319
  }>>> = ${formatQueries(queries)}
8991
9320
 
8992
9321
  const DIALECT = ${JSON.stringify(dialect)}
@@ -9209,9 +9538,10 @@ function generateExtension(runtimeImportPath) {
9209
9538
  requiresReduction: boolean,
9210
9539
  includeSpec: Record<string, any> | undefined,
9211
9540
  model: any | undefined,
9541
+ isArrayAgg?: boolean,
9212
9542
  ): Promise<unknown[]> {
9213
9543
  if (DIALECT === 'postgres') {
9214
- return executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS)
9544
+ return executePostgresQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS, isArrayAgg)
9215
9545
  }
9216
9546
 
9217
9547
  return executeSqliteQuery(client, sql, params, method, requiresReduction, includeSpec, model, MODELS)
@@ -9282,7 +9612,6 @@ function generateExtension(runtimeImportPath) {
9282
9612
  method,
9283
9613
  args: transformedArgs,
9284
9614
  allModels: MODELS,
9285
- relationStats: RELATION_STATS as any,
9286
9615
  dialect: DIALECT,
9287
9616
  })
9288
9617
 
@@ -9293,6 +9622,7 @@ function generateExtension(runtimeImportPath) {
9293
9622
  let prebaked = false
9294
9623
  let requiresReduction = false
9295
9624
  let includeSpec: Record<string, any> | undefined
9625
+ let isArrayAgg = false
9296
9626
 
9297
9627
  if (prebakedQuery) {
9298
9628
  sql = prebakedQuery.sql
@@ -9300,17 +9630,19 @@ function generateExtension(runtimeImportPath) {
9300
9630
  prebaked = true
9301
9631
  requiresReduction = prebakedQuery.requiresReduction || false
9302
9632
  includeSpec = prebakedQuery.includeSpec
9633
+ isArrayAgg = prebakedQuery.isArrayAgg || false
9303
9634
  } else {
9304
9635
  const result = buildSQL(model, MODELS, method, plan.filteredArgs, DIALECT)
9305
9636
  sql = result.sql
9306
9637
  params = result.params as unknown[]
9307
9638
  requiresReduction = result.requiresReduction || false
9308
9639
  includeSpec = result.includeSpec
9640
+ isArrayAgg = result.isArrayAgg || false
9309
9641
  }
9310
9642
 
9311
9643
  if (debug) {
9312
9644
  const strategy = DIALECT === 'postgres'
9313
- ? (requiresReduction ? 'STREAMING REDUCTION' : 'STREAMING')
9645
+ ? (isArrayAgg ? 'ARRAY AGG' : requiresReduction ? 'STREAMING REDUCTION' : 'STREAMING')
9314
9646
  : (requiresReduction ? 'BUFFERED REDUCTION' : 'DIRECT')
9315
9647
 
9316
9648
  const whereInMode = plan.whereInSegments.length > 0
@@ -9323,63 +9655,75 @@ function generateExtension(runtimeImportPath) {
9323
9655
  console.log(' Params:', params)
9324
9656
  }
9325
9657
 
9326
- let results = await executeQuery(sql, params, method, requiresReduction, includeSpec, model)
9327
-
9328
- const duration = Date.now() - startTime
9658
+ if (plan.whereInSegments.length > 0) {
9659
+ if (DIALECT === 'postgres') {
9660
+ const { executeWhereInSegmentsStreaming } = await import(${JSON.stringify(runtimeImportPath)})
9661
+
9662
+ const results = await executeWhereInSegmentsStreaming({
9663
+ segments: plan.whereInSegments,
9664
+ parentSql: sql,
9665
+ parentParams: normalizeParams(params),
9666
+ parentModel: model,
9667
+ allModels: MODELS,
9668
+ modelMap: MODEL_MAP,
9669
+ dialect: DIALECT,
9670
+ execute: async (sql: string, params: unknown[]) => {
9671
+ const results: any[] = []
9672
+ await client.unsafe(sql, normalizeParams(params)).forEach((row: any) => {
9673
+ results.push(row)
9674
+ })
9675
+ return results
9676
+ },
9677
+ })
9329
9678
 
9330
- onQuery?.({
9331
- model: modelName,
9332
- method,
9333
- sql,
9334
- params,
9335
- duration,
9336
- prebaked,
9337
- })
9679
+ if (plan.injectedParentKeys.length > 0) {
9680
+ for (const row of results) {
9681
+ for (const key of plan.injectedParentKeys) {
9682
+ delete row[key]
9683
+ }
9684
+ }
9685
+ }
9338
9686
 
9339
- let transformed = transformQueryResults(method, results)
9687
+ const duration = Date.now() - startTime
9688
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9340
9689
 
9341
- if (plan.whereInSegments.length > 0) {
9342
- const resultArray = Array.isArray(transformed) ? transformed : [transformed]
9690
+ return transformQueryResults(method, results)
9691
+ } else {
9692
+ const parentRows = await executeQuery(sql, params, method, requiresReduction, includeSpec, model, isArrayAgg) as any[]
9343
9693
 
9344
- if (resultArray.length > 0 && resultArray[0] != null) {
9345
- if (DIALECT === 'postgres') {
9346
- const { executeWhereInSegmentsStreaming } = await import(${JSON.stringify(runtimeImportPath)})
9347
-
9348
- const streamResults = await executeWhereInSegmentsStreaming({
9349
- segments: plan.whereInSegments,
9350
- parentSql: sql,
9351
- parentParams: params,
9352
- parentModel: model,
9353
- allModels: MODELS,
9354
- modelMap: MODEL_MAP,
9355
- dialect: DIALECT,
9356
- execute: async (sql: string, params: unknown[]) => {
9357
- const results: any[] = []
9358
- await client.unsafe(sql, normalizeParams(params)).forEach((row: any) => {
9359
- results.push(row)
9360
- })
9361
- return results
9362
- },
9363
- batchSize: 100,
9364
- maxConcurrency: 10
9365
- })
9366
-
9367
- transformed = Array.isArray(transformed) ? streamResults : streamResults[0]
9368
- } else {
9694
+ if (parentRows.length > 0) {
9369
9695
  await executeWhereInSegments({
9370
9696
  segments: plan.whereInSegments,
9371
- parentRows: resultArray,
9697
+ parentRows,
9372
9698
  parentModel: model,
9373
9699
  allModels: MODELS,
9374
9700
  modelMap: MODEL_MAP,
9375
9701
  dialect: DIALECT,
9376
9702
  execute: executeWhereInQuery,
9377
9703
  })
9704
+
9705
+ if (plan.injectedParentKeys.length > 0) {
9706
+ for (const row of parentRows) {
9707
+ for (const key of plan.injectedParentKeys) {
9708
+ delete row[key]
9709
+ }
9710
+ }
9711
+ }
9378
9712
  }
9713
+
9714
+ const duration = Date.now() - startTime
9715
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9716
+
9717
+ return transformQueryResults(method, parentRows)
9379
9718
  }
9380
9719
  }
9381
9720
 
9382
- return transformed
9721
+ const results = await executeQuery(sql, params, method, requiresReduction, includeSpec, model, isArrayAgg)
9722
+
9723
+ const duration = Date.now() - startTime
9724
+ onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
9725
+
9726
+ return transformQueryResults(method, results)
9383
9727
  } catch (error) {
9384
9728
  const msg = error instanceof Error ? error.message : String(error)
9385
9729
  console.warn(\`[prisma-sql] \${modelName}.\${method} acceleration failed: \${msg}\`)
@@ -9420,7 +9764,6 @@ function generateExtension(runtimeImportPath) {
9420
9764
  method: 'findMany',
9421
9765
  args: transformedArgs,
9422
9766
  allModels: MODELS,
9423
- relationStats: RELATION_STATS as any,
9424
9767
  dialect: DIALECT,
9425
9768
  })
9426
9769
 
@@ -9431,23 +9774,39 @@ function generateExtension(runtimeImportPath) {
9431
9774
  let params: unknown[]
9432
9775
  let requiresReduction = false
9433
9776
  let includeSpec: Record<string, any> | undefined
9777
+ let isArrayAgg = false
9434
9778
 
9435
9779
  if (prebakedQuery) {
9436
9780
  sql = prebakedQuery.sql
9437
9781
  params = resolveParamsFromMappings(plan.filteredArgs, prebakedQuery.paramMappings)
9438
9782
  requiresReduction = prebakedQuery.requiresReduction
9439
9783
  includeSpec = prebakedQuery.includeSpec
9784
+ isArrayAgg = prebakedQuery.isArrayAgg || false
9440
9785
  } else {
9441
9786
  const result = buildSQL(model, MODELS, 'findMany', plan.filteredArgs, DIALECT)
9442
9787
  sql = result.sql
9443
9788
  params = result.params as unknown[]
9444
9789
  requiresReduction = result.requiresReduction || false
9445
9790
  includeSpec = result.includeSpec
9791
+ isArrayAgg = result.isArrayAgg || false
9446
9792
  }
9447
9793
 
9448
9794
  const normalizedParams = normalizeParams(params)
9449
9795
 
9450
- if (requiresReduction && includeSpec) {
9796
+ if (isArrayAgg && includeSpec) {
9797
+ const { buildArrayAggReducerConfig, reduceArrayAggRows } = await import(${JSON.stringify(runtimeImportPath)})
9798
+ const config = buildArrayAggReducerConfig(model, includeSpec, MODELS)
9799
+ const results: any[] = []
9800
+
9801
+ await client.unsafe(sql, normalizedParams).forEach((row: any) => {
9802
+ results.push(row)
9803
+ })
9804
+
9805
+ const reduced = reduceArrayAggRows(results, config)
9806
+ for (const item of reduced) {
9807
+ yield item
9808
+ }
9809
+ } else if (requiresReduction && includeSpec) {
9451
9810
  const { createProgressiveReducer } = await import(${JSON.stringify(runtimeImportPath)})
9452
9811
  const config = buildReducerConfig(model, includeSpec, MODELS)
9453
9812
  const reducer = createProgressiveReducer(config)
@@ -9710,8 +10069,7 @@ function generateCode(models, queries, dialect, datamodel, runtimeImportPath) {
9710
10069
  generateDataConstants(cleanModels, mappings, fieldTypes, queries, dialect),
9711
10070
  generateTransformLogic(),
9712
10071
  generateExtension(runtimeImportPath),
9713
- generateTypeExports(),
9714
- `export * from './planner.generated'`
10072
+ generateTypeExports()
9715
10073
  ].join("\n\n");
9716
10074
  }
9717
10075
  function formatQueries(queries) {
@@ -9731,6 +10089,7 @@ function formatQueries(queries) {
9731
10089
  paramMappings: ${JSON.stringify(query.paramMappings)},
9732
10090
  requiresReduction: ${query.requiresReduction || false},
9733
10091
  includeSpec: ${JSON.stringify(query.includeSpec || {})},
10092
+ isArrayAgg: ${query.isArrayAgg || false},
9734
10093
  }`);
9735
10094
  }
9736
10095
  methodEntries.push(` ${JSON.stringify(method)}: {
@@ -9756,9 +10115,9 @@ function getDialectFromProvider(provider) {
9756
10115
  );
9757
10116
  }
9758
10117
  function getOutputDir(options) {
9759
- var _a, _b;
10118
+ var _a3, _b;
9760
10119
  const schemaDir = dirname(options.schemaPath);
9761
- if ((_a = options.generator.output) == null ? void 0 : _a.value) {
10120
+ if ((_a3 = options.generator.output) == null ? void 0 : _a3.value) {
9762
10121
  return resolve(schemaDir, options.generator.output.value);
9763
10122
  }
9764
10123
  const clientGenerator = options.otherGenerators.find(