@prisma/orm-family-sql 0.17.0 → 8.0.0-rc.1-dev.1

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.
Files changed (147) hide show
  1. package/dist/aggregate-descriptor-registry-DPV4z8MS.mjs +111 -0
  2. package/dist/aggregate-descriptor-registry-DPV4z8MS.mjs.map +1 -0
  3. package/dist/{ast-DSuzmsWn.d.mts → ast-Bb6loOw9.d.mts} +15 -19
  4. package/dist/ast-Bb6loOw9.d.mts.map +1 -0
  5. package/dist/{ast-BstHjAoG.mjs → ast-DDAyIKdt.mjs} +2 -2
  6. package/dist/ast-DDAyIKdt.mjs.map +1 -0
  7. package/dist/builder.d.mts +2 -2
  8. package/dist/builder__runtime.d.mts +14 -10
  9. package/dist/builder__runtime.d.mts.map +1 -1
  10. package/dist/builder__runtime.mjs +161 -107
  11. package/dist/builder__runtime.mjs.map +1 -1
  12. package/dist/builder__types.d.mts +2 -2
  13. package/dist/codec-types-B_xmJL2m-CC_Q-_u9.mjs +24 -0
  14. package/dist/codec-types-B_xmJL2m-CC_Q-_u9.mjs.map +1 -0
  15. package/dist/{config-types-47qB33rW.d.mts → config-types-DKKhWdzf.d.mts} +2 -2
  16. package/dist/{config-types-47qB33rW.d.mts.map → config-types-DKKhWdzf.d.mts.map} +1 -1
  17. package/dist/{contract-builder-MvJJrQ-5.d.mts → contract-builder-Cj-lKWgM.d.mts} +4 -4
  18. package/dist/{contract-builder-MvJJrQ-5.d.mts.map → contract-builder-Cj-lKWgM.d.mts.map} +1 -1
  19. package/dist/contract-emitter.mjs +1 -1
  20. package/dist/contract-psl.d.mts +2 -2
  21. package/dist/contract-psl__provider.d.mts +1 -1
  22. package/dist/contract-ts.d.mts +2 -2
  23. package/dist/contract-ts__config-types.d.mts +1 -1
  24. package/dist/contract-ts__contract-builder.d.mts +1 -1
  25. package/dist/contract.d.mts +6 -6
  26. package/dist/contract__factories.d.mts +1 -1
  27. package/dist/contract__index-type-validation.d.mts +1 -1
  28. package/dist/contract__types.d.mts +3 -3
  29. package/dist/contract__validators.d.mts +1 -1
  30. package/dist/{control-BHmsZudH.d.mts → control-BWngBFMj.d.mts} +10 -10
  31. package/dist/{control-BHmsZudH.d.mts.map → control-BWngBFMj.d.mts.map} +1 -1
  32. package/dist/{control-B7iS4jv4.mjs → control-C1EmRznB.mjs} +2 -2
  33. package/dist/{control-B7iS4jv4.mjs.map → control-C1EmRznB.mjs.map} +1 -1
  34. package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts → control-adapter-C99J7aEF-Cmay9zFj.d.mts} +6 -6
  35. package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts.map → control-adapter-C99J7aEF-Cmay9zFj.d.mts.map} +1 -1
  36. package/dist/control-adapter-DrCAQQpa.d.mts +1 -0
  37. package/dist/{db-DhMsmBS--DKENDi3l.d.mts → db-B5PMfDDd-BsvBY8Wh.d.mts} +65 -32
  38. package/dist/db-B5PMfDDd-BsvBY8Wh.d.mts.map +1 -0
  39. package/dist/{ddl-types-rrMsf77U-DGctYf-T.d.mts → ddl-types-h_3_pXmq-QBLq6WbP.d.mts} +4 -5
  40. package/dist/ddl-types-h_3_pXmq-QBLq6WbP.d.mts.map +1 -0
  41. package/dist/{diff-DhlzHOMD.d.mts → diff-DnLtQXpg.d.mts} +5 -5
  42. package/dist/{diff-DhlzHOMD.d.mts.map → diff-DnLtQXpg.d.mts.map} +1 -1
  43. package/dist/{dist-DrScXbhq.mjs → dist-DtLVFgdI.mjs} +62 -9
  44. package/dist/dist-DtLVFgdI.mjs.map +1 -0
  45. package/dist/{expression-RUO52bJB.mjs → expression-Dhu3dLiu.mjs} +2 -2
  46. package/dist/{expression-RUO52bJB.mjs.map → expression-Dhu3dLiu.mjs.map} +1 -1
  47. package/dist/{expression-DIf8F4Mc.d.mts → expression-KPBpeH4T.d.mts} +5 -6
  48. package/dist/expression-KPBpeH4T.d.mts.map +1 -0
  49. package/dist/{factories-B7tA4y9D.d.mts → factories-MfcqTt5R.d.mts} +2 -2
  50. package/dist/{factories-B7tA4y9D.d.mts.map → factories-MfcqTt5R.d.mts.map} +1 -1
  51. package/dist/family.d.mts +9 -9
  52. package/dist/family.mjs +1 -1
  53. package/dist/family__control-adapter.d.mts +2 -2
  54. package/dist/family__control.d.mts +3 -3
  55. package/dist/family__control.mjs +1 -1
  56. package/dist/family__diff.d.mts +2 -2
  57. package/dist/family__ir.d.mts +1 -1
  58. package/dist/family__migration.d.mts +1 -1
  59. package/dist/family__runtime.d.mts +1 -1
  60. package/dist/{index-Bb9U36N4.d.mts → index-BOhWLVvH.d.mts} +15 -16
  61. package/dist/index-BOhWLVvH.d.mts.map +1 -0
  62. package/dist/{index-BgaTJRxj.d.mts → index-BZF7Wehu.d.mts} +3 -3
  63. package/dist/{index-BgaTJRxj.d.mts.map → index-BZF7Wehu.d.mts.map} +1 -1
  64. package/dist/{index-type-validation-DN0L2mqm.d.mts → index-type-validation-D_vuj-76.d.mts} +2 -2
  65. package/dist/{index-type-validation-DN0L2mqm.d.mts.map → index-type-validation-D_vuj-76.d.mts.map} +1 -1
  66. package/dist/{ir-B3bKMnGQ.d.mts → ir-Cvj3eU-K.d.mts} +2 -2
  67. package/dist/{ir-B3bKMnGQ.d.mts.map → ir-Cvj3eU-K.d.mts.map} +1 -1
  68. package/dist/lane-query-builder.d.mts +3 -3
  69. package/dist/middleware-ChwIEKBC.d.mts +1 -0
  70. package/dist/{middleware-B4XbF4d4-tfwBl6mX.d.mts → middleware-eb7YwdD4-D0M6ACQ-.d.mts} +3 -3
  71. package/dist/{middleware-B4XbF4d4-tfwBl6mX.d.mts.map → middleware-eb7YwdD4-D0M6ACQ-.d.mts.map} +1 -1
  72. package/dist/{migration-CW0ZJLxP.d.mts → migration-BvCT6g2N.d.mts} +3 -3
  73. package/dist/{migration-CW0ZJLxP.d.mts.map → migration-BvCT6g2N.d.mts.map} +1 -1
  74. package/dist/operations.d.mts +1 -1
  75. package/dist/orm-client.d.mts +90 -45
  76. package/dist/orm-client.d.mts.map +1 -1
  77. package/dist/orm-client.mjs +293 -164
  78. package/dist/orm-client.mjs.map +1 -1
  79. package/dist/{plan-BTD8xFfa-Dd_K-A1R.d.mts → plan-Bmp5R9sq-DKMRkx6Z.d.mts} +4 -4
  80. package/dist/plan-Bmp5R9sq-DKMRkx6Z.d.mts.map +1 -0
  81. package/dist/plan-mKgmSe0R.d.mts +2 -0
  82. package/dist/query-lane-context-Dcj4eXUl.d.mts +1 -0
  83. package/dist/{query-lane-context-DtdVMqoz-C2Tj5QHA.d.mts → query-lane-context-DjyAyYht-HDNYE_oF.d.mts} +62 -6
  84. package/dist/query-lane-context-DjyAyYht-HDNYE_oF.d.mts.map +1 -0
  85. package/dist/relational-core.d.mts +12 -13
  86. package/dist/relational-core.mjs +4 -3
  87. package/dist/relational-core__aggregate-descriptor-registry.d.mts +12 -0
  88. package/dist/relational-core__aggregate-descriptor-registry.d.mts.map +1 -0
  89. package/dist/relational-core__aggregate-descriptor-registry.mjs +2 -0
  90. package/dist/relational-core__ast.d.mts +4 -5
  91. package/dist/relational-core__ast.mjs +3 -2
  92. package/dist/relational-core__codec-descriptor-registry.d.mts +3 -3
  93. package/dist/relational-core__contract-free.d.mts +3 -4
  94. package/dist/relational-core__contract-free.d.mts.map +1 -1
  95. package/dist/relational-core__contract-free.mjs +1 -1
  96. package/dist/relational-core__contract-free.mjs.map +1 -1
  97. package/dist/relational-core__expression.d.mts +1 -1
  98. package/dist/relational-core__expression.mjs +1 -1
  99. package/dist/relational-core__middleware.d.mts +2 -2
  100. package/dist/relational-core__plan.d.mts +3 -3
  101. package/dist/relational-core__query-lane-context.d.mts +3 -3
  102. package/dist/relational-core__types.d.mts +2 -2
  103. package/dist/{runtime-DNewRuec.d.mts → runtime-AvfMMERk.d.mts} +2 -2
  104. package/dist/{runtime-DNewRuec.d.mts.map → runtime-AvfMMERk.d.mts.map} +1 -1
  105. package/dist/runtime.d.mts +3 -3
  106. package/dist/runtime.mjs +16 -7
  107. package/dist/runtime.mjs.map +1 -1
  108. package/dist/{schema-differ-DpG_gnur-g5_iks8G.d.mts → schema-differ-DpG_gnur-zSwkxqxK.d.mts} +2 -2
  109. package/dist/{schema-differ-DpG_gnur-g5_iks8G.d.mts.map → schema-differ-DpG_gnur-zSwkxqxK.d.mts.map} +1 -1
  110. package/dist/{sql-execution-plan-CJmsCP7n-DoEpNn7r.d.mts → sql-execution-plan-Da_d82pz-IHBEmGSa.d.mts} +3 -3
  111. package/dist/sql-execution-plan-Da_d82pz-IHBEmGSa.d.mts.map +1 -0
  112. package/dist/{types-DIBA80mc-wf5wLmON.d.mts → types-BwePDa3m-BVrPIi8V.d.mts} +117 -5
  113. package/dist/types-BwePDa3m-BVrPIi8V.d.mts.map +1 -0
  114. package/dist/types-Cty2fvYD.d.mts +1 -0
  115. package/dist/{types-BgkZru_1-H7yfikSQ.mjs → types-D43EhRac-DOJmnq_t.mjs} +4 -21
  116. package/dist/types-D43EhRac-DOJmnq_t.mjs.map +1 -0
  117. package/dist/{types-CuDrWc5v-ISVXBmBs.d.mts → types-D_plAPEe-DqK5It_K.d.mts} +30 -4
  118. package/dist/types-D_plAPEe-DqK5It_K.d.mts.map +1 -0
  119. package/dist/{types-IqZMLrFC-DtdJNICr.d.mts → types-IqZMLrFC-D8PN7ygS.d.mts} +5 -5
  120. package/dist/{types-IqZMLrFC-DtdJNICr.d.mts.map → types-IqZMLrFC-D8PN7ygS.d.mts.map} +1 -1
  121. package/dist/{types-Dl20lxky-DC_jdA0T.d.mts → types-dD8JJfeD-BOvMw2Iu.d.mts} +9 -9
  122. package/dist/{types-Dl20lxky-DC_jdA0T.d.mts.map → types-dD8JJfeD-BOvMw2Iu.d.mts.map} +1 -1
  123. package/dist/{types-BchwQpmO.d.mts → types-wy2-Y8wQ.d.mts} +2 -2
  124. package/dist/{types-BchwQpmO.d.mts.map → types-wy2-Y8wQ.d.mts.map} +1 -1
  125. package/dist/{validators-CxeHhHrf.d.mts → validators-Ds_fvIs_.d.mts} +2 -2
  126. package/dist/{validators-CxeHhHrf.d.mts.map → validators-Ds_fvIs_.d.mts.map} +1 -1
  127. package/package.json +19 -18
  128. package/dist/ast-BstHjAoG.mjs.map +0 -1
  129. package/dist/ast-DSuzmsWn.d.mts.map +0 -1
  130. package/dist/codec-types-MOaceoPi-C5eL2sao.d.mts +0 -116
  131. package/dist/codec-types-MOaceoPi-C5eL2sao.d.mts.map +0 -1
  132. package/dist/control-adapter-4y1O8Ps3.d.mts +0 -1
  133. package/dist/db-DhMsmBS--DKENDi3l.d.mts.map +0 -1
  134. package/dist/ddl-types-rrMsf77U-DGctYf-T.d.mts.map +0 -1
  135. package/dist/dist-DrScXbhq.mjs.map +0 -1
  136. package/dist/expression-DIf8F4Mc.d.mts.map +0 -1
  137. package/dist/index-Bb9U36N4.d.mts.map +0 -1
  138. package/dist/middleware-ByRsXxxq.d.mts +0 -1
  139. package/dist/plan-BTD8xFfa-Dd_K-A1R.d.mts.map +0 -1
  140. package/dist/plan-Cm4jaoNM.d.mts +0 -2
  141. package/dist/query-lane-context-Bz8XJZ45.d.mts +0 -1
  142. package/dist/query-lane-context-DtdVMqoz-C2Tj5QHA.d.mts.map +0 -1
  143. package/dist/sql-execution-plan-CJmsCP7n-DoEpNn7r.d.mts.map +0 -1
  144. package/dist/types-BgkZru_1-H7yfikSQ.mjs.map +0 -1
  145. package/dist/types-CuDrWc5v-ISVXBmBs.d.mts.map +0 -1
  146. package/dist/types-DIBA80mc-wf5wLmON.d.mts.map +0 -1
  147. package/dist/types-DMxc5KZa.d.mts +0 -1
