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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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--BZUAzN1.d.mts} +3 -4
  4. package/dist/ast--BZUAzN1.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-BqrVERXN.d.mts} +10 -10
  31. package/dist/{control-BHmsZudH.d.mts.map → control-BqrVERXN.d.mts.map} +1 -1
  32. package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts → control-adapter-C99J7aEF-mjOpiO_9.d.mts} +6 -6
  33. package/dist/{control-adapter-C99J7aEF-C-17lFY8.d.mts.map → control-adapter-C99J7aEF-mjOpiO_9.d.mts.map} +1 -1
  34. package/dist/control-adapter-xEtAQKd9.d.mts +1 -0
  35. package/dist/{control-B7iS4jv4.mjs → control-mG3RlNzm.mjs} +2 -2
  36. package/dist/{control-B7iS4jv4.mjs.map → control-mG3RlNzm.mjs.map} +1 -1
  37. package/dist/{db-DhMsmBS--DKENDi3l.d.mts → db-B5PMfDDd-BiWfkubp.d.mts} +65 -32
  38. package/dist/db-B5PMfDDd-BiWfkubp.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-CIIMSaVD.d.mts} +5 -5
  42. package/dist/{diff-DhlzHOMD.d.mts.map → diff-CIIMSaVD.d.mts.map} +1 -1
  43. package/dist/{dist-DrScXbhq.mjs → dist-CYkK9Vbk.mjs} +55 -2
  44. package/dist/dist-CYkK9Vbk.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-BgaTJRxj.d.mts → index-BZF7Wehu.d.mts} +3 -3
  61. package/dist/{index-BgaTJRxj.d.mts.map → index-BZF7Wehu.d.mts.map} +1 -1
  62. package/dist/{index-Bb9U36N4.d.mts → index-D_QTT11u.d.mts} +15 -16
  63. package/dist/index-D_QTT11u.d.mts.map +1 -0
  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-Dtyw2JeL.d.mts} +3 -3
  73. package/dist/{migration-CW0ZJLxP.d.mts.map → migration-Dtyw2JeL.d.mts.map} +1 -1
  74. package/dist/operations.d.mts +1 -1
  75. package/dist/orm-client.d.mts +82 -39
  76. package/dist/orm-client.d.mts.map +1 -1
  77. package/dist/orm-client.mjs +157 -122
  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 +3 -4
  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-DXPO2ytG.d.mts} +2 -2
  104. package/dist/{runtime-DNewRuec.d.mts.map → runtime-DXPO2ytG.d.mts.map} +1 -1
  105. package/dist/runtime.d.mts +3 -3
  106. package/dist/runtime.mjs +12 -3
  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-C1Zu2oo9.d.mts} +5 -5
  120. package/dist/{types-IqZMLrFC-DtdJNICr.d.mts.map → types-IqZMLrFC-C1Zu2oo9.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.
@@ -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
- if (scalar.fn === "count") return AggregateExpr.count();
1542
- if (scalar.column === void 0) throw ormError("ORM.AGGREGATE_SELECTOR_INVALID", `Aggregate selector "${scalar.fn}" requires a column`, { meta: { fn: scalar.fn } });
1543
- const columnRef = ColumnRef.of(childTableRef, scalar.column);
1544
- switch (scalar.fn) {
1545
- case "sum": return AggregateExpr.sum(columnRef);
1546
- case "avg": return AggregateExpr.avg(columnRef);
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
- * Values are passed through unchangedno JS-side `Number()` coercion
2101
- * and no JS-side empty-relation defaulting. SQL semantics drive the
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 emptyScalarResult(scalar.fn);
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
- return parsed["value"];
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, selector] of aggregateEntries) mapped[alias] = coerceAggregateValue(selector.fn, row[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",
@@ -3411,7 +3443,7 @@ var Collection = class Collection {
3411
3443
  * .where({ published: true })
3412
3444
  * .groupBy('userId')
3413
3445
  * .aggregate((agg) => ({ count: agg.count(), totalViews: agg.sum('views') }));
3414
- * // [{ userId: 1, count: 3, totalViews: 120 }, ...]
3446
+ * // [{ userId: 1, count: 3n, totalViews: 120n }, ...]
3415
3447
  * ```
3416
3448
  */
3417
3449
  groupBy(...fields) {
@@ -3434,7 +3466,7 @@ var Collection = class Collection {
3434
3466
  *
3435
3467
  * ```typescript
3436
3468
  * const users = await db.orm.User.include('posts', (posts) => posts.count()).all();
3437
- * // each user row: { ...user, posts: number }
3469
+ * // each user row: { ...user, posts: bigint }
3438
3470
  * ```
3439
3471
  */
3440
3472
  count() {
@@ -3449,7 +3481,7 @@ var Collection = class Collection {
3449
3481
  *
3450
3482
  * ```typescript
3451
3483
  * const users = await db.orm.User.include('posts', (posts) => posts.sum('views')).all();
3452
- * // each user row: { ...user, posts: number | null }
3484
+ * // each user row: { ...user, posts: bigint | null } — an int4 column's sum widens to int8
3453
3485
  * ```
3454
3486
  */
3455
3487
  sum(field) {
@@ -3465,7 +3497,7 @@ var Collection = class Collection {
3465
3497
  *
3466
3498
  * ```typescript
3467
3499
  * const users = await db.orm.User.include('posts', (posts) => posts.avg('views')).all();
3468
- * // each user row: { ...user, posts: number | null }
3500
+ * // each user row: { ...user, posts: string | null } — PostgreSQL averages integers as numeric
3469
3501
  * ```
3470
3502
  */
3471
3503
  avg(field) {
@@ -3520,7 +3552,7 @@ var Collection = class Collection {
3520
3552
  * ).all();
3521
3553
  * // each user row: {
3522
3554
  * // ...user,
3523
- * // posts: { recent: Post[]; total: number; averageViews: number | null };
3555
+ * // posts: { recent: Post[]; total: bigint; averageViews: string | null };
3524
3556
  * // }
3525
3557
  * ```
3526
3558
  */
@@ -3692,7 +3724,7 @@ var Collection = class Collection {
3692
3724
  * averageViews: agg.avg('views'),
3693
3725
  * maxViews: agg.max('views'),
3694
3726
  * }));
3695
- * // { total: 42, averageViews: 17.3, maxViews: 9001 }
3727
+ * // { total: 42n, averageViews: '17.3000000000000000', maxViews: 9001 }
3696
3728
  * ```
3697
3729
  *
3698
3730
  * Accepts an optional `configure` callback that receives a
@@ -3712,8 +3744,11 @@ var Collection = class Collection {
3712
3744
  alias
3713
3745
  } });
3714
3746
  const annotationsMap = this.#collectAnnotationsFromMeta(configure, "read", "aggregate");
3715
- const compiled = mergeAnnotations(compileAggregate(this.contract, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
3716
- return normalizeAggregateResult(aggregateSpec, (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {});
3747
+ const compiled = mergeAnnotations(compileAggregate(this.contract, this.ctx.context.aggregateDescriptors, this.namespaceId, this.tableName, this.state.filters, aggregateSpec), annotationsMap);
3748
+ const row = (await executeQueryPlan(this.ctx.runtime, compiled).toArray())[0] ?? {};
3749
+ const result = {};
3750
+ for (const [alias, selector] of entries) result[alias] = row[alias] ?? emptyAggregateResult(selector.fn);
3751
+ return blindCast(result);
3717
3752
  }
3718
3753
  async create(data, configure) {
3719
3754
  assertReturningCapability(this.contract, "create()");