@prisma/orm-family-sql 0.16.0 → 0.17.0-dev.2
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/aggregate-descriptor-registry-DPV4z8MS.mjs +111 -0
- package/dist/aggregate-descriptor-registry-DPV4z8MS.mjs.map +1 -0
- package/dist/{ast-DSuzmsWn.d.mts → ast--BZUAzN1.d.mts} +3 -4
- package/dist/ast--BZUAzN1.d.mts.map +1 -0
- package/dist/{ast-BstHjAoG.mjs → ast-DDAyIKdt.mjs} +2 -2
- package/dist/ast-DDAyIKdt.mjs.map +1 -0
- package/dist/builder.d.mts +2 -2
- package/dist/builder__runtime.d.mts +14 -10
- package/dist/builder__runtime.d.mts.map +1 -1
- package/dist/builder__runtime.mjs +161 -107
- package/dist/builder__runtime.mjs.map +1 -1
- package/dist/builder__types.d.mts +2 -2
- package/dist/codec-types-B_xmJL2m-CC_Q-_u9.mjs +24 -0
- package/dist/codec-types-B_xmJL2m-CC_Q-_u9.mjs.map +1 -0
- package/dist/{config-types-47qB33rW.d.mts → config-types-DKKhWdzf.d.mts} +2 -2
- package/dist/{config-types-47qB33rW.d.mts.map → config-types-DKKhWdzf.d.mts.map} +1 -1
- package/dist/{contract-builder-MvJJrQ-5.d.mts → contract-builder-Cj-lKWgM.d.mts} +4 -4
- package/dist/{contract-builder-MvJJrQ-5.d.mts.map → contract-builder-Cj-lKWgM.d.mts.map} +1 -1
- package/dist/contract-emitter.mjs +1 -1
- package/dist/contract-psl.d.mts +2 -2
- package/dist/contract-psl__provider.d.mts +1 -1
- package/dist/contract-ts.d.mts +2 -2
- package/dist/contract-ts__config-types.d.mts +1 -1
- package/dist/contract-ts__contract-builder.d.mts +1 -1
- package/dist/contract.d.mts +6 -6
- package/dist/contract__factories.d.mts +1 -1
- package/dist/contract__index-type-validation.d.mts +1 -1
- package/dist/contract__types.d.mts +3 -3
- package/dist/contract__validators.d.mts +1 -1
- package/dist/{control-BHmsZudH.d.mts → control-BqrVERXN.d.mts} +10 -10
- package/dist/{control-BHmsZudH.d.mts.map → control-BqrVERXN.d.mts.map} +1 -1
- package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts → control-adapter-C99J7aEF-mjOpiO_9.d.mts} +6 -6
- package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts.map → control-adapter-C99J7aEF-mjOpiO_9.d.mts.map} +1 -1
- package/dist/control-adapter-xEtAQKd9.d.mts +1 -0
- package/dist/{control-B7iS4jv4.mjs → control-mG3RlNzm.mjs} +2 -2
- package/dist/{control-B7iS4jv4.mjs.map → control-mG3RlNzm.mjs.map} +1 -1
- package/dist/{db-DhMsmBS--DKENDi3l.d.mts → db-B5PMfDDd-BiWfkubp.d.mts} +65 -32
- package/dist/db-B5PMfDDd-BiWfkubp.d.mts.map +1 -0
- package/dist/{ddl-types-rrMsf77U-DGctYf-T.d.mts → ddl-types-h_3_pXmq-QBLq6WbP.d.mts} +4 -5
- package/dist/ddl-types-h_3_pXmq-QBLq6WbP.d.mts.map +1 -0
- package/dist/{diff-DhlzHOMD.d.mts → diff-CIIMSaVD.d.mts} +5 -5
- package/dist/{diff-DhlzHOMD.d.mts.map → diff-CIIMSaVD.d.mts.map} +1 -1
- package/dist/{dist-DrScXbhq.mjs → dist-CYkK9Vbk.mjs} +55 -2
- package/dist/dist-CYkK9Vbk.mjs.map +1 -0
- package/dist/{expression-RUO52bJB.mjs → expression-Dhu3dLiu.mjs} +2 -2
- package/dist/{expression-RUO52bJB.mjs.map → expression-Dhu3dLiu.mjs.map} +1 -1
- package/dist/{expression-DIf8F4Mc.d.mts → expression-KPBpeH4T.d.mts} +5 -6
- package/dist/expression-KPBpeH4T.d.mts.map +1 -0
- package/dist/{factories-B7tA4y9D.d.mts → factories-MfcqTt5R.d.mts} +2 -2
- package/dist/{factories-B7tA4y9D.d.mts.map → factories-MfcqTt5R.d.mts.map} +1 -1
- package/dist/family.d.mts +9 -9
- package/dist/family.mjs +1 -1
- package/dist/family__control-adapter.d.mts +2 -2
- package/dist/family__control.d.mts +3 -3
- package/dist/family__control.mjs +1 -1
- package/dist/family__diff.d.mts +2 -2
- package/dist/family__ir.d.mts +1 -1
- package/dist/family__migration.d.mts +1 -1
- package/dist/family__runtime.d.mts +1 -1
- package/dist/{index-BgaTJRxj.d.mts → index-BZF7Wehu.d.mts} +3 -3
- package/dist/{index-BgaTJRxj.d.mts.map → index-BZF7Wehu.d.mts.map} +1 -1
- package/dist/{index-Bb9U36N4.d.mts → index-D_QTT11u.d.mts} +15 -16
- package/dist/index-D_QTT11u.d.mts.map +1 -0
- package/dist/{index-type-validation-DN0L2mqm.d.mts → index-type-validation-D_vuj-76.d.mts} +2 -2
- package/dist/{index-type-validation-DN0L2mqm.d.mts.map → index-type-validation-D_vuj-76.d.mts.map} +1 -1
- package/dist/{ir-B3bKMnGQ.d.mts → ir-Cvj3eU-K.d.mts} +2 -2
- package/dist/{ir-B3bKMnGQ.d.mts.map → ir-Cvj3eU-K.d.mts.map} +1 -1
- package/dist/lane-query-builder.d.mts +3 -3
- package/dist/middleware-ChwIEKBC.d.mts +1 -0
- package/dist/{middleware-B4XbF4d4-tfwBl6mX.d.mts → middleware-eb7YwdD4-D0M6ACQ-.d.mts} +3 -3
- package/dist/{middleware-B4XbF4d4-tfwBl6mX.d.mts.map → middleware-eb7YwdD4-D0M6ACQ-.d.mts.map} +1 -1
- package/dist/{migration-CW0ZJLxP.d.mts → migration-Dtyw2JeL.d.mts} +3 -3
- package/dist/{migration-CW0ZJLxP.d.mts.map → migration-Dtyw2JeL.d.mts.map} +1 -1
- package/dist/operations.d.mts +1 -1
- package/dist/orm-client.d.mts +82 -39
- package/dist/orm-client.d.mts.map +1 -1
- package/dist/orm-client.mjs +174 -128
- package/dist/orm-client.mjs.map +1 -1
- package/dist/{plan-BTD8xFfa-Dd_K-A1R.d.mts → plan-Bmp5R9sq-DKMRkx6Z.d.mts} +4 -4
- package/dist/plan-Bmp5R9sq-DKMRkx6Z.d.mts.map +1 -0
- package/dist/plan-mKgmSe0R.d.mts +2 -0
- package/dist/query-lane-context-Dcj4eXUl.d.mts +1 -0
- package/dist/{query-lane-context-DtdVMqoz-C2Tj5QHA.d.mts → query-lane-context-DjyAyYht-HDNYE_oF.d.mts} +62 -6
- package/dist/query-lane-context-DjyAyYht-HDNYE_oF.d.mts.map +1 -0
- package/dist/relational-core.d.mts +12 -13
- package/dist/relational-core.mjs +4 -3
- package/dist/relational-core__aggregate-descriptor-registry.d.mts +12 -0
- package/dist/relational-core__aggregate-descriptor-registry.d.mts.map +1 -0
- package/dist/relational-core__aggregate-descriptor-registry.mjs +2 -0
- package/dist/relational-core__ast.d.mts +3 -4
- package/dist/relational-core__ast.mjs +3 -2
- package/dist/relational-core__codec-descriptor-registry.d.mts +3 -3
- package/dist/relational-core__contract-free.d.mts +3 -4
- package/dist/relational-core__contract-free.d.mts.map +1 -1
- package/dist/relational-core__contract-free.mjs +1 -1
- package/dist/relational-core__contract-free.mjs.map +1 -1
- package/dist/relational-core__expression.d.mts +1 -1
- package/dist/relational-core__expression.mjs +1 -1
- package/dist/relational-core__middleware.d.mts +2 -2
- package/dist/relational-core__plan.d.mts +3 -3
- package/dist/relational-core__query-lane-context.d.mts +3 -3
- package/dist/relational-core__types.d.mts +2 -2
- package/dist/{runtime-DNewRuec.d.mts → runtime-DXPO2ytG.d.mts} +2 -2
- package/dist/{runtime-DNewRuec.d.mts.map → runtime-DXPO2ytG.d.mts.map} +1 -1
- package/dist/runtime.d.mts +3 -3
- package/dist/runtime.mjs +12 -3
- package/dist/runtime.mjs.map +1 -1
- package/dist/{schema-differ-DpG_gnur-g5_iks8G.d.mts → schema-differ-DpG_gnur-zSwkxqxK.d.mts} +2 -2
- package/dist/{schema-differ-DpG_gnur-g5_iks8G.d.mts.map → schema-differ-DpG_gnur-zSwkxqxK.d.mts.map} +1 -1
- package/dist/{sql-execution-plan-CJmsCP7n-DoEpNn7r.d.mts → sql-execution-plan-Da_d82pz-IHBEmGSa.d.mts} +3 -3
- package/dist/sql-execution-plan-Da_d82pz-IHBEmGSa.d.mts.map +1 -0
- package/dist/{types-DIBA80mc-wf5wLmON.d.mts → types-BwePDa3m-BVrPIi8V.d.mts} +117 -5
- package/dist/types-BwePDa3m-BVrPIi8V.d.mts.map +1 -0
- package/dist/types-Cty2fvYD.d.mts +1 -0
- package/dist/{types-BgkZru_1-H7yfikSQ.mjs → types-D43EhRac-DOJmnq_t.mjs} +4 -21
- package/dist/types-D43EhRac-DOJmnq_t.mjs.map +1 -0
- package/dist/{types-CuDrWc5v-ISVXBmBs.d.mts → types-D_plAPEe-DqK5It_K.d.mts} +30 -4
- package/dist/types-D_plAPEe-DqK5It_K.d.mts.map +1 -0
- package/dist/{types-IqZMLrFC-DtdJNICr.d.mts → types-IqZMLrFC-C1Zu2oo9.d.mts} +5 -5
- package/dist/{types-IqZMLrFC-DtdJNICr.d.mts.map → types-IqZMLrFC-C1Zu2oo9.d.mts.map} +1 -1
- package/dist/{types-Dl20lxky-DC_jdA0T.d.mts → types-dD8JJfeD-BOvMw2Iu.d.mts} +9 -9
- package/dist/{types-Dl20lxky-DC_jdA0T.d.mts.map → types-dD8JJfeD-BOvMw2Iu.d.mts.map} +1 -1
- package/dist/{types-BchwQpmO.d.mts → types-wy2-Y8wQ.d.mts} +2 -2
- package/dist/{types-BchwQpmO.d.mts.map → types-wy2-Y8wQ.d.mts.map} +1 -1
- package/dist/{validators-CxeHhHrf.d.mts → validators-Ds_fvIs_.d.mts} +2 -2
- package/dist/{validators-CxeHhHrf.d.mts.map → validators-Ds_fvIs_.d.mts.map} +1 -1
- package/package.json +24 -18
- package/dist/ast-BstHjAoG.mjs.map +0 -1
- package/dist/ast-DSuzmsWn.d.mts.map +0 -1
- package/dist/codec-types-MOaceoPi-C5eL2sao.d.mts +0 -116
- package/dist/codec-types-MOaceoPi-C5eL2sao.d.mts.map +0 -1
- package/dist/control-adapter-4y1O8Ps3.d.mts +0 -1
- package/dist/db-DhMsmBS--DKENDi3l.d.mts.map +0 -1
- package/dist/ddl-types-rrMsf77U-DGctYf-T.d.mts.map +0 -1
- package/dist/dist-DrScXbhq.mjs.map +0 -1
- package/dist/expression-DIf8F4Mc.d.mts.map +0 -1
- package/dist/index-Bb9U36N4.d.mts.map +0 -1
- package/dist/middleware-ByRsXxxq.d.mts +0 -1
- package/dist/plan-BTD8xFfa-Dd_K-A1R.d.mts.map +0 -1
- package/dist/plan-Cm4jaoNM.d.mts +0 -2
- package/dist/query-lane-context-Bz8XJZ45.d.mts +0 -1
- package/dist/query-lane-context-DtdVMqoz-C2Tj5QHA.d.mts.map +0 -1
- package/dist/sql-execution-plan-CJmsCP7n-DoEpNn7r.d.mts.map +0 -1
- package/dist/types-BgkZru_1-H7yfikSQ.mjs.map +0 -1
- package/dist/types-CuDrWc5v-ISVXBmBs.d.mts.map +0 -1
- package/dist/types-DIBA80mc-wf5wLmON.d.mts.map +0 -1
- package/dist/types-DMxc5KZa.d.mts +0 -1
package/dist/orm-client.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as resolveStorageTable } from "./resolve-storage-table-DZsfnzeW.mjs";
|
|
2
2
|
import { i as isUniqueConstraintViolation } from "./dist-x6jvtkKM.mjs";
|
|
3
|
-
import { C as LiteralExpr, D as OrExpr, F as SubqueryExpr, I as TableSource, L as UpdateAst, O as OrderByItem, P as SelectAst, R as WindowFuncExpr, S as ListExpression, T as NullCheckExpr,
|
|
3
|
+
import { B as isWhereExpr, C as LiteralExpr, D as OrExpr, F as SubqueryExpr, I as TableSource, L as UpdateAst, O as OrderByItem, P as SelectAst, R as WindowFuncExpr, S as ListExpression, T as NullCheckExpr, _ as InsertAst, b as JsonArrayAggExpr, c as DeleteAst, f as EqColJoinOn, j as ProjectionItem, k as ParamRef, l as DerivedTableSource, n as AndExpr, o as ColumnRef, p as ExistsExpr, r as BinaryExpr, s as DefaultValueExpr, t as AggregateExpr, v as InsertOnConflict, w as NotExpr, x as JsonObjectExpr, y as JoinAst } from "./types-D43EhRac-DOJmnq_t.mjs";
|
|
4
4
|
import { t as collectOrderedParamRefs } from "./util-DQQgv2j1-D6INZaRG.mjs";
|
|
5
|
-
import { n as JsonDocumentProjection, r as NativeJsonValueProjection, t as CodecJsonValueProjection } from "./ast-
|
|
5
|
+
import { n as JsonDocumentProjection, r as NativeJsonValueProjection, t as CodecJsonValueProjection } from "./ast-DDAyIKdt.mjs";
|
|
6
6
|
import { n as codecRefForStorageColumn } from "./codec-descriptor-registry-BJVJRftS.mjs";
|
|
7
7
|
import { structuredError } from "@prisma/orm-framework/utils/structured-error";
|
|
8
|
-
import { InternalError
|
|
8
|
+
import { InternalError } from "@prisma/orm-framework/utils/internal-error";
|
|
9
9
|
import { domainModelsAtDefaultNamespace } from "@prisma/orm-framework/contract/types";
|
|
10
10
|
import { blindCast, castAs } from "@prisma/orm-framework/utils/casts";
|
|
11
11
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
@@ -372,42 +372,27 @@ function isAggregateSelector(value) {
|
|
|
372
372
|
if (candidate.kind !== "aggregate") return false;
|
|
373
373
|
return candidate.fn === "count" || candidate.fn === "sum" || candidate.fn === "avg" || candidate.fn === "min" || candidate.fn === "max";
|
|
374
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* The selector's result type is the contract's to state — it varies by target, operation, and the field's own codec — so the builder erases it here and each method's declared return type names it.
|
|
377
|
+
*/
|
|
375
378
|
function createFieldAggregateSelector(fieldToColumn, field, fn) {
|
|
376
|
-
const fieldName = field;
|
|
377
379
|
return {
|
|
378
380
|
kind: "aggregate",
|
|
379
381
|
fn,
|
|
380
|
-
column: fieldToColumn[
|
|
382
|
+
column: fieldToColumn[field] ?? field
|
|
381
383
|
};
|
|
382
384
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
if (typeof value === "number") {
|
|
396
|
-
result[alias] = value;
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
if (typeof value === "bigint") {
|
|
400
|
-
result[alias] = Number(value);
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
if (typeof value === "string") {
|
|
404
|
-
const numeric = Number(value);
|
|
405
|
-
result[alias] = Number.isNaN(numeric) ? value : numeric;
|
|
406
|
-
continue;
|
|
407
|
-
}
|
|
408
|
-
result[alias] = value;
|
|
409
|
-
}
|
|
410
|
-
return result;
|
|
385
|
+
/**
|
|
386
|
+
* What an aggregate reads as when there is no row to read at all.
|
|
387
|
+
*
|
|
388
|
+
* SQL answers an empty input set itself — `count` collapses to zero, the rest
|
|
389
|
+
* to null — so this covers only the degenerate case of a result set with no
|
|
390
|
+
* row: an absent aggregate alias, or an include whose envelope never arrived.
|
|
391
|
+
* Zero is a `bigint` because that is what both targets' `count` codecs decode
|
|
392
|
+
* to; a count is a cardinality, and cardinalities are not capped at 2^53.
|
|
393
|
+
*/
|
|
394
|
+
function emptyAggregateResult(fn) {
|
|
395
|
+
return fn === "count" ? 0n : null;
|
|
411
396
|
}
|
|
412
397
|
function mapFieldsToColumns(contract, namespaceId, modelName, fieldNames) {
|
|
413
398
|
const fieldToColumn = getFieldToColumnMap(contract, namespaceId, modelName);
|
|
@@ -423,6 +408,43 @@ function mapCursorValuesToColumns(contract, namespaceId, modelName, cursorValues
|
|
|
423
408
|
}
|
|
424
409
|
return mappedCursor;
|
|
425
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* What an aggregate resolves to: the codec its result carries, and the expression the target wants built for it.
|
|
413
|
+
*
|
|
414
|
+
* An aggregate over a column resolves against that column's own codec, so a target that widens `sum` over small integers and preserves it over decimals answers differently per column without the caller knowing either rule. Where a target also needs the result rendered a particular way — a value its driver cannot otherwise carry — the descriptor's lowering says so, and the codec it declared stays the codec regardless.
|
|
415
|
+
*
|
|
416
|
+
* A pair the composed stack declares no overload for is rejected before any SQL is built: an undeclared aggregate has no result identity to project or decode, and executing it anyway would hand back the driver-native value the declared-codec path exists to replace.
|
|
417
|
+
*/
|
|
418
|
+
function resolveAggregate(query) {
|
|
419
|
+
const input = inputCodecRef(query);
|
|
420
|
+
const resolved = query.aggregates.resolve(query.fn, input);
|
|
421
|
+
if (resolved === void 0) throw unsupportedAggregate(query, input);
|
|
422
|
+
return {
|
|
423
|
+
codec: resolved.output,
|
|
424
|
+
input,
|
|
425
|
+
lower: resolved.lower
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
/** The codec an aggregate's result carries. Rejects a pair the composed stack declares no overload for, exactly as planning does. */
|
|
429
|
+
function resolveAggregateOutputCodec(query) {
|
|
430
|
+
return resolveAggregate(query).codec;
|
|
431
|
+
}
|
|
432
|
+
function unsupportedAggregate(query, input) {
|
|
433
|
+
return ormError("ORM.AGGREGATE_UNSUPPORTED", input === void 0 ? `The composed target declares no '${query.fn}' aggregate for a call without an input.` : `The composed target declares no '${query.fn}' aggregate over codec '${input.codecId}' (column '${query.column}' of table '${query.tableName}').`, {
|
|
434
|
+
why: "An aggregate result decodes through the codec its target declares; an undeclared pair has no declared result to type or decode.",
|
|
435
|
+
fix: `Aggregate a column the target declares '${query.fn}' for, or contribute an aggregate descriptor for this pair.`,
|
|
436
|
+
meta: {
|
|
437
|
+
operation: query.fn,
|
|
438
|
+
table: query.tableName,
|
|
439
|
+
...ifDefined("column", query.column),
|
|
440
|
+
...ifDefined("inputCodecId", input?.codecId)
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
/** The codec of the value being aggregated — the column's own, or none where the aggregate is over rows. */
|
|
445
|
+
function inputCodecRef(query) {
|
|
446
|
+
return query.column === void 0 ? void 0 : codecRefForStorageColumn(query.contract.storage, query.namespaceId, query.tableName, query.column);
|
|
447
|
+
}
|
|
426
448
|
function stripHiddenMappedFields(contract, namespaceId, modelName, mapped, hiddenColumns) {
|
|
427
449
|
if (hiddenColumns.length === 0) return;
|
|
428
450
|
const columnToField = getColumnToFieldMap(contract, namespaceId, modelName);
|
|
@@ -575,20 +597,22 @@ function combineWhereExprs(filters) {
|
|
|
575
597
|
if (filters.length === 1) return filters[0];
|
|
576
598
|
return AndExpr.of(filters);
|
|
577
599
|
}
|
|
578
|
-
function toAggregateProjection(contract, namespaceId, tableName, selector) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
};
|
|
600
|
+
function toAggregateProjection(contract, aggregates, namespaceId, tableName, selector) {
|
|
601
|
+
const { codec, input: inputCodec, lower } = resolveAggregate({
|
|
602
|
+
aggregates,
|
|
603
|
+
contract,
|
|
604
|
+
namespaceId,
|
|
605
|
+
tableName,
|
|
606
|
+
fn: selector.fn,
|
|
607
|
+
column: selector.column
|
|
608
|
+
});
|
|
609
|
+
const inputExpr = selector.column === void 0 ? void 0 : ColumnRef.of(tableName, selector.column);
|
|
589
610
|
return {
|
|
590
|
-
expr
|
|
591
|
-
|
|
611
|
+
expr: lower !== void 0 ? lower({
|
|
612
|
+
expr: inputExpr,
|
|
613
|
+
inputCodec
|
|
614
|
+
}) : new AggregateExpr(selector.fn, inputExpr),
|
|
615
|
+
codec
|
|
592
616
|
};
|
|
593
617
|
}
|
|
594
618
|
function validateGroupedComparable(value) {
|
|
@@ -655,7 +679,7 @@ function validateGroupedHavingExpr(expr) {
|
|
|
655
679
|
rawExpr: rejectHavingExpr
|
|
656
680
|
});
|
|
657
681
|
}
|
|
658
|
-
function compileAggregate(contract, namespaceId, tableName, filters, aggregateSpec) {
|
|
682
|
+
function compileAggregate(contract, aggregates, namespaceId, tableName, filters, aggregateSpec) {
|
|
659
683
|
const entries = Object.entries(aggregateSpec);
|
|
660
684
|
if (entries.length === 0) throw ormError("ORM.AGGREGATE_SELECTOR_MISSING", "aggregate() requires at least one aggregation selector", { meta: {
|
|
661
685
|
method: "aggregate",
|
|
@@ -663,7 +687,7 @@ function compileAggregate(contract, namespaceId, tableName, filters, aggregateSp
|
|
|
663
687
|
tableName
|
|
664
688
|
} });
|
|
665
689
|
const projection = entries.map(([alias, selector]) => {
|
|
666
|
-
const { expr, codec } = toAggregateProjection(contract, namespaceId, tableName, selector);
|
|
690
|
+
const { expr, codec } = toAggregateProjection(contract, aggregates, namespaceId, tableName, selector);
|
|
667
691
|
return ProjectionItem.of(alias, expr, codec);
|
|
668
692
|
});
|
|
669
693
|
let ast = SelectAst.from(tableSourceForContract(contract, namespaceId, tableName)).withProjection(projection);
|
|
@@ -672,7 +696,7 @@ function compileAggregate(contract, namespaceId, tableName, filters, aggregateSp
|
|
|
672
696
|
const { params } = deriveParamsFromAst(ast);
|
|
673
697
|
return buildOrmQueryPlan(contract, ast, params);
|
|
674
698
|
}
|
|
675
|
-
function compileGroupedAggregate(contract, namespaceId, tableName, filters, groupByColumns, aggregateSpec, havingExpr) {
|
|
699
|
+
function compileGroupedAggregate(contract, aggregates, namespaceId, tableName, filters, groupByColumns, aggregateSpec, havingExpr) {
|
|
676
700
|
if (groupByColumns.length === 0) throw ormError("ORM.GROUP_BY_FIELD_MISSING", "groupBy() requires at least one field", { meta: {
|
|
677
701
|
namespaceId,
|
|
678
702
|
tableName
|
|
@@ -684,7 +708,7 @@ function compileGroupedAggregate(contract, namespaceId, tableName, filters, grou
|
|
|
684
708
|
tableName
|
|
685
709
|
} });
|
|
686
710
|
const projection = [...groupByColumns.map((column) => ProjectionItem.of(column, ColumnRef.of(tableName, column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column))), ...entries.map(([alias, selector]) => {
|
|
687
|
-
const { expr, codec } = toAggregateProjection(contract, namespaceId, tableName, selector);
|
|
711
|
+
const { expr, codec } = toAggregateProjection(contract, aggregates, namespaceId, tableName, selector);
|
|
688
712
|
return ProjectionItem.of(alias, expr, codec);
|
|
689
713
|
})];
|
|
690
714
|
let ast = SelectAst.from(tableSourceForContract(contract, namespaceId, tableName)).withProjection(projection).withGroupBy(groupByColumns.map((column) => ColumnRef.of(tableName, column)));
|
|
@@ -1020,11 +1044,13 @@ function bindSelectAst(contract, ast) {
|
|
|
1020
1044
|
* correlated subquery, a combine branch, or the object a child row set is
|
|
1021
1045
|
* aggregated from. Its parts were made canonical at the level that produced
|
|
1022
1046
|
* them; this level only nests it.
|
|
1023
|
-
* - `native`: the value has no codec identity.
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1027
|
-
* to identity — that, the
|
|
1047
|
+
* - `native`: the value has no codec identity. The case that reaches it is an
|
|
1048
|
+
* aggregate the target declares no overload for — SQLite computes `sum` over
|
|
1049
|
+
* a text column from whatever leading numbers the rows held, and declines to
|
|
1050
|
+
* type the result. Native is what a value with no codec identity means, which
|
|
1051
|
+
* is a different thing from defaulting a codec to identity — that, the
|
|
1052
|
+
* project forbids. An aggregate the target does declare carries the codec the
|
|
1053
|
+
* registry resolved for it, like any other value.
|
|
1028
1054
|
*
|
|
1029
1055
|
* A document never carries a codec and a codec-bearing column is never a
|
|
1030
1056
|
* document, so the first two cases cannot both apply.
|
|
@@ -1216,8 +1242,8 @@ function resolveChildTableSource(include, parentLocalRefs) {
|
|
|
1216
1242
|
* Each nested include contributes a single projection item whose
|
|
1217
1243
|
* expression is a correlated subquery.
|
|
1218
1244
|
*/
|
|
1219
|
-
function buildNestedIncludeProjections(contract, parentSource, includes) {
|
|
1220
|
-
return includes.map((nested) => buildCorrelatedIncludeProjection(contract, parentSource, nested).projection);
|
|
1245
|
+
function buildNestedIncludeProjections(contract, aggregates, parentSource, includes) {
|
|
1246
|
+
return includes.map((nested) => buildCorrelatedIncludeProjection(contract, aggregates, parentSource, nested).projection);
|
|
1221
1247
|
}
|
|
1222
1248
|
/**
|
|
1223
1249
|
* The aliases a level's nested includes contribute. Each such subquery
|
|
@@ -1320,7 +1346,7 @@ function buildManyToManyJunctionArtifacts(parentLocalRefs, childTableRef, throug
|
|
|
1320
1346
|
junctionJoin: JoinAst.inner(TableSource.named(junctionTable, void 0, namespaceId), joinOn, false)
|
|
1321
1347
|
};
|
|
1322
1348
|
}
|
|
1323
|
-
function buildIncludeChildRowsSelect(contract, parentSource, include) {
|
|
1349
|
+
function buildIncludeChildRowsSelect(contract, aggregates, parentSource, include) {
|
|
1324
1350
|
const childState = include.nested;
|
|
1325
1351
|
const parentLocalRefs = resolveParentLocalRefs(parentSource, include, localColumnsForRowInclude(include));
|
|
1326
1352
|
const childSource = resolveChildTableSource(include, parentLocalRefs);
|
|
@@ -1347,6 +1373,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
|
|
|
1347
1373
|
}
|
|
1348
1374
|
if (childState.distinct !== void 0 && childState.distinct.length > 0 && childState.includes.length > 0) return buildDistinctNonLeafChildRowsSelect({
|
|
1349
1375
|
contract,
|
|
1376
|
+
aggregates,
|
|
1350
1377
|
include,
|
|
1351
1378
|
childTableAlias,
|
|
1352
1379
|
childTableRef,
|
|
@@ -1359,7 +1386,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
|
|
|
1359
1386
|
});
|
|
1360
1387
|
const polyJoinsAndProjection = buildChildPolymorphismJoinsAndProjection(contract, include, childTableAlias, childTableRef);
|
|
1361
1388
|
const scalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, polyJoinsAndProjection.baseSelectedFields, childTableRef);
|
|
1362
|
-
const nestedProjections = buildNestedIncludeProjections(contract, {
|
|
1389
|
+
const nestedProjections = buildNestedIncludeProjections(contract, aggregates, {
|
|
1363
1390
|
baseTableName: include.relatedTableName,
|
|
1364
1391
|
tableRef: childTableRef,
|
|
1365
1392
|
variantColumnsProjected: false
|
|
@@ -1397,7 +1424,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
|
|
|
1397
1424
|
};
|
|
1398
1425
|
}
|
|
1399
1426
|
function buildDistinctNonLeafChildRowsSelect(options) {
|
|
1400
|
-
const { contract, include, childTableAlias, childTableRef, rowsAlias, childOrderBy, hiddenOrderProjection, aggregateOrderBy, whereExpr, junctionJoins } = options;
|
|
1427
|
+
const { contract, aggregates, include, childTableAlias, childTableRef, rowsAlias, childOrderBy, hiddenOrderProjection, aggregateOrderBy, whereExpr, junctionJoins } = options;
|
|
1401
1428
|
const childState = include.nested;
|
|
1402
1429
|
const grandchildJoinColumns = Array.from(new Set(childState.includes.flatMap((nested) => nested.localTableName === include.relatedTableName ? localColumnsForRowInclude(nested) : [])));
|
|
1403
1430
|
const { selectedForQuery } = augmentSelectionForJoinColumns(childState.selectedFields, grandchildJoinColumns);
|
|
@@ -1433,7 +1460,7 @@ function buildDistinctNonLeafChildRowsSelect(options) {
|
|
|
1433
1460
|
if (childState.offset !== void 0) innerSelect = innerSelect.withOffset(childState.offset);
|
|
1434
1461
|
const distinctAlias = `${include.relationName}__distinct`;
|
|
1435
1462
|
const outerScalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, visiblePolyProjection.baseSelectedFields, distinctAlias);
|
|
1436
|
-
const outerNestedProjections = buildNestedIncludeProjections(contract, {
|
|
1463
|
+
const outerNestedProjections = buildNestedIncludeProjections(contract, aggregates, {
|
|
1437
1464
|
baseTableName: include.relatedTableName,
|
|
1438
1465
|
tableRef: distinctAlias,
|
|
1439
1466
|
variantColumnsProjected: true
|
|
@@ -1481,32 +1508,51 @@ function buildDistinctNonLeafChildRowsSelect(options) {
|
|
|
1481
1508
|
* `distinct`) is dropped at the SQL level since reordering does not
|
|
1482
1509
|
* change which rows are aggregated.
|
|
1483
1510
|
*/
|
|
1484
|
-
function buildIncludeChildScalarSelect(contract, parentSource, include, scalar) {
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1487
|
-
|
|
1511
|
+
function buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, scalar) {
|
|
1512
|
+
const { codec: resultCodec, input: inputCodec, lower: resultLowering } = resolveAggregate({
|
|
1513
|
+
aggregates,
|
|
1514
|
+
contract,
|
|
1515
|
+
namespaceId: include.relatedNamespaceId,
|
|
1516
|
+
tableName: include.relatedTableName,
|
|
1517
|
+
fn: scalar.fn,
|
|
1518
|
+
column: scalar.column
|
|
1519
|
+
});
|
|
1520
|
+
const parentLocalRefs = resolveParentLocalRefs(parentSource, include, localColumnsForRowInclude(include));
|
|
1488
1521
|
const childSource = resolveChildTableSource(include, parentLocalRefs);
|
|
1489
1522
|
const childTableAlias = childSource.alias;
|
|
1490
1523
|
const childTableRef = childSource.tableRef;
|
|
1491
1524
|
const state = scalar.state;
|
|
1492
|
-
const joinExpr = BinaryExpr.eq(ColumnRef.of(childTableRef, include.targetColumn), parentLocalRef);
|
|
1493
1525
|
const childWhere = buildStateWhere(contract, childTableRef, state, {
|
|
1494
1526
|
filterTableName: include.relatedTableName,
|
|
1495
1527
|
namespaceId: include.relatedNamespaceId
|
|
1496
1528
|
});
|
|
1497
|
-
|
|
1529
|
+
let whereExpr;
|
|
1530
|
+
let junctionJoins = [];
|
|
1531
|
+
if (include.through !== void 0) {
|
|
1532
|
+
const artifacts = buildManyToManyJunctionArtifacts(parentLocalRefs, childTableRef, include.through);
|
|
1533
|
+
whereExpr = childWhere ? AndExpr.of([artifacts.whereExpr, childWhere]) : artifacts.whereExpr;
|
|
1534
|
+
junctionJoins = [artifacts.junctionJoin];
|
|
1535
|
+
} else {
|
|
1536
|
+
const parentLocalRef = parentLocalRefs[0];
|
|
1537
|
+
assertDefined(parentLocalRef, `Include '${include.relationName}' has no parent-local column ref`);
|
|
1538
|
+
const joinExpr = BinaryExpr.eq(ColumnRef.of(childTableRef, include.targetColumn), parentLocalRef);
|
|
1539
|
+
whereExpr = childWhere ? AndExpr.of([joinExpr, childWhere]) : joinExpr;
|
|
1540
|
+
}
|
|
1498
1541
|
const remappedOrderBy = childTableAlias && state.orderBy ? state.orderBy.map((item) => item.rewrite(createTableRefRemapper(include.relatedTableName, childTableRef))) : state.orderBy;
|
|
1499
1542
|
const hasPagination = state.limit !== void 0 || state.offset !== void 0;
|
|
1500
1543
|
const hasDistinct = state.distinct !== void 0 && state.distinct.length > 0 || state.distinctOn !== void 0 && state.distinctOn.length > 0;
|
|
1501
1544
|
if (!(hasPagination || hasDistinct)) {
|
|
1502
|
-
const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef);
|
|
1503
|
-
const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, {}))]);
|
|
1504
|
-
|
|
1545
|
+
const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef, resultLowering, inputCodec);
|
|
1546
|
+
const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, { codec: resultCodec }))]);
|
|
1547
|
+
let select = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection([ProjectionItem.of(include.relationName, jsonObjectExpr)]).withWhere(whereExpr);
|
|
1548
|
+
if (junctionJoins.length > 0) select = select.withJoins(junctionJoins);
|
|
1549
|
+
return select;
|
|
1505
1550
|
}
|
|
1506
1551
|
const innerAlias = `${include.relationName}__scalar`;
|
|
1507
1552
|
const hiddenOrderProjection = state.distinct !== void 0 && state.distinct.length > 0 && remappedOrderBy !== void 0 && remappedOrderBy.length > 0 ? remappedOrderBy.map((item, index) => ProjectionItem.of(`${include.relationName}__order_${index}`, item.expr)) : [];
|
|
1508
1553
|
const innerProjection = [...scalar.column !== void 0 ? [ProjectionItem.of(scalar.column, ColumnRef.of(childTableRef, scalar.column))] : [ProjectionItem.of("__row", LiteralExpr.of(1))], ...hiddenOrderProjection];
|
|
1509
1554
|
let inner = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection(innerProjection).withWhere(whereExpr);
|
|
1555
|
+
if (junctionJoins.length > 0) inner = inner.withJoins(junctionJoins);
|
|
1510
1556
|
if (state.distinctOn !== void 0 && state.distinctOn.length > 0) {
|
|
1511
1557
|
inner = inner.withDistinctOn(state.distinctOn.map((column) => ColumnRef.of(childTableRef, column)));
|
|
1512
1558
|
if (remappedOrderBy !== void 0 && remappedOrderBy.length > 0) inner = inner.withOrderBy(remappedOrderBy);
|
|
@@ -1522,21 +1568,17 @@ function buildIncludeChildScalarSelect(contract, parentSource, include, scalar)
|
|
|
1522
1568
|
} else if (remappedOrderBy !== void 0 && remappedOrderBy.length > 0) inner = inner.withOrderBy(remappedOrderBy);
|
|
1523
1569
|
if (state.limit !== void 0) inner = inner.withLimit(state.limit);
|
|
1524
1570
|
if (state.offset !== void 0) inner = inner.withOffset(state.offset);
|
|
1525
|
-
const outerAggregateExpr = buildIncludeAggregateExpr(scalar, innerAlias);
|
|
1526
|
-
const outerJsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(outerAggregateExpr, {}))]);
|
|
1571
|
+
const outerAggregateExpr = buildIncludeAggregateExpr(scalar, innerAlias, resultLowering, inputCodec);
|
|
1572
|
+
const outerJsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(outerAggregateExpr, { codec: resultCodec }))]);
|
|
1527
1573
|
return SelectAst.from(DerivedTableSource.as(innerAlias, inner)).withProjection([ProjectionItem.of(include.relationName, outerJsonObjectExpr)]);
|
|
1528
1574
|
}
|
|
1529
|
-
function buildIncludeAggregateExpr(scalar, childTableRef) {
|
|
1530
|
-
|
|
1531
|
-
if (
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
case "min": return AggregateExpr.min(columnRef);
|
|
1537
|
-
case "max": return AggregateExpr.max(columnRef);
|
|
1538
|
-
default: return assertNever(scalar.fn);
|
|
1539
|
-
}
|
|
1575
|
+
function buildIncludeAggregateExpr(scalar, childTableRef, lower, inputCodec) {
|
|
1576
|
+
const expr = scalar.column === void 0 ? void 0 : ColumnRef.of(childTableRef, scalar.column);
|
|
1577
|
+
if (lower !== void 0) return lower({
|
|
1578
|
+
expr,
|
|
1579
|
+
inputCodec
|
|
1580
|
+
});
|
|
1581
|
+
return new AggregateExpr(scalar.fn, expr);
|
|
1540
1582
|
}
|
|
1541
1583
|
/**
|
|
1542
1584
|
* Build the inner SELECT for a `combine({ a, b, ... })` include.
|
|
@@ -1557,13 +1599,13 @@ function buildIncludeAggregateExpr(scalar, childTableRef) {
|
|
|
1557
1599
|
* branch fan out naturally because the row builder is invoked with
|
|
1558
1600
|
* a synthetic IncludeExpr whose `nested` is the branch's state.
|
|
1559
1601
|
*/
|
|
1560
|
-
function buildIncludeChildCombineSelect(contract, parentSource, include, branches) {
|
|
1602
|
+
function buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, branches) {
|
|
1561
1603
|
const branchEntries = Object.entries(branches);
|
|
1562
1604
|
if (branchEntries.length === 0) throw ormError("ORM.INCLUDE_INVALID", `combine() include "${include.relationName}" has no branches`, { meta: { relation: include.relationName } });
|
|
1563
1605
|
const compiledBranches = branchEntries.map(([name, branch]) => ({
|
|
1564
1606
|
name,
|
|
1565
1607
|
alias: `${include.relationName}__combine__${name}`,
|
|
1566
|
-
select: buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch)
|
|
1608
|
+
select: buildIncludeChildCombineBranchSelect(contract, aggregates, parentSource, include, branch)
|
|
1567
1609
|
}));
|
|
1568
1610
|
const jsonObjectExpr = JsonObjectExpr.fromEntries(compiledBranches.map((branch) => JsonObjectExpr.entry(branch.name, jsonEntryProjection(ColumnRef.of(branch.alias, include.relationName), { document: true }))));
|
|
1569
1611
|
const [firstBranch, ...restBranches] = compiledBranches;
|
|
@@ -1577,9 +1619,9 @@ function buildIncludeChildCombineSelect(contract, parentSource, include, branche
|
|
|
1577
1619
|
* relation name. Dispatches to the standalone scalar / row builders
|
|
1578
1620
|
* with the branch's state spliced into a synthetic IncludeExpr.
|
|
1579
1621
|
*/
|
|
1580
|
-
function buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch) {
|
|
1581
|
-
if (branch.kind === "scalar") return buildIncludeChildScalarSelect(contract, parentSource, include, branch.selector);
|
|
1582
|
-
return buildIncludeChildRowsAggregateSelect(contract, parentSource, {
|
|
1622
|
+
function buildIncludeChildCombineBranchSelect(contract, aggregates, parentSource, include, branch) {
|
|
1623
|
+
if (branch.kind === "scalar") return buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, branch.selector);
|
|
1624
|
+
return buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, {
|
|
1583
1625
|
...include,
|
|
1584
1626
|
nested: branch.state,
|
|
1585
1627
|
scalar: void 0,
|
|
@@ -1592,24 +1634,24 @@ function buildIncludeChildCombineBranchSelect(contract, parentSource, include, b
|
|
|
1592
1634
|
* name. Used by both the standalone row correlated-subquery path and
|
|
1593
1635
|
* by combine's row branches.
|
|
1594
1636
|
*/
|
|
1595
|
-
function buildIncludeChildRowsAggregateSelect(contract, parentSource, include) {
|
|
1596
|
-
const { childRows, childProjection, documentAliases, rowsAlias, aggregateOrderBy } = buildIncludeChildRowsSelect(contract, parentSource, include);
|
|
1637
|
+
function buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include) {
|
|
1638
|
+
const { childRows, childProjection, documentAliases, rowsAlias, aggregateOrderBy } = buildIncludeChildRowsSelect(contract, aggregates, parentSource, include);
|
|
1597
1639
|
const jsonObjectExpr = JsonObjectExpr.fromEntries(childProjection.map((item) => JsonObjectExpr.entry(item.alias, jsonEntryProjection(ColumnRef.of(rowsAlias, item.alias), {
|
|
1598
1640
|
codec: item.codec,
|
|
1599
1641
|
document: documentAliases.has(item.alias)
|
|
1600
1642
|
}))));
|
|
1601
1643
|
return SelectAst.from(DerivedTableSource.as(rowsAlias, childRows)).withProjection([ProjectionItem.of(include.relationName, JsonArrayAggExpr.of(jsonEntryProjection(jsonObjectExpr, { document: true }), "emptyArray", aggregateOrderBy))]);
|
|
1602
1644
|
}
|
|
1603
|
-
function buildCorrelatedIncludeProjection(contract, parentSource, include) {
|
|
1645
|
+
function buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include) {
|
|
1604
1646
|
if (include.scalar) {
|
|
1605
|
-
const scalarSelect = buildIncludeChildScalarSelect(contract, parentSource, include, include.scalar);
|
|
1647
|
+
const scalarSelect = buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, include.scalar);
|
|
1606
1648
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(scalarSelect)) };
|
|
1607
1649
|
}
|
|
1608
1650
|
if (include.combine) {
|
|
1609
|
-
const combineSelect = buildIncludeChildCombineSelect(contract, parentSource, include, include.combine);
|
|
1651
|
+
const combineSelect = buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, include.combine);
|
|
1610
1652
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(combineSelect)) };
|
|
1611
1653
|
}
|
|
1612
|
-
const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, parentSource, include);
|
|
1654
|
+
const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include);
|
|
1613
1655
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(aggregateQuery)) };
|
|
1614
1656
|
}
|
|
1615
1657
|
function buildSelectAst(contract, tableName, state, options) {
|
|
@@ -1686,7 +1728,7 @@ function compileSelect(contract, namespaceId, tableName, state, modelName) {
|
|
|
1686
1728
|
const { params } = deriveParamsFromAst(ast);
|
|
1687
1729
|
return buildOrmQueryPlan(contract, ast, params, state.annotations);
|
|
1688
1730
|
}
|
|
1689
|
-
function compileSelectWithIncludes(contract, namespaceId, tableName, state, modelName) {
|
|
1731
|
+
function compileSelectWithIncludes(contract, aggregates, namespaceId, tableName, state, modelName) {
|
|
1690
1732
|
const includeJoins = [];
|
|
1691
1733
|
const includeProjection = [];
|
|
1692
1734
|
const topLevelWhere = buildStateWhere(contract, tableName, state, { namespaceId });
|
|
@@ -1710,7 +1752,7 @@ function compileSelectWithIncludes(contract, namespaceId, tableName, state, mode
|
|
|
1710
1752
|
variantColumnsProjected: false
|
|
1711
1753
|
};
|
|
1712
1754
|
for (const include of state.includes) {
|
|
1713
|
-
const artifact = buildCorrelatedIncludeProjection(contract, parentSource, include);
|
|
1755
|
+
const artifact = buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include);
|
|
1714
1756
|
includeProjection.push(artifact.projection);
|
|
1715
1757
|
}
|
|
1716
1758
|
const ast = buildSelectAst(contract, tableName, {
|
|
@@ -1829,7 +1871,7 @@ function dispatchWithIncludes(options) {
|
|
|
1829
1871
|
const generator = async function* () {
|
|
1830
1872
|
const { scope, release } = await acquireRuntimeScope(runtime);
|
|
1831
1873
|
try {
|
|
1832
|
-
const parentRowsRaw = await executeQueryPlan(scope, compileSelectWithIncludes(contract, namespaceId, tableName, state, modelName)).toArray();
|
|
1874
|
+
const parentRowsRaw = await executeQueryPlan(scope, compileSelectWithIncludes(contract, context.aggregateDescriptors, namespaceId, tableName, state, modelName)).toArray();
|
|
1833
1875
|
if (parentRowsRaw.length === 0) return;
|
|
1834
1876
|
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
1835
1877
|
const parentRows = parentRowsRaw.map((row) => {
|
|
@@ -1927,7 +1969,7 @@ function buildIdentityInFilter(contract, namespaceId, tableName, identityColumns
|
|
|
1927
1969
|
* declared shape (see `decodeCombineIncludePayload`).
|
|
1928
1970
|
*/
|
|
1929
1971
|
async function decodeIncludePayload(contract, context, include, raw) {
|
|
1930
|
-
if (include.scalar) return Promise.resolve(decodeScalarIncludePayload(include, include.scalar, raw));
|
|
1972
|
+
if (include.scalar) return Promise.resolve(decodeScalarIncludePayload(contract, context, include, include.scalar, raw));
|
|
1931
1973
|
if (include.combine) return decodeCombineIncludePayload(contract, context, include, include.combine, raw);
|
|
1932
1974
|
const rawChildren = parseIncludedRows(include, raw);
|
|
1933
1975
|
const polyInfo = resolvePolymorphismInfo(contract, include.relatedNamespaceId, include.relatedModelName);
|
|
@@ -2001,6 +2043,7 @@ async function decodeIncludedColumnValue(ref, codecId, codec, value) {
|
|
|
2001
2043
|
}
|
|
2002
2044
|
return decodeIncludedJsonValue(ref, codecId, codec, value);
|
|
2003
2045
|
}
|
|
2046
|
+
/** `ref` names the value for a decode failure; an aggregate names its relation where a column would name itself. */
|
|
2004
2047
|
function decodeIncludedJsonValue(ref, codecId, codec, value) {
|
|
2005
2048
|
try {
|
|
2006
2049
|
return codec.decodeJson(blindCast(value));
|
|
@@ -2053,7 +2096,7 @@ async function decodeCombineIncludePayload(contract, context, include, branches,
|
|
|
2053
2096
|
scalar: void 0,
|
|
2054
2097
|
combine: void 0
|
|
2055
2098
|
}, branchRaw);
|
|
2056
|
-
else result[branchName] = decodeScalarIncludePayload(include, branch.selector, branchRaw);
|
|
2099
|
+
else result[branchName] = decodeScalarIncludePayload(contract, context, include, branch.selector, branchRaw);
|
|
2057
2100
|
}
|
|
2058
2101
|
return result;
|
|
2059
2102
|
}
|
|
@@ -2086,8 +2129,9 @@ function describeEnvelopeShape(value) {
|
|
|
2086
2129
|
* loudly naming the include relation rather than soft-handling.
|
|
2087
2130
|
* Mirrors `parseCombineEnvelope`'s strict shape gate.
|
|
2088
2131
|
*
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2132
|
+
* The value passes through its own codec — the one the planner projected it
|
|
2133
|
+
* under — because it arrived inside a JSON document, where a count past 2^53
|
|
2134
|
+
* would otherwise have been read as a rounded number. SQL semantics drive the
|
|
2091
2135
|
* empty-relation case: `COUNT(*)` over an empty input set is `0`;
|
|
2092
2136
|
* `SUM` / `AVG` / `MIN` / `MAX` over an empty input set return SQL
|
|
2093
2137
|
* `NULL`, which surfaces as `null` here. The outer `raw === null`
|
|
@@ -2095,11 +2139,24 @@ function describeEnvelopeShape(value) {
|
|
|
2095
2139
|
* dispatch the correlated subquery always produces a row, so the inner
|
|
2096
2140
|
* envelope's `value` is always set by SQL.
|
|
2097
2141
|
*/
|
|
2098
|
-
function decodeScalarIncludePayload(include, scalar, raw) {
|
|
2099
|
-
if (raw === null || raw === void 0) return
|
|
2142
|
+
function decodeScalarIncludePayload(contract, context, include, scalar, raw) {
|
|
2143
|
+
if (raw === null || raw === void 0) return emptyAggregateResult(scalar.fn);
|
|
2100
2144
|
const parsed = parseIncludePayload(raw);
|
|
2101
2145
|
if (!isPlainObjectEnvelope(parsed)) throw new InternalError(`scalar() envelope for include "${include.relationName}" has unexpected shape (expected object, got ${describeEnvelopeShape(parsed)}); this indicates a planner or decoder bug.`);
|
|
2102
|
-
|
|
2146
|
+
const value = parsed["value"];
|
|
2147
|
+
if (value === null || value === void 0) return emptyAggregateResult(scalar.fn);
|
|
2148
|
+
const codecRef = resolveAggregateOutputCodec({
|
|
2149
|
+
aggregates: context.aggregateDescriptors,
|
|
2150
|
+
contract,
|
|
2151
|
+
namespaceId: include.relatedNamespaceId,
|
|
2152
|
+
tableName: include.relatedTableName,
|
|
2153
|
+
fn: scalar.fn,
|
|
2154
|
+
column: scalar.column
|
|
2155
|
+
});
|
|
2156
|
+
return decodeIncludedJsonValue({
|
|
2157
|
+
table: include.relatedTableName,
|
|
2158
|
+
column: include.relationName
|
|
2159
|
+
}, codecRef.codecId, context.contractCodecs.forCodecRef(codecRef), value);
|
|
2103
2160
|
}
|
|
2104
2161
|
function parseIncludedRows(include, value) {
|
|
2105
2162
|
if (value === null || value === void 0) return [];
|
|
@@ -2123,9 +2180,6 @@ function parseIncludePayload(value) {
|
|
|
2123
2180
|
function coerceSingleQueryIncludeResult(rows, cardinality) {
|
|
2124
2181
|
return isToOneCardinality(cardinality) ? rows[0] ?? null : rows;
|
|
2125
2182
|
}
|
|
2126
|
-
function emptyScalarResult(fn) {
|
|
2127
|
-
return fn === "count" ? 0 : null;
|
|
2128
|
-
}
|
|
2129
2183
|
function createMutationRowMapper(contract, namespaceId, modelName, variantName) {
|
|
2130
2184
|
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
2131
2185
|
return polyInfo ? (row) => mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, row, variantName) : (row) => mapStorageRowToModelFields(contract, namespaceId, modelName, row);
|
|
@@ -2308,10 +2362,10 @@ var GroupedCollection = class GroupedCollection {
|
|
|
2308
2362
|
configure(meta);
|
|
2309
2363
|
if (meta.annotations.size > 0) annotationsMap = meta.annotations;
|
|
2310
2364
|
}
|
|
2311
|
-
const compiled = mergeAnnotations(compileGroupedAggregate(this.contract, this.namespaceId, this.tableName, this.baseFilters, this.groupByColumns, aggregateSpec, combineWhereExprs(this.havingFilters)), annotationsMap);
|
|
2365
|
+
const compiled = mergeAnnotations(compileGroupedAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.baseFilters, this.groupByColumns, aggregateSpec, combineWhereExprs(this.havingFilters)), annotationsMap);
|
|
2312
2366
|
return (await executeQueryPlan(this.ctx.runtime, compiled).toArray()).map((row) => {
|
|
2313
2367
|
const mapped = mapStorageRowToModelFields(this.contract, this.namespaceId, this.modelName, row);
|
|
2314
|
-
for (const [alias
|
|
2368
|
+
for (const [alias] of aggregateEntries) mapped[alias] = row[alias];
|
|
2315
2369
|
return mapped;
|
|
2316
2370
|
});
|
|
2317
2371
|
}
|
|
@@ -2360,17 +2414,6 @@ function createHavingComparisonMethods(metric) {
|
|
|
2360
2414
|
}
|
|
2361
2415
|
};
|
|
2362
2416
|
}
|
|
2363
|
-
function coerceAggregateValue(fn, value) {
|
|
2364
|
-
if (value === null) return null;
|
|
2365
|
-
if (value === void 0) return fn === "count" ? 0 : null;
|
|
2366
|
-
if (typeof value === "number") return value;
|
|
2367
|
-
if (typeof value === "bigint") return Number(value);
|
|
2368
|
-
if (typeof value === "string") {
|
|
2369
|
-
const numeric = Number(value);
|
|
2370
|
-
return Number.isNaN(numeric) ? value : numeric;
|
|
2371
|
-
}
|
|
2372
|
-
return value;
|
|
2373
|
-
}
|
|
2374
2417
|
const aggregateFns = /* @__PURE__ */ new Set([
|
|
2375
2418
|
"count",
|
|
2376
2419
|
"sum",
|
|
@@ -3400,7 +3443,7 @@ var Collection = class Collection {
|
|
|
3400
3443
|
* .where({ published: true })
|
|
3401
3444
|
* .groupBy('userId')
|
|
3402
3445
|
* .aggregate((agg) => ({ count: agg.count(), totalViews: agg.sum('views') }));
|
|
3403
|
-
* // [{ userId: 1, count:
|
|
3446
|
+
* // [{ userId: 1, count: 3n, totalViews: 120n }, ...]
|
|
3404
3447
|
* ```
|
|
3405
3448
|
*/
|
|
3406
3449
|
groupBy(...fields) {
|
|
@@ -3423,7 +3466,7 @@ var Collection = class Collection {
|
|
|
3423
3466
|
*
|
|
3424
3467
|
* ```typescript
|
|
3425
3468
|
* const users = await db.orm.User.include('posts', (posts) => posts.count()).all();
|
|
3426
|
-
* // each user row: { ...user, posts:
|
|
3469
|
+
* // each user row: { ...user, posts: bigint }
|
|
3427
3470
|
* ```
|
|
3428
3471
|
*/
|
|
3429
3472
|
count() {
|
|
@@ -3438,7 +3481,7 @@ var Collection = class Collection {
|
|
|
3438
3481
|
*
|
|
3439
3482
|
* ```typescript
|
|
3440
3483
|
* const users = await db.orm.User.include('posts', (posts) => posts.sum('views')).all();
|
|
3441
|
-
* // each user row: { ...user, posts:
|
|
3484
|
+
* // each user row: { ...user, posts: bigint | null } — an int4 column's sum widens to int8
|
|
3442
3485
|
* ```
|
|
3443
3486
|
*/
|
|
3444
3487
|
sum(field) {
|
|
@@ -3454,7 +3497,7 @@ var Collection = class Collection {
|
|
|
3454
3497
|
*
|
|
3455
3498
|
* ```typescript
|
|
3456
3499
|
* const users = await db.orm.User.include('posts', (posts) => posts.avg('views')).all();
|
|
3457
|
-
* // each user row: { ...user, posts:
|
|
3500
|
+
* // each user row: { ...user, posts: string | null } — PostgreSQL averages integers as numeric
|
|
3458
3501
|
* ```
|
|
3459
3502
|
*/
|
|
3460
3503
|
avg(field) {
|
|
@@ -3509,7 +3552,7 @@ var Collection = class Collection {
|
|
|
3509
3552
|
* ).all();
|
|
3510
3553
|
* // each user row: {
|
|
3511
3554
|
* // ...user,
|
|
3512
|
-
* // posts: { recent: Post[]; total:
|
|
3555
|
+
* // posts: { recent: Post[]; total: bigint; averageViews: string | null };
|
|
3513
3556
|
* // }
|
|
3514
3557
|
* ```
|
|
3515
3558
|
*/
|
|
@@ -3681,7 +3724,7 @@ var Collection = class Collection {
|
|
|
3681
3724
|
* averageViews: agg.avg('views'),
|
|
3682
3725
|
* maxViews: agg.max('views'),
|
|
3683
3726
|
* }));
|
|
3684
|
-
* // { total:
|
|
3727
|
+
* // { total: 42n, averageViews: '17.3000000000000000', maxViews: 9001 }
|
|
3685
3728
|
* ```
|
|
3686
3729
|
*
|
|
3687
3730
|
* Accepts an optional `configure` callback that receives a
|
|
@@ -3701,8 +3744,11 @@ var Collection = class Collection {
|
|
|
3701
3744
|
alias
|
|
3702
3745
|
} });
|
|
3703
3746
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "read", "aggregate");
|
|
3704
|
-
const compiled = mergeAnnotations(compileAggregate(this.contract, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
|
|
3705
|
-
|
|
3747
|
+
const compiled = mergeAnnotations(compileAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
|
|
3748
|
+
const row = (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {};
|
|
3749
|
+
const result = {};
|
|
3750
|
+
for (const [alias, selector] of entries) result[alias] = row[alias] ?? emptyAggregateResult(selector.fn);
|
|
3751
|
+
return blindCast(result);
|
|
3706
3752
|
}
|
|
3707
3753
|
async create(data, configure) {
|
|
3708
3754
|
assertReturningCapability(this.contract, "create()");
|