@@ -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, V as isWhereExpr, _ 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-BgkZru_1-H7yfikSQ.mjs";
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-BstHjAoG.mjs";
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, assertNever } from "@prisma/orm-framework/utils/internal-error";
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[fieldName] ?? fieldName
382
+ column: fieldToColumn[field] ?? field
381
383
  };
382
384
  }
383
- function normalizeAggregateResult(aggregateSpec, row) {
384
- const result = {};
385
- for (const [alias, selector] of Object.entries(aggregateSpec)) {
386
- const value = row[alias];
387
- if (value === null) {
388
- result[alias] = null;
389
- continue;
390
- }
391
- if (value === void 0) {
392
- result[alias] = selector.fn === "count" ? 0 : null;
393
- continue;
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
- if (selector.fn === "count") return {
580
- expr: AggregateExpr.count(),
581
- codec: void 0
582
- };
583
- if (!selector.column) throw ormError("ORM.AGGREGATE_SELECTOR_INVALID", `Aggregate selector "${selector.fn}" requires a field`, { meta: { fn: selector.fn } });
584
- const expr = new AggregateExpr(selector.fn, ColumnRef.of(tableName, selector.column));
585
- if (selector.fn === "min" || selector.fn === "max") return {
586
- expr,
587
- codec: codecRefForStorageColumn(contract.storage, namespaceId, tableName, selector.column)
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
- codec: void 0
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. An aggregate is the case that
1024
- * arises today: `COUNT(*)` and `SUM(col)` are computed, and the aggregate's
1025
- * own result type is not the column's codec. Native is what a value with no
1026
- * codec identity means, which is a different thing from defaulting a codec
1027
- * to identity — that, the project forbids.
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.
@@ -1140,7 +1166,8 @@ function createTableRefRemapper(fromTable, toTable) {
1140
1166
  function buildStateWhere(contract, tableName, state, options) {
1141
1167
  const filterTableName = options?.filterTableName;
1142
1168
  const cursorWhere = buildCursorWhere(filterTableName ?? tableName, state.orderBy, state.cursor);
1143
- const remappedFilters = filterTableName && filterTableName !== tableName ? state.filters.map((filter) => filter.rewrite(createTableRefRemapper(filterTableName, tableName))) : state.filters;
1169
+ const boundFilters = state.filters.map((filter) => bindWhereExpr(contract, filter, options?.namespaceId));
1170
+ const remappedFilters = filterTableName && filterTableName !== tableName ? boundFilters.map((filter) => filter.rewrite(createTableRefRemapper(filterTableName, tableName))) : boundFilters;
1144
1171
  const boundCursorWhere = cursorWhere ? bindWhereExpr(contract, cursorWhere, options?.namespaceId) : void 0;
1145
1172
  const remappedCursorWhere = boundCursorWhere && filterTableName && filterTableName !== tableName ? boundCursorWhere.rewrite(createTableRefRemapper(filterTableName, tableName)) : boundCursorWhere;
1146
1173
  return combineWhereExprs(remappedCursorWhere ? [...remappedFilters, remappedCursorWhere] : remappedFilters);
@@ -1216,8 +1243,8 @@ function resolveChildTableSource(include, parentLocalRefs) {
1216
1243
  * Each nested include contributes a single projection item whose
1217
1244
  * expression is a correlated subquery.
1218
1245
  */
1219
- function buildNestedIncludeProjections(contract, parentSource, includes) {
1220
- return includes.map((nested) => buildCorrelatedIncludeProjection(contract, parentSource, nested).projection);
1246
+ function buildNestedIncludeProjections(contract, aggregates, parentSource, includes) {
1247
+ return includes.map((nested) => buildCorrelatedIncludeProjection(contract, aggregates, parentSource, nested).projection);
1221
1248
  }
1222
1249
  /**
1223
1250
  * The aliases a level's nested includes contribute. Each such subquery
@@ -1320,7 +1347,7 @@ function buildManyToManyJunctionArtifacts(parentLocalRefs, childTableRef, throug
1320
1347
  junctionJoin: JoinAst.inner(TableSource.named(junctionTable, void 0, namespaceId), joinOn, false)
1321
1348
  };
1322
1349
  }
1323
- function buildIncludeChildRowsSelect(contract, parentSource, include) {
1350
+ function buildIncludeChildRowsSelect(contract, aggregates, parentSource, include) {
1324
1351
  const childState = include.nested;
1325
1352
  const parentLocalRefs = resolveParentLocalRefs(parentSource, include, localColumnsForRowInclude(include));
1326
1353
  const childSource = resolveChildTableSource(include, parentLocalRefs);
@@ -1347,6 +1374,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
1347
1374
  }
1348
1375
  if (childState.distinct !== void 0 && childState.distinct.length > 0 && childState.includes.length > 0) return buildDistinctNonLeafChildRowsSelect({
1349
1376
  contract,
1377
+ aggregates,
1350
1378
  include,
1351
1379
  childTableAlias,
1352
1380
  childTableRef,
@@ -1359,7 +1387,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
1359
1387
  });
1360
1388
  const polyJoinsAndProjection = buildChildPolymorphismJoinsAndProjection(contract, include, childTableAlias, childTableRef);
1361
1389
  const scalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, polyJoinsAndProjection.baseSelectedFields, childTableRef);
1362
- const nestedProjections = buildNestedIncludeProjections(contract, {
1390
+ const nestedProjections = buildNestedIncludeProjections(contract, aggregates, {
1363
1391
  baseTableName: include.relatedTableName,
1364
1392
  tableRef: childTableRef,
1365
1393
  variantColumnsProjected: false
@@ -1397,7 +1425,7 @@ function buildIncludeChildRowsSelect(contract, parentSource, include) {
1397
1425
  };
1398
1426
  }
1399
1427
  function buildDistinctNonLeafChildRowsSelect(options) {
1400
- const { contract, include, childTableAlias, childTableRef, rowsAlias, childOrderBy, hiddenOrderProjection, aggregateOrderBy, whereExpr, junctionJoins } = options;
1428
+ const { contract, aggregates, include, childTableAlias, childTableRef, rowsAlias, childOrderBy, hiddenOrderProjection, aggregateOrderBy, whereExpr, junctionJoins } = options;
1401
1429
  const childState = include.nested;
1402
1430
  const grandchildJoinColumns = Array.from(new Set(childState.includes.flatMap((nested) => nested.localTableName === include.relatedTableName ? localColumnsForRowInclude(nested) : [])));
1403
1431
  const { selectedForQuery } = augmentSelectionForJoinColumns(childState.selectedFields, grandchildJoinColumns);
@@ -1433,7 +1461,7 @@ function buildDistinctNonLeafChildRowsSelect(options) {
1433
1461
  if (childState.offset !== void 0) innerSelect = innerSelect.withOffset(childState.offset);
1434
1462
  const distinctAlias = `${include.relationName}__distinct`;
1435
1463
  const outerScalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, visiblePolyProjection.baseSelectedFields, distinctAlias);
1436
- const outerNestedProjections = buildNestedIncludeProjections(contract, {
1464
+ const outerNestedProjections = buildNestedIncludeProjections(contract, aggregates, {
1437
1465
  baseTableName: include.relatedTableName,
1438
1466
  tableRef: distinctAlias,
1439
1467
  variantColumnsProjected: true
@@ -1481,32 +1509,51 @@ function buildDistinctNonLeafChildRowsSelect(options) {
1481
1509
  * `distinct`) is dropped at the SQL level since reordering does not
1482
1510
  * change which rows are aggregated.
1483
1511
  */
1484
- function buildIncludeChildScalarSelect(contract, parentSource, include, scalar) {
1485
- const parentLocalRefs = resolveParentLocalRefs(parentSource, include, [include.localColumn]);
1486
- const parentLocalRef = parentLocalRefs[0];
1487
- assertDefined(parentLocalRef, `Include '${include.relationName}' has no parent-local column ref`);
1512
+ function buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, scalar) {
1513
+ const { codec: resultCodec, input: inputCodec, lower: resultLowering } = resolveAggregate({
1514
+ aggregates,
1515
+ contract,
1516
+ namespaceId: include.relatedNamespaceId,
1517
+ tableName: include.relatedTableName,
1518
+ fn: scalar.fn,
1519
+ column: scalar.column
1520
+ });
1521
+ const parentLocalRefs = resolveParentLocalRefs(parentSource, include, localColumnsForRowInclude(include));
1488
1522
  const childSource = resolveChildTableSource(include, parentLocalRefs);
1489
1523
  const childTableAlias = childSource.alias;
1490
1524
  const childTableRef = childSource.tableRef;
1491
1525
  const state = scalar.state;
1492
- const joinExpr = BinaryExpr.eq(ColumnRef.of(childTableRef, include.targetColumn), parentLocalRef);
1493
1526
  const childWhere = buildStateWhere(contract, childTableRef, state, {
1494
1527
  filterTableName: include.relatedTableName,
1495
1528
  namespaceId: include.relatedNamespaceId
1496
1529
  });
1497
- const whereExpr = childWhere ? AndExpr.of([joinExpr, childWhere]) : joinExpr;
1530
+ let whereExpr;
1531
+ let junctionJoins = [];
1532
+ if (include.through !== void 0) {
1533
+ const artifacts = buildManyToManyJunctionArtifacts(parentLocalRefs, childTableRef, include.through);
1534
+ whereExpr = childWhere ? AndExpr.of([artifacts.whereExpr, childWhere]) : artifacts.whereExpr;
1535
+ junctionJoins = [artifacts.junctionJoin];
1536
+ } else {
1537
+ const parentLocalRef = parentLocalRefs[0];
1538
+ assertDefined(parentLocalRef, `Include '${include.relationName}' has no parent-local column ref`);
1539
+ const joinExpr = BinaryExpr.eq(ColumnRef.of(childTableRef, include.targetColumn), parentLocalRef);
1540
+ whereExpr = childWhere ? AndExpr.of([joinExpr, childWhere]) : joinExpr;
1541
+ }
1498
1542
  const remappedOrderBy = childTableAlias && state.orderBy ? state.orderBy.map((item) => item.rewrite(createTableRefRemapper(include.relatedTableName, childTableRef))) : state.orderBy;
1499
1543
  const hasPagination = state.limit !== void 0 || state.offset !== void 0;
1500
1544
  const hasDistinct = state.distinct !== void 0 && state.distinct.length > 0 || state.distinctOn !== void 0 && state.distinctOn.length > 0;
1501
1545
  if (!(hasPagination || hasDistinct)) {
1502
- const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef);
1503
- const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, {}))]);
1504
- return SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection([ProjectionItem.of(include.relationName, jsonObjectExpr)]).withWhere(whereExpr);
1546
+ const aggregateExpr = buildIncludeAggregateExpr(scalar, childTableRef, resultLowering, inputCodec);
1547
+ const jsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(aggregateExpr, { codec: resultCodec }))]);
1548
+ let select = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection([ProjectionItem.of(include.relationName, jsonObjectExpr)]).withWhere(whereExpr);
1549
+ if (junctionJoins.length > 0) select = select.withJoins(junctionJoins);
1550
+ return select;
1505
1551
  }
1506
1552
  const innerAlias = `${include.relationName}__scalar`;
1507
1553
  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
1554
  const innerProjection = [...scalar.column !== void 0 ? [ProjectionItem.of(scalar.column, ColumnRef.of(childTableRef, scalar.column))] : [ProjectionItem.of("__row", LiteralExpr.of(1))], ...hiddenOrderProjection];
1509
1555
  let inner = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection(innerProjection).withWhere(whereExpr);
1556
+ if (junctionJoins.length > 0) inner = inner.withJoins(junctionJoins);
1510
1557
  if (state.distinctOn !== void 0 && state.distinctOn.length > 0) {
1511
1558
  inner = inner.withDistinctOn(state.distinctOn.map((column) => ColumnRef.of(childTableRef, column)));
1512
1559
  if (remappedOrderBy !== void 0 && remappedOrderBy.length > 0) inner = inner.withOrderBy(remappedOrderBy);
@@ -1522,21 +1569,17 @@ function buildIncludeChildScalarSelect(contract, parentSource, include, scalar)
1522
1569
  } else if (remappedOrderBy !== void 0 && remappedOrderBy.length > 0) inner = inner.withOrderBy(remappedOrderBy);
1523
1570
  if (state.limit !== void 0) inner = inner.withLimit(state.limit);
1524
1571
  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, {}))]);
