@prisma/orm-family-sql 0.17.0-dev.1 → 0.17.0-dev.11
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-Bb6loOw9.d.mts} +15 -19
- package/dist/ast-Bb6loOw9.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-BWngBFMj.d.mts} +10 -10
- package/dist/{control-BHmsZudH.d.mts.map → control-BWngBFMj.d.mts.map} +1 -1
- package/dist/{control-B7iS4jv4.mjs → control-C1EmRznB.mjs} +2 -2
- package/dist/{control-B7iS4jv4.mjs.map → control-C1EmRznB.mjs.map} +1 -1
- package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts → control-adapter-C99J7aEF-Cmay9zFj.d.mts} +6 -6
- package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts.map → control-adapter-C99J7aEF-Cmay9zFj.d.mts.map} +1 -1
- package/dist/control-adapter-DrCAQQpa.d.mts +1 -0
- package/dist/{db-DhMsmBS--DKENDi3l.d.mts → db-B5PMfDDd-BsvBY8Wh.d.mts} +65 -32
- package/dist/db-B5PMfDDd-BsvBY8Wh.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-DnLtQXpg.d.mts} +5 -5
- package/dist/{diff-DhlzHOMD.d.mts.map → diff-DnLtQXpg.d.mts.map} +1 -1
- package/dist/{dist-DrScXbhq.mjs → dist-DtLVFgdI.mjs} +62 -9
- package/dist/dist-DtLVFgdI.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-Bb9U36N4.d.mts → index-BOhWLVvH.d.mts} +15 -16
- package/dist/index-BOhWLVvH.d.mts.map +1 -0
- 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-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-BvCT6g2N.d.mts} +3 -3
- package/dist/{migration-CW0ZJLxP.d.mts.map → migration-BvCT6g2N.d.mts.map} +1 -1
- package/dist/operations.d.mts +1 -1
- package/dist/orm-client.d.mts +90 -45
- package/dist/orm-client.d.mts.map +1 -1
- package/dist/orm-client.mjs +274 -157
- 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 +4 -5
- 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-AvfMMERk.d.mts} +2 -2
- package/dist/{runtime-DNewRuec.d.mts.map → runtime-AvfMMERk.d.mts.map} +1 -1
- package/dist/runtime.d.mts +3 -3
- package/dist/runtime.mjs +16 -7
- 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-D8PN7ygS.d.mts} +5 -5
- package/dist/{types-IqZMLrFC-DtdJNICr.d.mts.map → types-IqZMLrFC-D8PN7ygS.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 +19 -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,7 +1508,15 @@ 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) {
|
|
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
|
+
});
|
|
1485
1520
|
const parentLocalRefs = resolveParentLocalRefs(parentSource, include, localColumnsForRowInclude(include));
|
|
1486
1521
|
const childSource = resolveChildTableSource(include, parentLocalRefs);
|
|
1487
1522
|
const childTableAlias = childSource.alias;
|
|
@@ -1507,8 +1542,8 @@ function buildIncludeChildScalarSelect(contract, parentSource, include, scalar)
|
|
|
1507
1542
|
const hasPagination = state.limit !== void 0 || state.offset !== void 0;
|
|
1508
1543
|
const hasDistinct = state.distinct !== void 0 && state.distinct.length > 0 || state.distinctOn !== void 0 && state.distinctOn.length > 0;
|
|
1509
1544
|
if (!(hasPagination || hasDistinct)) {
|
|
1510
|
-
const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef);
|
|
1511
|
-
const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, {}))]);
|
|
1545
|
+
const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef, resultLowering, inputCodec);
|
|
1546
|
+
const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, { codec: resultCodec }))]);
|
|
1512
1547
|
let select = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection([ProjectionItem.of(include.relationName, jsonObjectExpr)]).withWhere(whereExpr);
|
|
1513
1548
|
if (junctionJoins.length > 0) select = select.withJoins(junctionJoins);
|
|
1514
1549
|
return select;
|
|
@@ -1533,21 +1568,17 @@ function buildIncludeChildScalarSelect(contract, parentSource, include, scalar)
|
|
|
1533
1568
|
} else if (remappedOrderBy !== void 0 && remappedOrderBy.length > 0) inner = inner.withOrderBy(remappedOrderBy);
|
|
1534
1569
|
if (state.limit !== void 0) inner = inner.withLimit(state.limit);
|
|
1535
1570
|
if (state.offset !== void 0) inner = inner.withOffset(state.offset);
|
|
1536
|
-
const outerAggregateExpr = buildIncludeAggregateExpr(scalar, innerAlias);
|
|
1537
|
-
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 }))]);
|
|
1538
1573
|
return SelectAst.from(DerivedTableSource.as(innerAlias, inner)).withProjection([ProjectionItem.of(include.relationName, outerJsonObjectExpr)]);
|
|
1539
1574
|
}
|
|
1540
|
-
function buildIncludeAggregateExpr(scalar, childTableRef) {
|
|
1541
|
-
|
|
1542
|
-
if (
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
case "min": return AggregateExpr.min(columnRef);
|
|
1548
|
-
case "max": return AggregateExpr.max(columnRef);
|
|
1549
|
-
default: return assertNever(scalar.fn);
|
|
1550
|
-
}
|
|
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);
|
|
1551
1582
|
}
|
|
1552
1583
|
/**
|
|
1553
1584
|
* Build the inner SELECT for a `combine({ a, b, ... })` include.
|
|
@@ -1568,13 +1599,13 @@ function buildIncludeAggregateExpr(scalar, childTableRef) {
|
|
|
1568
1599
|
* branch fan out naturally because the row builder is invoked with
|
|
1569
1600
|
* a synthetic IncludeExpr whose `nested` is the branch's state.
|
|
1570
1601
|
*/
|
|
1571
|
-
function buildIncludeChildCombineSelect(contract, parentSource, include, branches) {
|
|
1602
|
+
function buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, branches) {
|
|
1572
1603
|
const branchEntries = Object.entries(branches);
|
|
1573
1604
|
if (branchEntries.length === 0) throw ormError("ORM.INCLUDE_INVALID", `combine() include "${include.relationName}" has no branches`, { meta: { relation: include.relationName } });
|
|
1574
1605
|
const compiledBranches = branchEntries.map(([name, branch]) => ({
|
|
1575
1606
|
name,
|
|
1576
1607
|
alias: `${include.relationName}__combine__${name}`,
|
|
1577
|
-
select: buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch)
|
|
1608
|
+
select: buildIncludeChildCombineBranchSelect(contract, aggregates, parentSource, include, branch)
|
|
1578
1609
|
}));
|
|
1579
1610
|
const jsonObjectExpr = JsonObjectExpr.fromEntries(compiledBranches.map((branch) => JsonObjectExpr.entry(branch.name, jsonEntryProjection(ColumnRef.of(branch.alias, include.relationName), { document: true }))));
|
|
1580
1611
|
const [firstBranch, ...restBranches] = compiledBranches;
|
|
@@ -1588,9 +1619,9 @@ function buildIncludeChildCombineSelect(contract, parentSource, include, branche
|
|
|
1588
1619
|
* relation name. Dispatches to the standalone scalar / row builders
|
|
1589
1620
|
* with the branch's state spliced into a synthetic IncludeExpr.
|
|
1590
1621
|
*/
|
|
1591
|
-
function buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch) {
|
|
1592
|
-
if (branch.kind === "scalar") return buildIncludeChildScalarSelect(contract, parentSource, include, branch.selector);
|
|
1593
|
-
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, {
|
|
1594
1625
|
...include,
|
|
1595
1626
|
nested: branch.state,
|
|
1596
1627
|
scalar: void 0,
|
|
@@ -1603,24 +1634,24 @@ function buildIncludeChildCombineBranchSelect(contract, parentSource, include, b
|
|
|
1603
1634
|
* name. Used by both the standalone row correlated-subquery path and
|
|
1604
1635
|
* by combine's row branches.
|
|
1605
1636
|
*/
|
|
1606
|
-
function buildIncludeChildRowsAggregateSelect(contract, parentSource, include) {
|
|
1607
|
-
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);
|
|
1608
1639
|
const jsonObjectExpr = JsonObjectExpr.fromEntries(childProjection.map((item) => JsonObjectExpr.entry(item.alias, jsonEntryProjection(ColumnRef.of(rowsAlias, item.alias), {
|
|
1609
1640
|
codec: item.codec,
|
|
1610
1641
|
document: documentAliases.has(item.alias)
|
|
1611
1642
|
}))));
|
|
1612
1643
|
return SelectAst.from(DerivedTableSource.as(rowsAlias, childRows)).withProjection([ProjectionItem.of(include.relationName, JsonArrayAggExpr.of(jsonEntryProjection(jsonObjectExpr, { document: true }), "emptyArray", aggregateOrderBy))]);
|
|
1613
1644
|
}
|
|
1614
|
-
function buildCorrelatedIncludeProjection(contract, parentSource, include) {
|
|
1645
|
+
function buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include) {
|
|
1615
1646
|
if (include.scalar) {
|
|
1616
|
-
const scalarSelect = buildIncludeChildScalarSelect(contract, parentSource, include, include.scalar);
|
|
1647
|
+
const scalarSelect = buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, include.scalar);
|
|
1617
1648
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(scalarSelect)) };
|
|
1618
1649
|
}
|
|
1619
1650
|
if (include.combine) {
|
|
1620
|
-
const combineSelect = buildIncludeChildCombineSelect(contract, parentSource, include, include.combine);
|
|
1651
|
+
const combineSelect = buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, include.combine);
|
|
1621
1652
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(combineSelect)) };
|
|
1622
1653
|
}
|
|
1623
|
-
const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, parentSource, include);
|
|
1654
|
+
const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include);
|
|
1624
1655
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(aggregateQuery)) };
|
|
1625
1656
|
}
|
|
1626
1657
|
function buildSelectAst(contract, tableName, state, options) {
|
|
@@ -1697,7 +1728,7 @@ function compileSelect(contract, namespaceId, tableName, state, modelName) {
|
|
|
1697
1728
|
const { params } = deriveParamsFromAst(ast);
|
|
1698
1729
|
return buildOrmQueryPlan(contract, ast, params, state.annotations);
|
|
1699
1730
|
}
|
|
1700
|
-
function compileSelectWithIncludes(contract, namespaceId, tableName, state, modelName) {
|
|
1731
|
+
function compileSelectWithIncludes(contract, aggregates, namespaceId, tableName, state, modelName) {
|
|
1701
1732
|
const includeJoins = [];
|
|
1702
1733
|
const includeProjection = [];
|
|
1703
1734
|
const topLevelWhere = buildStateWhere(contract, tableName, state, { namespaceId });
|
|
@@ -1721,7 +1752,7 @@ function compileSelectWithIncludes(contract, namespaceId, tableName, state, mode
|
|
|
1721
1752
|
variantColumnsProjected: false
|
|
1722
1753
|
};
|
|
1723
1754
|
for (const include of state.includes) {
|
|
1724
|
-
const artifact = buildCorrelatedIncludeProjection(contract, parentSource, include);
|
|
1755
|
+
const artifact = buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include);
|
|
1725
1756
|
includeProjection.push(artifact.projection);
|
|
1726
1757
|
}
|
|
1727
1758
|
const ast = buildSelectAst(contract, tableName, {
|
|
@@ -1840,7 +1871,7 @@ function dispatchWithIncludes(options) {
|
|
|
1840
1871
|
const generator = async function* () {
|
|
1841
1872
|
const { scope, release } = await acquireRuntimeScope(runtime);
|
|
1842
1873
|
try {
|
|
1843
|
-
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();
|
|
1844
1875
|
if (parentRowsRaw.length === 0) return;
|
|
1845
1876
|
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
1846
1877
|
const parentRows = parentRowsRaw.map((row) => {
|
|
@@ -1938,7 +1969,7 @@ function buildIdentityInFilter(contract, namespaceId, tableName, identityColumns
|
|
|
1938
1969
|
* declared shape (see `decodeCombineIncludePayload`).
|
|
1939
1970
|
*/
|
|
1940
1971
|
async function decodeIncludePayload(contract, context, include, raw) {
|
|
1941
|
-
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));
|
|
1942
1973
|
if (include.combine) return decodeCombineIncludePayload(contract, context, include, include.combine, raw);
|
|
1943
1974
|
const rawChildren = parseIncludedRows(include, raw);
|
|
1944
1975
|
const polyInfo = resolvePolymorphismInfo(contract, include.relatedNamespaceId, include.relatedModelName);
|
|
@@ -2012,6 +2043,7 @@ async function decodeIncludedColumnValue(ref, codecId, codec, value) {
|
|
|
2012
2043
|
}
|
|
2013
2044
|
return decodeIncludedJsonValue(ref, codecId, codec, value);
|
|
2014
2045
|
}
|
|
2046
|
+
/** `ref` names the value for a decode failure; an aggregate names its relation where a column would name itself. */
|
|
2015
2047
|
function decodeIncludedJsonValue(ref, codecId, codec, value) {
|
|
2016
2048
|
try {
|
|
2017
2049
|
return codec.decodeJson(blindCast(value));
|
|
@@ -2064,7 +2096,7 @@ async function decodeCombineIncludePayload(contract, context, include, branches,
|
|
|
2064
2096
|
scalar: void 0,
|
|
2065
2097
|
combine: void 0
|
|
2066
2098
|
}, branchRaw);
|
|
2067
|
-
else result[branchName] = decodeScalarIncludePayload(include, branch.selector, branchRaw);
|
|
2099
|
+
else result[branchName] = decodeScalarIncludePayload(contract, context, include, branch.selector, branchRaw);
|
|
2068
2100
|
}
|
|
2069
2101
|
return result;
|
|
2070
2102
|
}
|
|
@@ -2097,8 +2129,9 @@ function describeEnvelopeShape(value) {
|
|
|
2097
2129
|
* loudly naming the include relation rather than soft-handling.
|
|
2098
2130
|
* Mirrors `parseCombineEnvelope`'s strict shape gate.
|
|
2099
2131
|
*
|
|
2100
|
-
*
|
|
2101
|
-
*
|
|
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
|
|
2102
2135
|
* empty-relation case: `COUNT(*)` over an empty input set is `0`;
|
|
2103
2136
|
* `SUM` / `AVG` / `MIN` / `MAX` over an empty input set return SQL
|
|
2104
2137
|
* `NULL`, which surfaces as `null` here. The outer `raw === null`
|
|
@@ -2106,11 +2139,24 @@ function describeEnvelopeShape(value) {
|
|
|
2106
2139
|
* dispatch the correlated subquery always produces a row, so the inner
|
|
2107
2140
|
* envelope's `value` is always set by SQL.
|
|
2108
2141
|
*/
|
|
2109
|
-
function decodeScalarIncludePayload(include, scalar, raw) {
|
|
2110
|
-
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);
|
|
2111
2144
|
const parsed = parseIncludePayload(raw);
|
|
2112
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.`);
|
|
2113
|
-
|
|
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);
|
|
2114
2160
|
}
|
|
2115
2161
|
function parseIncludedRows(include, value) {
|
|
2116
2162
|
if (value === null || value === void 0) return [];
|
|
@@ -2134,9 +2180,6 @@ function parseIncludePayload(value) {
|
|
|
2134
2180
|
function coerceSingleQueryIncludeResult(rows, cardinality) {
|
|
2135
2181
|
return isToOneCardinality(cardinality) ? rows[0] ?? null : rows;
|
|
2136
2182
|
}
|
|
2137
|
-
function emptyScalarResult(fn) {
|
|
2138
|
-
return fn === "count" ? 0 : null;
|
|
2139
|
-
}
|
|
2140
2183
|
function createMutationRowMapper(contract, namespaceId, modelName, variantName) {
|
|
2141
2184
|
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
2142
2185
|
return polyInfo ? (row) => mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, row, variantName) : (row) => mapStorageRowToModelFields(contract, namespaceId, modelName, row);
|
|
@@ -2319,10 +2362,10 @@ var GroupedCollection = class GroupedCollection {
|
|
|
2319
2362
|
configure(meta);
|
|
2320
2363
|
if (meta.annotations.size > 0) annotationsMap = meta.annotations;
|
|
2321
2364
|
}
|
|
2322
|
-
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);
|
|
2323
2366
|
return (await executeQueryPlan(this.ctx.runtime, compiled).toArray()).map((row) => {
|
|
2324
2367
|
const mapped = mapStorageRowToModelFields(this.contract, this.namespaceId, this.modelName, row);
|
|
2325
|
-
for (const [alias
|
|
2368
|
+
for (const [alias] of aggregateEntries) mapped[alias] = row[alias];
|
|
2326
2369
|
return mapped;
|
|
2327
2370
|
});
|
|
2328
2371
|
}
|
|
@@ -2371,17 +2414,6 @@ function createHavingComparisonMethods(metric) {
|
|
|
2371
2414
|
}
|
|
2372
2415
|
};
|
|
2373
2416
|
}
|
|
2374
|
-
function coerceAggregateValue(fn, value) {
|
|
2375
|
-
if (value === null) return null;
|
|
2376
|
-
if (value === void 0) return fn === "count" ? 0 : null;
|
|
2377
|
-
if (typeof value === "number") return value;
|
|
2378
|
-
if (typeof value === "bigint") return Number(value);
|
|
2379
|
-
if (typeof value === "string") {
|
|
2380
|
-
const numeric = Number(value);
|
|
2381
|
-
return Number.isNaN(numeric) ? value : numeric;
|
|
2382
|
-
}
|
|
2383
|
-
return value;
|
|
2384
|
-
}
|
|
2385
2417
|
const aggregateFns = /* @__PURE__ */ new Set([
|
|
2386
2418
|
"count",
|
|
2387
2419
|
"sum",
|
|
@@ -2427,7 +2459,91 @@ function isCollectionState(value) {
|
|
|
2427
2459
|
function hasThrough$1(relation) {
|
|
2428
2460
|
return relation.through !== void 0;
|
|
2429
2461
|
}
|
|
2462
|
+
var SqlTableBinding = class SqlTableBinding {
|
|
2463
|
+
#storage;
|
|
2464
|
+
#reference;
|
|
2465
|
+
constructor(storage, reference) {
|
|
2466
|
+
this.#storage = Object.freeze({ ...storage });
|
|
2467
|
+
this.#reference = reference;
|
|
2468
|
+
Object.freeze(this);
|
|
2469
|
+
}
|
|
2470
|
+
static unaliased(storage) {
|
|
2471
|
+
return new SqlTableBinding(storage, storage.tableName);
|
|
2472
|
+
}
|
|
2473
|
+
static aliased(storage, alias) {
|
|
2474
|
+
return new SqlTableBinding(storage, alias);
|
|
2475
|
+
}
|
|
2476
|
+
column(columnName) {
|
|
2477
|
+
return ColumnRef.of(this.#reference, columnName);
|
|
2478
|
+
}
|
|
2479
|
+
tableSource(contract) {
|
|
2480
|
+
return tableSourceForContract(contract, this.#storage.namespaceId, this.#storage.tableName, this.#reference);
|
|
2481
|
+
}
|
|
2482
|
+
isReferencedAs(candidate) {
|
|
2483
|
+
return this.#reference === candidate;
|
|
2484
|
+
}
|
|
2485
|
+
isStoredAt(namespaceId, tableName) {
|
|
2486
|
+
return this.#storage.namespaceId === namespaceId && this.#storage.tableName === tableName;
|
|
2487
|
+
}
|
|
2488
|
+
};
|
|
2489
|
+
var ModelAccessorScope = class ModelAccessorScope {
|
|
2490
|
+
current;
|
|
2491
|
+
#visibleBindings;
|
|
2492
|
+
#aliasCounter;
|
|
2493
|
+
constructor(current, visibleBindings, aliasCounter) {
|
|
2494
|
+
this.current = current;
|
|
2495
|
+
this.#visibleBindings = Object.freeze([...visibleBindings]);
|
|
2496
|
+
this.#aliasCounter = aliasCounter;
|
|
2497
|
+
Object.freeze(this);
|
|
2498
|
+
}
|
|
2499
|
+
static root(namespaceId, tableName) {
|
|
2500
|
+
const binding = SqlTableBinding.unaliased({
|
|
2501
|
+
namespaceId,
|
|
2502
|
+
tableName
|
|
2503
|
+
});
|
|
2504
|
+
return new ModelAccessorScope(binding, [binding], { nextId: 1 });
|
|
2505
|
+
}
|
|
2506
|
+
forRelation(namespaceId, tableName) {
|
|
2507
|
+
const binding = this.#allocateBinding(namespaceId, tableName, "rel");
|
|
2508
|
+
return new ModelAccessorScope(binding, [...this.#visibleBindings, binding], this.#aliasCounter);
|
|
2509
|
+
}
|
|
2510
|
+
forManyToManyRelation(childNamespaceId, childTableName, junctionNamespaceId, junctionTableName) {
|
|
2511
|
+
const initialChildScope = this.forRelation(childNamespaceId, childTableName);
|
|
2512
|
+
const junctionBinding = initialChildScope.#allocateBinding(junctionNamespaceId, junctionTableName, "junction");
|
|
2513
|
+
return {
|
|
2514
|
+
childScope: new ModelAccessorScope(initialChildScope.current, [...initialChildScope.#visibleBindings, junctionBinding], this.#aliasCounter),
|
|
2515
|
+
junctionBinding
|
|
2516
|
+
};
|
|
2517
|
+
}
|
|
2518
|
+
forJoinedSource(namespaceId, tableName) {
|
|
2519
|
+
if (this.current.isStoredAt(namespaceId, tableName)) return this;
|
|
2520
|
+
const binding = SqlTableBinding.unaliased({
|
|
2521
|
+
namespaceId,
|
|
2522
|
+
tableName
|
|
2523
|
+
});
|
|
2524
|
+
return new ModelAccessorScope(binding, [...this.#visibleBindings, binding], this.#aliasCounter);
|
|
2525
|
+
}
|
|
2526
|
+
#allocateBinding(namespaceId, tableName, aliasKind) {
|
|
2527
|
+
const storage = {
|
|
2528
|
+
namespaceId,
|
|
2529
|
+
tableName
|
|
2530
|
+
};
|
|
2531
|
+
if (!this.#visibleBindings.some((binding) => binding.isReferencedAs(tableName))) return SqlTableBinding.unaliased(storage);
|
|
2532
|
+
return SqlTableBinding.aliased(storage, this.#allocateAlias(aliasKind));
|
|
2533
|
+
}
|
|
2534
|
+
#allocateAlias(kind) {
|
|
2535
|
+
while (true) {
|
|
2536
|
+
const alias = `__orm_${kind}_${this.#aliasCounter.nextId}`;
|
|
2537
|
+
this.#aliasCounter.nextId += 1;
|
|
2538
|
+
if (!this.#visibleBindings.some((binding) => binding.isReferencedAs(alias))) return alias;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2430
2542
|
function createModelAccessor(context, namespaceId, modelName, variantName) {
|
|
2543
|
+
const tableName = resolveModelTableName(context.contract, namespaceId, modelName);
|
|
2544
|
+
return createModelAccessorInScope(context, namespaceId, modelName, variantName, ModelAccessorScope.root(namespaceId, tableName));
|
|
2545
|
+
}
|
|
2546
|
+
function createModelAccessorInScope(context, namespaceId, modelName, variantName, scope) {
|
|
2431
2547
|
const contract = context.contract;
|
|
2432
2548
|
const fieldToColumn = getFieldToColumnMap(contract, namespaceId, modelName);
|
|
2433
2549
|
const tableName = resolveModelTableName(contract, namespaceId, modelName);
|
|
@@ -2461,19 +2577,20 @@ function createModelAccessor(context, namespaceId, modelName, variantName) {
|
|
|
2461
2577
|
if (typeof prop !== "string") return;
|
|
2462
2578
|
if (variantCoordinates) {
|
|
2463
2579
|
const variantRelation = variantCoordinates.relations[prop];
|
|
2464
|
-
if (variantRelation) return createRelationFilterAccessor(context, namespaceId, variantCoordinates.name, variantCoordinates.tableName,
|
|
2580
|
+
if (variantRelation) return createRelationFilterAccessor(context, namespaceId, variantCoordinates.name, scope.forJoinedSource(namespaceId, variantCoordinates.tableName), variantRelation);
|
|
2465
2581
|
}
|
|
2466
2582
|
const relation = modelRelations[prop];
|
|
2467
|
-
if (relation) return createRelationFilterAccessor(context, namespaceId, modelName,
|
|
2583
|
+
if (relation) return createRelationFilterAccessor(context, namespaceId, modelName, scope, relation);
|
|
2468
2584
|
const variantField = variantFieldColumns[prop];
|
|
2469
2585
|
const resolvedTable = variantField?.table ?? tableName;
|
|
2586
|
+
const fieldBinding = scope.forJoinedSource(namespaceId, resolvedTable).current;
|
|
2470
2587
|
const columnName = variantField?.column ?? fieldToColumn[prop] ?? prop;
|
|
2471
2588
|
const column = resolveColumn(contract, namespaceId, resolvedTable, columnName);
|
|
2472
2589
|
if (!column) return;
|
|
2473
2590
|
const traits = context.codecDescriptors.descriptorFor(column.codecId)?.traits ?? [];
|
|
2474
2591
|
const operations = opsByCodecId.get(column.codecId) ?? [];
|
|
2475
2592
|
const codec = codecRefForStorageColumn(contract.storage, namespaceId, resolvedTable, columnName);
|
|
2476
|
-
return createScalarFieldAccessor(
|
|
2593
|
+
return createScalarFieldAccessor(fieldBinding, columnName, column.codecId, column.nullable, codec, traits, operations, context);
|
|
2477
2594
|
} }));
|
|
2478
2595
|
}
|
|
2479
2596
|
function resolveColumn(contract, namespaceId, tableName, columnName) {
|
|
@@ -2490,8 +2607,8 @@ function resolveColumn(contract, namespaceId, tableName, columnName) {
|
|
|
2490
2607
|
nullable: column.nullable
|
|
2491
2608
|
};
|
|
2492
2609
|
}
|
|
2493
|
-
function createScalarFieldAccessor(
|
|
2494
|
-
const column =
|
|
2610
|
+
function createScalarFieldAccessor(tableBinding, columnName, codecId, nullable, codec, traits, operations, context) {
|
|
2611
|
+
const column = tableBinding.column(columnName);
|
|
2495
2612
|
const comparisonEntries = [];
|
|
2496
2613
|
for (const [name, meta] of Object.entries(COMPARISON_METHODS_META)) {
|
|
2497
2614
|
if (meta.traits.some((t) => !traits.includes(t))) continue;
|
|
@@ -2526,42 +2643,41 @@ function createExtensionMethodFactory(selfExpr, entry, context) {
|
|
|
2526
2643
|
return methods;
|
|
2527
2644
|
};
|
|
2528
2645
|
}
|
|
2529
|
-
function createRelationFilterAccessor(context, parentNamespaceId, parentModelName,
|
|
2646
|
+
function createRelationFilterAccessor(context, parentNamespaceId, parentModelName, parentScope, relation) {
|
|
2530
2647
|
const relatedTableName = resolveModelTableName(context.contract, relation.toNamespace, relation.to);
|
|
2531
2648
|
return {
|
|
2532
|
-
some: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2649
|
+
some: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
|
|
2533
2650
|
mode: "some",
|
|
2534
2651
|
predicate
|
|
2535
2652
|
}),
|
|
2536
|
-
every: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2653
|
+
every: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
|
|
2537
2654
|
mode: "every",
|
|
2538
2655
|
predicate
|
|
2539
2656
|
}),
|
|
2540
|
-
none: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2657
|
+
none: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
|
|
2541
2658
|
mode: "none",
|
|
2542
2659
|
predicate
|
|
2543
2660
|
})
|
|
2544
2661
|
};
|
|
2545
2662
|
}
|
|
2546
|
-
function buildExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2547
|
-
if (hasThrough$1(relation)) return buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2548
|
-
const
|
|
2663
|
+
function buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options) {
|
|
2664
|
+
if (hasThrough$1(relation)) return buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options);
|
|
2665
|
+
const childScope = parentScope.forRelation(relation.toNamespace, relatedTableName);
|
|
2666
|
+
const filterPlan = planRelationFilterMode(buildJoinWhere(context.contract, parentNamespaceId, parentModelName, parentScope.current, childScope.current, relation), toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate, childScope), options.mode);
|
|
2549
2667
|
if (filterPlan.kind === "constantTrue") return AndExpr.true();
|
|
2550
2668
|
const selectProjectionColumn = firstTargetColumn(context.contract, relation) ?? "id";
|
|
2551
|
-
const subquery = SelectAst.from(
|
|
2669
|
+
const subquery = SelectAst.from(childScope.current.tableSource(context.contract)).withProjection([ProjectionItem.of("_exists", childScope.current.column(selectProjectionColumn))]).withWhere(filterPlan.where);
|
|
2552
2670
|
return filterPlan.notExists ? ExistsExpr.notExists(subquery) : ExistsExpr.exists(subquery);
|
|
2553
2671
|
}
|
|
2554
|
-
function buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName,
|
|
2672
|
+
function buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options) {
|
|
2555
2673
|
const { through } = relation;
|
|
2556
|
-
const
|
|
2557
|
-
const
|
|
2558
|
-
const relatedTableRef = relatedTableAlias ?? relatedTableName;
|
|
2559
|
-
const junctionJoinOn = buildPairedColumnExprs(junctionTable, through.childColumns, relatedTableRef, through.targetColumns);
|
|
2674
|
+
const { childScope, junctionBinding } = parentScope.forManyToManyRelation(relation.toNamespace, relatedTableName, through.namespaceId, through.table);
|
|
2675
|
+
const junctionJoinOn = buildPairedColumnExprs(junctionBinding, through.childColumns, childScope.current, through.targetColumns);
|
|
2560
2676
|
const parentLocalColumns = relation.on.localFields.map((field) => resolveFieldToColumn(context.contract, parentNamespaceId, parentModelName, field));
|
|
2561
|
-
const filterPlan = planRelationFilterMode(buildPairedColumnExprs(
|
|
2677
|
+
const filterPlan = planRelationFilterMode(buildPairedColumnExprs(junctionBinding, through.parentColumns, parentScope.current, parentLocalColumns), toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate, childScope), options.mode);
|
|
2562
2678
|
if (filterPlan.kind === "constantTrue") return AndExpr.true();
|
|
2563
2679
|
const firstTargetCol = firstJoinColumn(through.targetColumns, "targetColumns");
|
|
2564
|
-
const subquery = SelectAst.from(
|
|
2680
|
+
const subquery = SelectAst.from(childScope.current.tableSource(context.contract)).withJoins([JoinAst.inner(junctionBinding.tableSource(context.contract), junctionJoinOn)]).withProjection([ProjectionItem.of("_exists", childScope.current.column(firstTargetCol))]).withWhere(filterPlan.where);
|
|
2565
2681
|
return filterPlan.notExists ? ExistsExpr.notExists(subquery) : ExistsExpr.exists(subquery);
|
|
2566
2682
|
}
|
|
2567
2683
|
function planRelationFilterMode(joinWhere, childWhere, mode) {
|
|
@@ -2584,10 +2700,6 @@ function planRelationFilterMode(joinWhere, childWhere, mode) {
|
|
|
2584
2700
|
where: childWhere ? and(joinWhere, childWhere) : joinWhere
|
|
2585
2701
|
};
|
|
2586
2702
|
}
|
|
2587
|
-
function remapColumnRefs(tableName, tableRef, expr) {
|
|
2588
|
-
if (!expr || tableName === tableRef) return expr;
|
|
2589
|
-
return expr.rewrite({ columnRef: (column) => column.table === tableName ? ColumnRef.of(tableRef, column.column) : column });
|
|
2590
|
-
}
|
|
2591
2703
|
function firstJoinColumn(columns, label) {
|
|
2592
2704
|
const first = columns[0];
|
|
2593
2705
|
if (!first) throw new InternalError(`Relation metadata is missing ${label}`);
|
|
@@ -2601,14 +2713,14 @@ function buildPairedColumnExprs(leftTable, leftColumns, rightTable, rightColumns
|
|
|
2601
2713
|
const left = leftColumns[i];
|
|
2602
2714
|
const right = rightColumns[i];
|
|
2603
2715
|
if (!left || !right) throw new InternalError(`Relation metadata is missing a join column pair at index ${i}`);
|
|
2604
|
-
exprs.push(BinaryExpr.eq(
|
|
2716
|
+
exprs.push(BinaryExpr.eq(leftTable.column(left), rightTable.column(right)));
|
|
2605
2717
|
}
|
|
2606
2718
|
if (exprs.length === 1 && exprs[0]) return exprs[0];
|
|
2607
2719
|
return and(...exprs);
|
|
2608
2720
|
}
|
|
2609
|
-
function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, predicate) {
|
|
2721
|
+
function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, predicate, scope) {
|
|
2610
2722
|
if (!predicate) return;
|
|
2611
|
-
const accessor =
|
|
2723
|
+
const accessor = createModelAccessorInScope(context, relatedNamespaceId, relatedModelName, void 0, scope);
|
|
2612
2724
|
if (typeof predicate === "function") return predicate(accessor);
|
|
2613
2725
|
const exprs = [];
|
|
2614
2726
|
for (const [fieldName, value] of Object.entries(predicate)) {
|
|
@@ -2633,7 +2745,7 @@ function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, pred
|
|
|
2633
2745
|
if (exprs.length === 0) return;
|
|
2634
2746
|
return exprs.length === 1 ? exprs[0] : and(...exprs);
|
|
2635
2747
|
}
|
|
2636
|
-
function buildJoinWhere(contract, parentNamespaceId, parentModelName,
|
|
2748
|
+
function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTable, relatedTable, relation) {
|
|
2637
2749
|
const localFields = relation.on?.localFields ?? [];
|
|
2638
2750
|
const targetFields = relation.on?.targetFields ?? [];
|
|
2639
2751
|
const joinExprs = [];
|
|
@@ -2644,7 +2756,7 @@ function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTabl
|
|
|
2644
2756
|
if (!localField || !targetField) continue;
|
|
2645
2757
|
const localColumn = resolveFieldToColumn(contract, parentNamespaceId, parentModelName, localField);
|
|
2646
2758
|
const targetColumn = resolveFieldToColumn(contract, relation.toNamespace, relation.to, targetField);
|
|
2647
|
-
joinExprs.push(BinaryExpr.eq(
|
|
2759
|
+
joinExprs.push(BinaryExpr.eq(relatedTable.column(targetColumn), parentTable.column(localColumn)));
|
|
2648
2760
|
}
|
|
2649
2761
|
if (joinExprs.length === 0) throw new InternalError("Relation metadata is missing join columns");
|
|
2650
2762
|
const firstExpr = joinExprs[0];
|
|
@@ -3411,7 +3523,7 @@ var Collection = class Collection {
|
|
|
3411
3523
|
* .where({ published: true })
|
|
3412
3524
|
* .groupBy('userId')
|
|
3413
3525
|
* .aggregate((agg) => ({ count: agg.count(), totalViews: agg.sum('views') }));
|
|
3414
|
-
* // [{ userId: 1, count:
|
|
3526
|
+
* // [{ userId: 1, count: 3n, totalViews: 120n }, ...]
|
|
3415
3527
|
* ```
|
|
3416
3528
|
*/
|
|
3417
3529
|
groupBy(...fields) {
|
|
@@ -3434,7 +3546,7 @@ var Collection = class Collection {
|
|
|
3434
3546
|
*
|
|
3435
3547
|
* ```typescript
|
|
3436
3548
|
* const users = await db.orm.User.include('posts', (posts) => posts.count()).all();
|
|
3437
|
-
* // each user row: { ...user, posts:
|
|
3549
|
+
* // each user row: { ...user, posts: bigint }
|
|
3438
3550
|
* ```
|
|
3439
3551
|
*/
|
|
3440
3552
|
count() {
|
|
@@ -3449,7 +3561,7 @@ var Collection = class Collection {
|
|
|
3449
3561
|
*
|
|
3450
3562
|
* ```typescript
|
|
3451
3563
|
* const users = await db.orm.User.include('posts', (posts) => posts.sum('views')).all();
|
|
3452
|
-
* // each user row: { ...user, posts:
|
|
3564
|
+
* // each user row: { ...user, posts: bigint | null } — an int4 column's sum widens to int8
|
|
3453
3565
|
* ```
|
|
3454
3566
|
*/
|
|
3455
3567
|
sum(field) {
|
|
@@ -3465,7 +3577,7 @@ var Collection = class Collection {
|
|
|
3465
3577
|
*
|
|
3466
3578
|
* ```typescript
|
|
3467
3579
|
* const users = await db.orm.User.include('posts', (posts) => posts.avg('views')).all();
|
|
3468
|
-
* // each user row: { ...user, posts:
|
|
3580
|
+
* // each user row: { ...user, posts: string | null } — PostgreSQL averages integers as numeric
|
|
3469
3581
|
* ```
|
|
3470
3582
|
*/
|
|
3471
3583
|
avg(field) {
|
|
@@ -3520,7 +3632,7 @@ var Collection = class Collection {
|
|
|
3520
3632
|
* ).all();
|
|
3521
3633
|
* // each user row: {
|
|
3522
3634
|
* // ...user,
|
|
3523
|
-
* // posts: { recent: Post[]; total:
|
|
3635
|
+
* // posts: { recent: Post[]; total: bigint; averageViews: string | null };
|
|
3524
3636
|
* // }
|
|
3525
3637
|
* ```
|
|
3526
3638
|
*/
|
|
@@ -3692,7 +3804,7 @@ var Collection = class Collection {
|
|
|
3692
3804
|
* averageViews: agg.avg('views'),
|
|
3693
3805
|
* maxViews: agg.max('views'),
|
|
3694
3806
|
* }));
|
|
3695
|
-
* // { total:
|
|
3807
|
+
* // { total: 42n, averageViews: '17.3000000000000000', maxViews: 9001 }
|
|
3696
3808
|
* ```
|
|
3697
3809
|
*
|
|
3698
3810
|
* Accepts an optional `configure` callback that receives a
|
|
@@ -3712,8 +3824,11 @@ var Collection = class Collection {
|
|
|
3712
3824
|
alias
|
|
3713
3825
|
} });
|
|
3714
3826
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "read", "aggregate");
|
|
3715
|
-
const compiled = mergeAnnotations(compileAggregate(this.contract, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
|
|
3716
|
-
|
|
3827
|
+
const compiled = mergeAnnotations(compileAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
|
|
3828
|
+
const row = (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {};
|
|
3829
|
+
const result = {};
|
|
3830
|
+
for (const [alias, selector] of entries) result[alias] = row[alias] ?? emptyAggregateResult(selector.fn);
|
|
3831
|
+
return blindCast(result);
|
|
3717
3832
|
}
|
|
3718
3833
|
async create(data, configure) {
|
|
3719
3834
|
assertReturningCapability(this.contract, "create()");
|
|
@@ -4032,9 +4147,10 @@ var Collection = class Collection {
|
|
|
4032
4147
|
} });
|
|
4033
4148
|
}
|
|
4034
4149
|
/**
|
|
4035
|
-
* Write terminal: update matching
|
|
4036
|
-
* `null` when no row matched).
|
|
4037
|
-
* calling `update(...)` on an
|
|
4150
|
+
* Write terminal: update a single matching row — the first one the
|
|
4151
|
+
* filter matches — and return it (or `null` when no row matched).
|
|
4152
|
+
* Requires a prior `.where(...)` — calling `update(...)` on an
|
|
4153
|
+
* unfiltered collection is a type error.
|
|
4038
4154
|
*
|
|
4039
4155
|
* Related rows can be created or relinked through relation
|
|
4040
4156
|
* callbacks on parent/child-owned relations (one-to-one or
|
|
@@ -4175,9 +4291,10 @@ var Collection = class Collection {
|
|
|
4175
4291
|
return matchingRows.length;
|
|
4176
4292
|
}
|
|
4177
4293
|
/**
|
|
4178
|
-
* Write terminal: delete matching
|
|
4179
|
-
*
|
|
4180
|
-
* — calling `delete()` on an
|
|
4294
|
+
* Write terminal: delete a single matching row — the first one the
|
|
4295
|
+
* filter matches — and return it (or `null` when no row matched).
|
|
4296
|
+
* Requires a prior `.where(...)` — calling `delete()` on an
|
|
4297
|
+
* unfiltered collection is a type error.
|
|
4181
4298
|
*
|
|
4182
4299
|
* ```typescript
|
|
4183
4300
|
* const deleted = await db.orm.User.where({ id: 1 }).delete();
|