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.cjs +562 -203
- package/dist/generator.cjs.map +1 -1
- package/dist/generator.js +562 -203
- package/dist/generator.js.map +1 -1
- package/dist/index.cjs +1174 -466
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +52 -27
- package/dist/index.d.ts +52 -27
- package/dist/index.js +1171 -467
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/generator.cjs
CHANGED
|
@@ -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.
|
|
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
|
|
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((
|
|
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
|
|
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 = (
|
|
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
|
-
|
|
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
|
|
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
|
|
3990
|
+
let finalOrderEntries = normalizeAndValidateOrderBy(
|
|
3960
3991
|
orderBy,
|
|
3961
3992
|
model,
|
|
3962
3993
|
parseOrderByValue
|
|
3963
3994
|
);
|
|
3964
|
-
if (
|
|
3965
|
-
|
|
3995
|
+
if (finalOrderEntries.length === 0) {
|
|
3996
|
+
finalOrderEntries = cursorEntries.map(([field]) => ({
|
|
3966
3997
|
field,
|
|
3967
3998
|
direction: "asc"
|
|
3968
3999
|
}));
|
|
3969
4000
|
} else {
|
|
3970
|
-
|
|
4001
|
+
finalOrderEntries = ensureCursorFieldsInOrder(
|
|
4002
|
+
finalOrderEntries,
|
|
4003
|
+
cursorEntries
|
|
4004
|
+
);
|
|
3971
4005
|
}
|
|
3972
|
-
assertCursorAndOrderFieldsScalar(model, cursor,
|
|
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 =
|
|
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
|
-
|
|
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 <
|
|
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 =
|
|
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 =
|
|
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 = (
|
|
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
|
|
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
|
|
5342
|
+
var _a3, _b, _c, _d, _e;
|
|
5291
5343
|
assertSafeAlias(options.alias);
|
|
5292
5344
|
const dialect = options.dialect || getGlobalDialect();
|
|
5293
|
-
const params = (
|
|
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
|
|
5353
|
-
return (
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
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
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
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
|
-
|
|
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
|
|
6561
|
-
|
|
6562
|
-
const
|
|
6563
|
-
const
|
|
6564
|
-
const
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
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
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
6619
|
-
const { includes, from, whereClause, whereJoins,
|
|
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 = (
|
|
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
|
|
6633
|
-
const
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
const
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
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 =
|
|
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
|
|
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 = (
|
|
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
|
|
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
|
-
|
|
6963
|
-
|
|
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
|
|
7320
|
+
var _a3;
|
|
6994
7321
|
const firstByField = mapFirstOrderByByField(existing);
|
|
6995
7322
|
const next = [];
|
|
6996
7323
|
for (const f of distinctFields) {
|
|
6997
|
-
next.push((
|
|
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
|
|
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 = (
|
|
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
|
|
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 = (
|
|
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
|
|
8034
|
-
return (
|
|
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
|
|
9096
|
+
var _a3;
|
|
8764
9097
|
const { datamodel, outputDir, config, datasourceUrl } = options;
|
|
8765
|
-
const runtimeImportPath = (
|
|
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
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
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
|
-
|
|
9342
|
-
|
|
9343
|
-
|
|
9344
|
-
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
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
|
-
|
|
9698
|
+
const duration = Date.now() - startTime
|
|
9699
|
+
onQuery?.({ model: modelName, method, sql, params, duration, prebaked })
|
|
9351
9700
|
|
|
9352
|
-
|
|
9353
|
-
|
|
9701
|
+
return transformQueryResults(method, results)
|
|
9702
|
+
} else {
|
|
9703
|
+
const parentRows = await executeQuery(sql, params, method, requiresReduction, includeSpec, model, isArrayAgg) as any[]
|
|
9354
9704
|
|
|
9355
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
|
10129
|
+
var _a3, _b;
|
|
9771
10130
|
const schemaDir = path.dirname(options.schemaPath);
|
|
9772
|
-
if ((
|
|
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(
|