1572
+ const outerAggregateExpr = buildIncludeAggregateExpr(scalar, innerAlias, resultLowering, inputCodec);
1573
+ const outerJsonObjectExpr = JsonObjectExpr.fromEntries([JsonObjectExpr.entry("value", jsonEntryProjection(outerAggregateExpr, { codec: resultCodec }))]);
1527
1574
  return SelectAst.from(DerivedTableSource.as(innerAlias, inner)).withProjection([ProjectionItem.of(include.relationName, outerJsonObjectExpr)]);
1528
1575
  }
1529
- function buildIncludeAggregateExpr(scalar, childTableRef) {
1530
- if (scalar.fn === "count") return AggregateExpr.count();
1531
- if (scalar.column === void 0) throw ormError("ORM.AGGREGATE_SELECTOR_INVALID", `Aggregate selector "${scalar.fn}" requires a column`, { meta: { fn: scalar.fn } });
1532
- const columnRef = ColumnRef.of(childTableRef, scalar.column);
1533
- switch (scalar.fn) {
1534
- case "sum": return AggregateExpr.sum(columnRef);
1535
- case "avg": return AggregateExpr.avg(columnRef);
1536
- case "min": return AggregateExpr.min(columnRef);
1537
- case "max": return AggregateExpr.max(columnRef);
1538
- default: return assertNever(scalar.fn);
1539
- }
1576
+ function buildIncludeAggregateExpr(scalar, childTableRef, lower, inputCodec) {
1577
+ const expr = scalar.column === void 0 ? void 0 : ColumnRef.of(childTableRef, scalar.column);
1578
+ if (lower !== void 0) return lower({
1579
+ expr,
1580
+ inputCodec
1581
+ });
1582
+ return new AggregateExpr(scalar.fn, expr);
1540
1583
  }
1541
1584
  /**
1542
1585
  * Build the inner SELECT for a `combine({ a, b, ... })` include.
@@ -1557,13 +1600,13 @@ function buildIncludeAggregateExpr(scalar, childTableRef) {
1557
1600
  * branch fan out naturally because the row builder is invoked with
1558
1601
  * a synthetic IncludeExpr whose `nested` is the branch's state.
1559
1602
  */
1560
- function buildIncludeChildCombineSelect(contract, parentSource, include, branches) {
1603
+ function buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, branches) {
1561
1604
  const branchEntries = Object.entries(branches);
1562
1605
  if (branchEntries.length === 0) throw ormError("ORM.INCLUDE_INVALID", `combine() include "${include.relationName}" has no branches`, { meta: { relation: include.relationName } });
1563
1606
  const compiledBranches = branchEntries.map(([name, branch]) => ({
1564
1607
  name,
1565
1608
  alias: `${include.relationName}__combine__${name}`,
1566
- select: buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch)
1609
+ select: buildIncludeChildCombineBranchSelect(contract, aggregates, parentSource, include, branch)
1567
1610
  }));
1568
1611
  const jsonObjectExpr = JsonObjectExpr.fromEntries(compiledBranches.map((branch) => JsonObjectExpr.entry(branch.name, jsonEntryProjection(ColumnRef.of(branch.alias, include.relationName), { document: true }))));
1569
1612
  const [firstBranch, ...restBranches] = compiledBranches;
@@ -1577,9 +1620,9 @@ function buildIncludeChildCombineSelect(contract, parentSource, include, branche
1577
1620
  * relation name. Dispatches to the standalone scalar / row builders
1578
1621
  * with the branch's state spliced into a synthetic IncludeExpr.
1579
1622
  */
1580
- function buildIncludeChildCombineBranchSelect(contract, parentSource, include, branch) {
1581
- if (branch.kind === "scalar") return buildIncludeChildScalarSelect(contract, parentSource, include, branch.selector);
1582
- return buildIncludeChildRowsAggregateSelect(contract, parentSource, {
1623
+ function buildIncludeChildCombineBranchSelect(contract, aggregates, parentSource, include, branch) {
1624
+ if (branch.kind === "scalar") return buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, branch.selector);
1625
+ return buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, {
1583
1626
  ...include,
1584
1627
  nested: branch.state,
1585
1628
  scalar: void 0,
@@ -1592,24 +1635,24 @@ function buildIncludeChildCombineBranchSelect(contract, parentSource, include, b
1592
1635
  * name. Used by both the standalone row correlated-subquery path and
1593
1636
  * by combine's row branches.
1594
1637
  */
1595
- function buildIncludeChildRowsAggregateSelect(contract, parentSource, include) {
1596
- const { childRows, childProjection, documentAliases, rowsAlias, aggregateOrderBy } = buildIncludeChildRowsSelect(contract, parentSource, include);
1638
+ function buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include) {
1639
+ const { childRows, childProjection, documentAliases, rowsAlias, aggregateOrderBy } = buildIncludeChildRowsSelect(contract, aggregates, parentSource, include);
1597
1640
  const jsonObjectExpr = JsonObjectExpr.fromEntries(childProjection.map((item) => JsonObjectExpr.entry(item.alias, jsonEntryProjection(ColumnRef.of(rowsAlias, item.alias), {
1598
1641
  codec: item.codec,
1599
1642
  document: documentAliases.has(item.alias)
1600
1643
  }))));
1601
1644
  return SelectAst.from(DerivedTableSource.as(rowsAlias, childRows)).withProjection([ProjectionItem.of(include.relationName, JsonArrayAggExpr.of(jsonEntryProjection(jsonObjectExpr, { document: true }), "emptyArray", aggregateOrderBy))]);
1602
1645
  }
1603
- function buildCorrelatedIncludeProjection(contract, parentSource, include) {
1646
+ function buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include) {
1604
1647
  if (include.scalar) {
1605
- const scalarSelect = buildIncludeChildScalarSelect(contract, parentSource, include, include.scalar);
1648
+ const scalarSelect = buildIncludeChildScalarSelect(contract, aggregates, parentSource, include, include.scalar);
1606
1649
  return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(scalarSelect)) };
1607
1650
  }
1608
1651
  if (include.combine) {
1609
- const combineSelect = buildIncludeChildCombineSelect(contract, parentSource, include, include.combine);
1652
+ const combineSelect = buildIncludeChildCombineSelect(contract, aggregates, parentSource, include, include.combine);
1610
1653
  return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(combineSelect)) };
1611
1654
  }
1612
- const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, parentSource, include);
1655
+ const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include);
1613
1656
  return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(aggregateQuery)) };
1614
1657
  }
1615
1658
  function buildSelectAst(contract, tableName, state, options) {
@@ -1686,7 +1729,7 @@ function compileSelect(contract, namespaceId, tableName, state, modelName) {
1686
1729
  const { params } = deriveParamsFromAst(ast);
1687
1730
  return buildOrmQueryPlan(contract, ast, params, state.annotations);
1688
1731
  }
1689
- function compileSelectWithIncludes(contract, namespaceId, tableName, state, modelName) {
1732
+ function compileSelectWithIncludes(contract, aggregates, namespaceId, tableName, state, modelName) {
1690
1733
  const includeJoins = [];
1691
1734
  const includeProjection = [];
1692
1735
  const topLevelWhere = buildStateWhere(contract, tableName, state, { namespaceId });
@@ -1710,7 +1753,7 @@ function compileSelectWithIncludes(contract, namespaceId, tableName, state, mode
1710
1753
  variantColumnsProjected: false
1711
1754
  };
1712
1755
  for (const include of state.includes) {
1713
- const artifact = buildCorrelatedIncludeProjection(contract, parentSource, include);
1756
+ const artifact = buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include);
1714
1757
  includeProjection.push(artifact.projection);
1715
1758
  }
1716
1759
  const ast = buildSelectAst(contract, tableName, {
@@ -1829,7 +1872,7 @@ function dispatchWithIncludes(options) {
1829
1872
  const generator = async function* () {
1830
1873
  const { scope, release } = await acquireRuntimeScope(runtime);
1831
1874
  try {
1832
- const parentRowsRaw = await executeQueryPlan(scope, compileSelectWithIncludes(contract, namespaceId, tableName, state, modelName)).toArray();
1875
+ const parentRowsRaw = await executeQueryPlan(scope, compileSelectWithIncludes(contract, context.aggregateDescriptors, namespaceId, tableName, state, modelName)).toArray();
1833
1876
  if (parentRowsRaw.length === 0) return;
1834
1877
  const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
1835
1878
  const parentRows = parentRowsRaw.map((row) => {
@@ -1927,7 +1970,7 @@ function buildIdentityInFilter(contract, namespaceId, tableName, identityColumns
1927
1970
  * declared shape (see `decodeCombineIncludePayload`).
1928
1971
  */
1929
1972
  async function decodeIncludePayload(contract, context, include, raw) {
1930
- if (include.scalar) return Promise.resolve(decodeScalarIncludePayload(include, include.scalar, raw));
1973
+ if (include.scalar) return Promise.resolve(decodeScalarIncludePayload(contract, context, include, include.scalar, raw));
1931
1974
  if (include.combine) return decodeCombineIncludePayload(contract, context, include, include.combine, raw);
1932
1975
  const rawChildren = parseIncludedRows(include, raw);
1933
1976
  const polyInfo = resolvePolymorphismInfo(contract, include.relatedNamespaceId, include.relatedModelName);
@@ -2001,6 +2044,7 @@ async function decodeIncludedColumnValue(ref, codecId, codec, value) {
2001
2044
  }
2002
2045
  return decodeIncludedJsonValue(ref, codecId, codec, value);
2003
2046
  }
2047
+ /** `ref` names the value for a decode failure; an aggregate names its relation where a column would name itself. */
2004
2048
  function decodeIncludedJsonValue(ref, codecId, codec, value) {
2005
2049
  try {
2006
2050
  return codec.decodeJson(blindCast(value));
@@ -2053,7 +2097,7 @@ async function decodeCombineIncludePayload(contract, context, include, branches,
2053
2097
  scalar: void 0,
2054
2098
  combine: void 0
2055
2099
  }, branchRaw);
2056
- else result[branchName] = decodeScalarIncludePayload(include, branch.selector, branchRaw);
2100
+ else result[branchName] = decodeScalarIncludePayload(contract, context, include, branch.selector, branchRaw);
2057
2101
  }
2058
2102
  return result;
2059
2103
  }
@@ -2086,8 +2130,9 @@ function describeEnvelopeShape(value) {
2086
2130
  * loudly naming the include relation rather than soft-handling.
2087
2131
  * Mirrors `parseCombineEnvelope`'s strict shape gate.
2088
2132
  *
2089
- * Values are passed through unchangedno JS-side `Number()` coercion
2090
- * and no JS-side empty-relation defaulting. SQL semantics drive the
2133
+ * The value passes through its own codec the one the planner projected it
2134
+ * under because it arrived inside a JSON document, where a count past 2^53
2135
+ * would otherwise have been read as a rounded number. SQL semantics drive the
2091
2136
  * empty-relation case: `COUNT(*)` over an empty input set is `0`;
2092
2137
  * `SUM` / `AVG` / `MIN` / `MAX` over an empty input set return SQL
2093
2138
  * `NULL`, which surfaces as `null` here. The outer `raw === null`
@@ -2095,11 +2140,24 @@ function describeEnvelopeShape(value) {
2095
2140
  * dispatch the correlated subquery always produces a row, so the inner
2096
2141
  * envelope's `value` is always set by SQL.
2097
2142
  */
2098
- function decodeScalarIncludePayload(include, scalar, raw) {
2099
- if (raw === null || raw === void 0) return emptyScalarResult(scalar.fn);
2143
+ function decodeScalarIncludePayload(contract, context, include, scalar, raw) {
2144
+ if (raw === null || raw === void 0) return emptyAggregateResult(scalar.fn);
2100
2145
  const parsed = parseIncludePayload(raw);
2101
2146
  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
- return parsed["value"];
2147
+ const value = parsed["value"];
2148
+ if (value === null || value === void 0) return emptyAggregateResult(scalar.fn);
2149
+ const codecRef = resolveAggregateOutputCodec({
2150
+ aggregates: context.aggregateDescriptors,
2151
+ contract,
2152
+ namespaceId: include.relatedNamespaceId,
2153
+ tableName: include.relatedTableName,
2154
+ fn: scalar.fn,
2155
+ column: scalar.column
2156
+ });
2157
+ return decodeIncludedJsonValue({
2158
+ table: include.relatedTableName,
2159
+ column: include.relationName
2160
+ }, codecRef.codecId, context.contractCodecs.forCodecRef(codecRef), value);
2103
2161
  }
2104
2162
  function parseIncludedRows(include, value) {
2105
2163
  if (value === null || value === void 0) return [];
@@ -2123,9 +2181,6 @@ function parseIncludePayload(value) {
2123
2181
  function coerceSingleQueryIncludeResult(rows, cardinality) {
2124
2182
  return isToOneCardinality(cardinality) ? rows[0] ?? null : rows;
2125
2183
  }
2126
- function emptyScalarResult(fn) {
2127
- return fn === "count" ? 0 : null;
2128
- }
2129
2184
  function createMutationRowMapper(contract, namespaceId, modelName, variantName) {
2130
2185
  const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
2131
2186
  return polyInfo ? (row) => mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, row, variantName) : (row) => mapStorageRowToModelFields(contract, namespaceId, modelName, row);
@@ -2308,10 +2363,10 @@ var GroupedCollection = class GroupedCollection {
2308
2363
  configure(meta);
2309
2364
  if (meta.annotations.size > 0) annotationsMap = meta.annotations;
2310
2365
  }
2311
- const compiled = mergeAnnotations(compileGroupedAggregate(this.contract, this.namespaceId, this.tableName, this.baseFilters, this.groupByColumns, aggregateSpec, combineWhereExprs(this.havingFilters)), annotationsMap);
2366
+ const compiled = mergeAnnotations(compileGroupedAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.baseFilters, this.groupByColumns, aggregateSpec, combineWhereExprs(this.havingFilters)), annotationsMap);
2312
2367
  return (await executeQueryPlan(this.ctx.runtime, compiled).toArray()).map((row) => {
2313
2368
  const mapped = mapStorageRowToModelFields(this.contract, this.namespaceId, this.modelName, row);
2314
- for (const [alias, selector] of aggregateEntries) mapped[alias] = coerceAggregateValue(selector.fn, row[alias]);
2369
+ for (const [alias] of aggregateEntries) mapped[alias] = row[alias];
2315
2370
  return mapped;
2316
2371
  });
2317
2372
  }
@@ -2360,17 +2415,6 @@ function createHavingComparisonMethods(metric) {
2360
2415
  }
2361
2416
  };
2362
2417
  }
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
2418
  const aggregateFns = /* @__PURE__ */ new Set([
2375
2419
  "count",
2376
2420
  "sum",
@@ -2416,7 +2460,91 @@ function isCollectionState(value) {
2416
2460
  function hasThrough$1(relation) {
2417
2461
  return relation.through !== void 0;
2418
2462
  }
2463
+ var SqlTableBinding = class SqlTableBinding {
2464
+ #storage;
2465
+ #reference;
2466
+ constructor(storage, reference) {
2467
+ this.#storage = Object.freeze({ ...storage });
2468
+ this.#reference = reference;
2469
+ Object.freeze(this);
2470
+ }
2471
+ static unaliased(storage) {
2472
+ return new SqlTableBinding(storage, storage.tableName);
2473
+ }
2474
+ static aliased(storage, alias) {
2475
+ return new SqlTableBinding(storage, alias);
2476
+ }
2477
+ column(columnName) {
2478
+ return ColumnRef.of(this.#reference, columnName);
2479
+ }
2480
+ tableSource(contract) {
2481
+ return tableSourceForContract(contract, this.#storage.namespaceId, this.#storage.tableName, this.#reference);
2482
+ }
2483
+ isReferencedAs(candidate) {
2484
+ return this.#reference === candidate;
2485
+ }
2486
+ isStoredAt(namespaceId, tableName) {
2487
+ return this.#storage.namespaceId === namespaceId && this.#storage.tableName === tableName;
2488
+ }
2489
+ };
2490
+ var ModelAccessorScope = class ModelAccessorScope {
2491
+ current;
2492
+ #visibleBindings;
2493
+ #aliasCounter;
2494
+ constructor(current, visibleBindings, aliasCounter) {
2495
+ this.current = current;
2496
+ this.#visibleBindings = Object.freeze([...visibleBindings]);
2497
+ this.#aliasCounter = aliasCounter;
2498
+ Object.freeze(this);
2499
+ }
2500
+ static root(namespaceId, tableName) {
2501
+ const binding = SqlTableBinding.unaliased({
2502
+ namespaceId,
2503
+ tableName
2504
+ });
2505
+ return new ModelAccessorScope(binding, [binding], { nextId: 1 });
2506
+ }
2507
+ forRelation(namespaceId, tableName) {
2508
+ const binding = this.#allocateBinding(namespaceId, tableName, "rel");
2509
+ return new ModelAccessorScope(binding, [...this.#visibleBindings, binding], this.#aliasCounter);
2510
+ }
2511
+ forManyToManyRelation(childNamespaceId, childTableName, junctionNamespaceId, junctionTableName) {
2512
+ const initialChildScope = this.forRelation(childNamespaceId, childTableName);
2513
+ const junctionBinding = initialChildScope.#allocateBinding(junctionNamespaceId, junctionTableName, "junction");
2514
+ return {
2515
+ childScope: new ModelAccessorScope(initialChildScope.current, [...initialChildScope.#visibleBindings, junctionBinding], this.#aliasCounter),
2516
+ junctionBinding
2517
+ };
2518
+ }
2519
+ forJoinedSource(namespaceId, tableName) {
2520
+ if (this.current.isStoredAt(namespaceId, tableName)) return this;
2521
+ const binding = SqlTableBinding.unaliased({
2522
+ namespaceId,
2523
+ tableName
2524
+ });
2525
+ return new ModelAccessorScope(binding, [...this.#visibleBindings, binding], this.#aliasCounter);
2526
+ }
2527
+ #allocateBinding(namespaceId, tableName, aliasKind) {
2528
+ const storage = {
2529
+ namespaceId,
2530
+ tableName
2531
+ };
2532
+ if (!this.#visibleBindings.some((binding) => binding.isReferencedAs(tableName))) return SqlTableBinding.unaliased(storage);
2533
+ return SqlTableBinding.aliased(storage, this.#allocateAlias(aliasKind));
2534
+ }
2535
+ #allocateAlias(kind) {
2536
+ while (true) {
2537
+ const alias = `__orm_${kind}_${this.#aliasCounter.nextId}`;
2538
+ this.#aliasCounter.nextId += 1;
2539
+ if (!this.#visibleBindings.some((binding) => binding.isReferencedAs(alias))) return alias;
2540
+ }
2541
+ }
2542
+ };
2419
2543
  function createModelAccessor(context, namespaceId, modelName, variantName) {
2544
+ const tableName = resolveModelTableName(context.contract, namespaceId, modelName);
2545
+ return createModelAccessorInScope(context, namespaceId, modelName, variantName, ModelAccessorScope.root(namespaceId, tableName));
2546
+ }
2547
+ function createModelAccessorInScope(context, namespaceId, modelName, variantName, scope) {
2420
2548
  const contract = context.contract;
2421
2549
  const fieldToColumn = getFieldToColumnMap(contract, namespaceId, modelName);
2422
2550
  const tableName = resolveModelTableName(contract, namespaceId, modelName);
@@ -2450,19 +2578,20 @@ function createModelAccessor(context, namespaceId, modelName, variantName) {
2450
2578
  if (typeof prop !== "string") return;
2451
2579
  if (variantCoordinates) {
2452
2580
  const variantRelation = variantCoordinates.relations[prop];
2453
- if (variantRelation) return createRelationFilterAccessor(context, namespaceId, variantCoordinates.name, variantCoordinates.tableName, prop, variantRelation);
2581
+ if (variantRelation) return createRelationFilterAccessor(context, namespaceId, variantCoordinates.name, scope.forJoinedSource(namespaceId, variantCoordinates.tableName), variantRelation);
2454
2582
  }
2455
2583
  const relation = modelRelations[prop];
2456
- if (relation) return createRelationFilterAccessor(context, namespaceId, modelName, tableName, prop, relation);
2584
+ if (relation) return createRelationFilterAccessor(context, namespaceId, modelName, scope, relation);
2457
2585
  const variantField = variantFieldColumns[prop];
2458
2586
  const resolvedTable = variantField?.table ?? tableName;
2587
+ const fieldBinding = scope.forJoinedSource(namespaceId, resolvedTable).current;
2459
2588
  const columnName = variantField?.column ?? fieldToColumn[prop] ?? prop;
2460
2589
  const column = resolveColumn(contract, namespaceId, resolvedTable, columnName);
2461
2590
  if (!column) return;
2462
2591
  const traits = context.codecDescriptors.descriptorFor(column.codecId)?.traits ?? [];
2463
2592
  const operations = opsByCodecId.get(column.codecId) ?? [];
2464
2593
  const codec = codecRefForStorageColumn(contract.storage, namespaceId, resolvedTable, columnName);
2465
- return createScalarFieldAccessor(resolvedTable, columnName, column.codecId, column.nullable, codec, traits, operations, context);
2594
+ return createScalarFieldAccessor(fieldBinding, columnName, column.codecId, column.nullable, codec, traits, operations, context);
2466
2595
  } }));
2467
2596
  }
2468
2597
  function resolveColumn(contract, namespaceId, tableName, columnName) {
@@ -2479,8 +2608,8 @@ function resolveColumn(contract, namespaceId, tableName, columnName) {
2479
2608
  nullable: column.nullable
2480
2609
  };
2481
2610
  }
2482
- function createScalarFieldAccessor(tableName, columnName, codecId, nullable, codec, traits, operations, context) {
2483
- const column = ColumnRef.of(tableName, columnName);
2611
+ function createScalarFieldAccessor(tableBinding, columnName, codecId, nullable, codec, traits, operations, context) {
2612
+ const column = tableBinding.column(columnName);
2484
2613
  const comparisonEntries = [];
2485
2614
  for (const [name, meta] of Object.entries(COMPARISON_METHODS_META)) {
2486
2615
  if (meta.traits.some((t) => !traits.includes(t))) continue;
@@ -2515,42 +2644,41 @@ function createExtensionMethodFactory(selfExpr, entry, context) {
2515
2644
  return methods;
2516
2645
  };
2517
2646
  }
2518
- function createRelationFilterAccessor(context, parentNamespaceId, parentModelName, parentTableName, relationName, relation) {
2647
+ function createRelationFilterAccessor(context, parentNamespaceId, parentModelName, parentScope, relation) {
2519
2648
  const relatedTableName = resolveModelTableName(context.contract, relation.toNamespace, relation.to);
2520
2649
  return {
2521
- some: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, {
2650
+ some: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
2522
2651
  mode: "some",
2523
2652
  predicate
2524
2653
  }),
2525
- every: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, {
2654
+ every: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
2526
2655
  mode: "every",
2527
2656
  predicate
2528
2657
  }),
2529
- none: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, {
2658
+ none: (predicate) => buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, {
2530
2659
  mode: "none",
2531
2660
  predicate
2532
2661
  })
2533
2662
  };
2534
2663
  }
2535
- function buildExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, options) {
2536
- if (hasThrough$1(relation)) return buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, options);
2537
- const filterPlan = planRelationFilterMode(buildJoinWhere(context.contract, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relation), toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate), options.mode);
2664
+ function buildExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options) {
2665
+ if (hasThrough$1(relation)) return buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options);
2666
+ const childScope = parentScope.forRelation(relation.toNamespace, relatedTableName);
2667
+ const filterPlan = planRelationFilterMode(buildJoinWhere(context.contract, parentNamespaceId, parentModelName, parentScope.current, childScope.current, relation), toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate, childScope), options.mode);
2538
2668
  if (filterPlan.kind === "constantTrue") return AndExpr.true();
2539
2669
  const selectProjectionColumn = firstTargetColumn(context.contract, relation) ?? "id";
2540
- const subquery = SelectAst.from(tableSourceForContract(context.contract, relation.toNamespace, relatedTableName)).withProjection([ProjectionItem.of("_exists", ColumnRef.of(relatedTableName, selectProjectionColumn))]).withWhere(filterPlan.where);
2670
+ const subquery = SelectAst.from(childScope.current.tableSource(context.contract)).withProjection([ProjectionItem.of("_exists", childScope.current.column(selectProjectionColumn))]).withWhere(filterPlan.where);
2541
2671
  return filterPlan.notExists ? ExistsExpr.notExists(subquery) : ExistsExpr.exists(subquery);
2542
2672
  }
2543
- function buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relationName, relation, options) {
2673
+ function buildManyToManyExistsExpr(context, parentNamespaceId, parentModelName, parentScope, relatedTableName, relation, options) {
2544
2674
  const { through } = relation;
2545
- const junctionTable = through.table;
2546
- const relatedTableAlias = parentNamespaceId === relation.toNamespace && parentTableName === relatedTableName ? `${relationName}__child` : void 0;
2547
- const relatedTableRef = relatedTableAlias ?? relatedTableName;
2548
- const junctionJoinOn = buildPairedColumnExprs(junctionTable, through.childColumns, relatedTableRef, through.targetColumns);
2675
+ const { childScope, junctionBinding } = parentScope.forManyToManyRelation(relation.toNamespace, relatedTableName, through.namespaceId, through.table);
2676
+ const junctionJoinOn = buildPairedColumnExprs(junctionBinding, through.childColumns, childScope.current, through.targetColumns);
2549
2677
  const parentLocalColumns = relation.on.localFields.map((field) => resolveFieldToColumn(context.contract, parentNamespaceId, parentModelName, field));
2550
- const filterPlan = planRelationFilterMode(buildPairedColumnExprs(junctionTable, through.parentColumns, parentTableName, parentLocalColumns), remapColumnRefs(relatedTableName, relatedTableRef, toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate)), options.mode);
2678
+ const filterPlan = planRelationFilterMode(buildPairedColumnExprs(junctionBinding, through.parentColumns, parentScope.current, parentLocalColumns), toRelationWhereExpr(context, relation.toNamespace, relation.to, options.predicate, childScope), options.mode);
2551
2679
  if (filterPlan.kind === "constantTrue") return AndExpr.true();
2552
2680
  const firstTargetCol = firstJoinColumn(through.targetColumns, "targetColumns");
2553
- const subquery = SelectAst.from(tableSourceForContract(context.contract, relation.toNamespace, relatedTableName, relatedTableAlias)).withJoins([JoinAst.inner(TableSource.named(junctionTable, void 0, through.namespaceId), junctionJoinOn)]).withProjection([ProjectionItem.of("_exists", ColumnRef.of(relatedTableRef, firstTargetCol))]).withWhere(filterPlan.where);
2681
+ 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);
2554
2682
  return filterPlan.notExists ? ExistsExpr.notExists(subquery) : ExistsExpr.exists(subquery);
2555
2683
  }
2556
2684
  function planRelationFilterMode(joinWhere, childWhere, mode) {
@@ -2573,10 +2701,6 @@ function planRelationFilterMode(joinWhere, childWhere, mode) {
2573
2701
  where: childWhere ? and(joinWhere, childWhere) : joinWhere
2574
2702
  };
2575
2703
  }
2576
- function remapColumnRefs(tableName, tableRef, expr) {
2577
- if (!expr || tableName === tableRef) return expr;
2578
- return expr.rewrite({ columnRef: (column) => column.table === tableName ? ColumnRef.of(tableRef, column.column) : column });
2579
- }
2580
2704
  function firstJoinColumn(columns, label) {
2581
2705
  const first = columns[0];
2582
2706
  if (!first) throw new InternalError(`Relation metadata is missing ${label}`);
@@ -2590,14 +2714,14 @@ function buildPairedColumnExprs(leftTable, leftColumns, rightTable, rightColumns
2590
2714
  const left = leftColumns[i];
2591
2715
  const right = rightColumns[i];
2592
2716
  if (!left || !right) throw new InternalError(`Relation metadata is missing a join column pair at index ${i}`);
2593
- exprs.push(BinaryExpr.eq(ColumnRef.of(leftTable, left), ColumnRef.of(rightTable, right)));
2717
+ exprs.push(BinaryExpr.eq(leftTable.column(left), rightTable.column(right)));
2594
2718
  }
2595
2719
  if (exprs.length === 1 && exprs[0]) return exprs[0];
2596
2720
  return and(...exprs);
2597
2721
  }
2598
- function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, predicate) {
2722
+ function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, predicate, scope) {
2599
2723
  if (!predicate) return;
2600
- const accessor = createModelAccessor(context, relatedNamespaceId, relatedModelName);
2724
+ const accessor = createModelAccessorInScope(context, relatedNamespaceId, relatedModelName, void 0, scope);
2601
2725
  if (typeof predicate === "function") return predicate(accessor);
2602
2726
  const exprs = [];
2603
2727
  for (const [fieldName, value] of Object.entries(predicate)) {
@@ -2622,7 +2746,7 @@ function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, pred
2622
2746
  if (exprs.length === 0) return;
2623
2747
  return exprs.length === 1 ? exprs[0] : and(...exprs);
2624
2748
  }
2625
- function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTableName, relatedTableName, relation) {
2749
+ function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTable, relatedTable, relation) {
2626
2750
  const localFields = relation.on?.localFields ?? [];
2627
2751
  const targetFields = relation.on?.targetFields ?? [];
2628
2752
  const joinExprs = [];
@@ -2633,7 +2757,7 @@ function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTabl
2633
2757
  if (!localField || !targetField) continue;
2634
2758
  const localColumn = resolveFieldToColumn(contract, parentNamespaceId, parentModelName, localField);
2635
2759
  const targetColumn = resolveFieldToColumn(contract, relation.toNamespace, relation.to, targetField);
2636
- joinExprs.push(BinaryExpr.eq(ColumnRef.of(relatedTableName, targetColumn), ColumnRef.of(parentTableName, localColumn)));
2760
+ joinExprs.push(BinaryExpr.eq(relatedTable.column(targetColumn), parentTable.column(localColumn)));
2637
2761
  }
2638
2762
  if (joinExprs.length === 0) throw new InternalError("Relation metadata is missing join columns");
2639
2763
  const firstExpr = joinExprs[0];
@@ -3400,7 +3524,7 @@ var Collection = class Collection {
3400
3524
  * .where({ published: true })
3401
3525
  * .groupBy('userId')
3402
3526
  * .aggregate((agg) => ({ count: agg.count(), totalViews: agg.sum('views') }));
3403
- * // [{ userId: 1, count: 3, totalViews: 120 }, ...]
3527
+ * // [{ userId: 1, count: 3n, totalViews: 120n }, ...]
3404
3528
  * ```
3405
3529
  */
3406
3530
  groupBy(...fields) {
@@ -3423,7 +3547,7 @@ var Collection = class Collection {
3423
3547
  *
3424
3548
  * ```typescript
3425
3549
  * const users = await db.orm.User.include('posts', (posts) => posts.count()).all();
3426
- * // each user row: { ...user, posts: number }
3550
+ * // each user row: { ...user, posts: bigint }
3427
3551
  * ```
3428
3552
  */
3429
3553
  count() {
@@ -3438,7 +3562,7 @@ var Collection = class Collection {
3438
3562
  *
3439
3563
  * ```typescript
3440
3564
  * const users = await db.orm.User.include('posts', (posts) => posts.sum('views')).all();
3441
- * // each user row: { ...user, posts: number | null }
3565
+ * // each user row: { ...user, posts: bigint | null } — an int4 column's sum widens to int8
3442
3566
  * ```
3443
3567
  */
3444
3568
  sum(field) {
@@ -3454,7 +3578,7 @@ var Collection = class Collection {
3454
3578
  *
3455
3579
  * ```typescript
3456
3580
  * const users = await db.orm.User.include('posts', (posts) => posts.avg('views')).all();
3457
- * // each user row: { ...user, posts: number | null }
3581
+ * // each user row: { ...user, posts: string | null } — PostgreSQL averages integers as numeric
3458
3582
  * ```
3459
3583
  */
3460
3584
  avg(field) {
@@ -3509,7 +3633,7 @@ var Collection = class Collection {
3509
3633
  * ).all();
3510
3634
  * // each user row: {
3511
3635
  * // ...user,
3512
- * // posts: { recent: Post[]; total: number; averageViews: number | null };
3636
+ * // posts: { recent: Post[]; total: bigint; averageViews: string | null };
3513
3637
  * // }
3514
3638
  * ```
3515
3639
  */
@@ -3681,7 +3805,7 @@ var Collection = class Collection {
3681
3805
  * averageViews: agg.avg('views'),
3682
3806
  * maxViews: agg.max('views'),
3683
3807
  * }));
3684
- * // { total: 42, averageViews: 17.3, maxViews: 9001 }
3808
+ * // { total: 42n, averageViews: '17.3000000000000000', maxViews: 9001 }
3685
3809
  * ```
3686
3810
  *
3687
3811
  * Accepts an optional `configure` callback that receives a
@@ -3701,8 +3825,11 @@ var Collection = class Collection {
3701
3825
  alias
3702
3826
  } });
3703
3827
  const annotationsMap = this.#collectAnnotationsFromMeta(configure, "read", "aggregate");
3704
- const compiled = mergeAnnotations(compileAggregate(this.contract, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
3705
- return normalizeAggregateResult(aggregateSpec, (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {});
3828
+ const compiled = mergeAnnotations(compileAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
3829
+ const row = (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {};
3830
+ const result = {};
3831
+ for (const [alias, selector] of entries) result[alias] = row[alias] ?? emptyAggregateResult(selector.fn);
3832
+ return blindCast(result);
3706
3833
  }
3707
3834
  async create(data, configure) {
3708
3835
  assertReturningCapability(this.contract, "create()");
@@ -4021,9 +4148,10 @@ var Collection = class Collection {
4021
4148
  } });
4022
4149
  }
4023
4150
  /**
4024
- * Write terminal: update matching rows and return the first one (or
4025
- * `null` when no row matched). Requires a prior `.where(...)` —
4026
- * calling `update(...)` on an unfiltered collection is a type error.
4151
+ * Write terminal: update a single matching row the first one the
4152
+ * filter matches — and return it (or `null` when no row matched).
4153
+ * Requires a prior `.where(...)` — calling `update(...)` on an
4154
+ * unfiltered collection is a type error.
4027
4155
  *
4028
4156
  * Related rows can be created or relinked through relation
4029
4157
  * callbacks on parent/child-owned relations (one-to-one or
@@ -4164,9 +4292,10 @@ var Collection = class Collection {
4164
4292
  return matchingRows.length;
4165
4293
  }
4166
4294
  /**
4167
- * Write terminal: delete matching rows and return the first deleted
4168
- * row (or `null` when no row matched). Requires a prior `.where(...)`
4169
- * — calling `delete()` on an unfiltered collection is a type error.
4295
+ * Write terminal: delete a single matching row the first one the
4296
+ * filter matches — and return it (or `null` when no row matched).
4297
+ * Requires a prior `.where(...)` — calling `delete()` on an
4298
+ * unfiltered collection is a type error.
4170
4299
  *
4171
4300
  * ```typescript
4172
4301
  * const deleted = await db.orm.User.where({ id: 1 }).delete();