@prisma/orm-family-mongo 0.16.0-dev.36

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 (166) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +27 -0
  3. package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs +176 -0
  4. package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs.map +1 -0
  5. package/dist/canonicalization-hooks-DF3Z6sjO.mjs +22 -0
  6. package/dist/canonicalization-hooks-DF3Z6sjO.mjs.map +1 -0
  7. package/dist/codec.d.mts +2 -0
  8. package/dist/codec.mjs +2 -0
  9. package/dist/config-types-CFDf9ivE.mjs +37 -0
  10. package/dist/config-types-CFDf9ivE.mjs.map +1 -0
  11. package/dist/config-types-CQOf5N7R.d.mts +12 -0
  12. package/dist/config-types-CQOf5N7R.d.mts.map +1 -0
  13. package/dist/contract-builder-BFq0gOMV.mjs +634 -0
  14. package/dist/contract-builder-BFq0gOMV.mjs.map +1 -0
  15. package/dist/contract-builder-DB8nguDE.d.mts +445 -0
  16. package/dist/contract-builder-DB8nguDE.d.mts.map +1 -0
  17. package/dist/contract-errors-BCN6RVI5-kMurtAbI.mjs +9 -0
  18. package/dist/contract-errors-BCN6RVI5-kMurtAbI.mjs.map +1 -0
  19. package/dist/contract-psl.d.mts +45 -0
  20. package/dist/contract-psl.d.mts.map +1 -0
  21. package/dist/contract-psl.mjs +2 -0
  22. package/dist/contract-psl__provider.d.mts +15 -0
  23. package/dist/contract-psl__provider.d.mts.map +1 -0
  24. package/dist/contract-psl__provider.mjs +82 -0
  25. package/dist/contract-psl__provider.mjs.map +1 -0
  26. package/dist/contract-ts.d.mts +3 -0
  27. package/dist/contract-ts.mjs +3 -0
  28. package/dist/contract-ts__config-types.d.mts +2 -0
  29. package/dist/contract-ts__config-types.mjs +2 -0
  30. package/dist/contract-ts__contract-builder.d.mts +2 -0
  31. package/dist/contract-ts__contract-builder.mjs +2 -0
  32. package/dist/contract.d.mts +3 -0
  33. package/dist/contract.mjs +3 -0
  34. package/dist/contract__canonicalization-hooks.d.mts +9 -0
  35. package/dist/contract__canonicalization-hooks.d.mts.map +1 -0
  36. package/dist/contract__canonicalization-hooks.mjs +2 -0
  37. package/dist/contract__entity-kinds.d.mts +17 -0
  38. package/dist/contract__entity-kinds.d.mts.map +1 -0
  39. package/dist/contract__entity-kinds.mjs +2 -0
  40. package/dist/control-C7-kthr1.d.mts +193 -0
  41. package/dist/control-C7-kthr1.d.mts.map +1 -0
  42. package/dist/control-CClR5JMr.mjs +127 -0
  43. package/dist/control-CClR5JMr.mjs.map +1 -0
  44. package/dist/control-CFr3tYsg.mjs +398 -0
  45. package/dist/control-CFr3tYsg.mjs.map +1 -0
  46. package/dist/control-Cj81sPbj.d.mts +101 -0
  47. package/dist/control-Cj81sPbj.d.mts.map +1 -0
  48. package/dist/control-adapter-Db5pT77b.d.mts +83 -0
  49. package/dist/control-adapter-Db5pT77b.d.mts.map +1 -0
  50. package/dist/dist-C7Ykq48Q.mjs +19 -0
  51. package/dist/dist-C7Ykq48Q.mjs.map +1 -0
  52. package/dist/dist-Czwqx_i3.mjs +58 -0
  53. package/dist/dist-Czwqx_i3.mjs.map +1 -0
  54. package/dist/dist-DHrEJnhK.mjs +236 -0
  55. package/dist/dist-DHrEJnhK.mjs.map +1 -0
  56. package/dist/dist-Dyp05u64.mjs +1546 -0
  57. package/dist/dist-Dyp05u64.mjs.map +1 -0
  58. package/dist/emitter.d.mts +22 -0
  59. package/dist/emitter.d.mts.map +1 -0
  60. package/dist/emitter.mjs +2 -0
  61. package/dist/entity-kinds-B4KNTF8z-DPIuUuuB.mjs +603 -0
  62. package/dist/entity-kinds-B4KNTF8z-DPIuUuuB.mjs.map +1 -0
  63. package/dist/execution-CKnUiOfm.d.mts +48 -0
  64. package/dist/execution-CKnUiOfm.d.mts.map +1 -0
  65. package/dist/execution-D5XyZ5XS.mjs +1269 -0
  66. package/dist/execution-D5XyZ5XS.mjs.map +1 -0
  67. package/dist/exports-Bx-hlnZ3.mjs +209 -0
  68. package/dist/exports-Bx-hlnZ3.mjs.map +1 -0
  69. package/dist/exports-CJMh0VTU.mjs +156 -0
  70. package/dist/exports-CJMh0VTU.mjs.map +1 -0
  71. package/dist/family.d.mts +10 -0
  72. package/dist/family.mjs +9 -0
  73. package/dist/family__control-adapter.d.mts +2 -0
  74. package/dist/family__control-adapter.mjs +1 -0
  75. package/dist/family__control.d.mts +2 -0
  76. package/dist/family__control.mjs +3 -0
  77. package/dist/family__ir.d.mts +3 -0
  78. package/dist/family__ir.mjs +4 -0
  79. package/dist/family__migration.d.mts +2 -0
  80. package/dist/family__migration.mjs +2 -0
  81. package/dist/family__pack.d.mts +2 -0
  82. package/dist/family__pack.mjs +16 -0
  83. package/dist/family__pack.mjs.map +1 -0
  84. package/dist/family__runtime.d.mts +3 -0
  85. package/dist/family__runtime.mjs +2 -0
  86. package/dist/family__schema-verify.d.mts +2 -0
  87. package/dist/family__schema-verify.mjs +2 -0
  88. package/dist/field-accessor-0oUt6RZC-B_Z30uAA.mjs +234 -0
  89. package/dist/field-accessor-0oUt6RZC-B_Z30uAA.mjs.map +1 -0
  90. package/dist/field-accessor-DHsAPiW3-BdYCspQC.d.mts +588 -0
  91. package/dist/field-accessor-DHsAPiW3-BdYCspQC.d.mts.map +1 -0
  92. package/dist/filter-expressions-Uo8ZdzwB-53qnqceS.mjs +181 -0
  93. package/dist/filter-expressions-Uo8ZdzwB-53qnqceS.mjs.map +1 -0
  94. package/dist/index-BR0ue13b.d.mts +136 -0
  95. package/dist/index-BR0ue13b.d.mts.map +1 -0
  96. package/dist/index-Cd2zLiU6.d.mts +128 -0
  97. package/dist/index-Cd2zLiU6.d.mts.map +1 -0
  98. package/dist/index-DAOkcTCK.d.mts +151 -0
  99. package/dist/index-DAOkcTCK.d.mts.map +1 -0
  100. package/dist/index-Dv2PNMiG.d.mts +53 -0
  101. package/dist/index-Dv2PNMiG.d.mts.map +1 -0
  102. package/dist/index-DxoO-ywI.d.mts +178 -0
  103. package/dist/index-DxoO-ywI.d.mts.map +1 -0
  104. package/dist/index-wKMm41HC.d.mts +30 -0
  105. package/dist/index-wKMm41HC.d.mts.map +1 -0
  106. package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs +1091 -0
  107. package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs.map +1 -0
  108. package/dist/ir-CQrenTYt.d.mts +147 -0
  109. package/dist/ir-CQrenTYt.d.mts.map +1 -0
  110. package/dist/ir-Ch2aPr7a.mjs +62 -0
  111. package/dist/ir-Ch2aPr7a.mjs.map +1 -0
  112. package/dist/lowering.d.mts +2 -0
  113. package/dist/lowering.mjs +1 -0
  114. package/dist/migration-CNDQv5yB.d.mts +50 -0
  115. package/dist/migration-CNDQv5yB.d.mts.map +1 -0
  116. package/dist/migration-dcM7u4HG.mjs +52 -0
  117. package/dist/migration-dcM7u4HG.mjs.map +1 -0
  118. package/dist/mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs +119 -0
  119. package/dist/mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs.map +1 -0
  120. package/dist/mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts +27 -0
  121. package/dist/mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts.map +1 -0
  122. package/dist/mongo-contract-view-rcWzby6f-wRBCUnBt.mjs +17 -0
  123. package/dist/mongo-contract-view-rcWzby6f-wRBCUnBt.mjs.map +1 -0
  124. package/dist/mongo-value-set-tNn9-pun-dJYx_rVD.d.mts +536 -0
  125. package/dist/mongo-value-set-tNn9-pun-dJYx_rVD.d.mts.map +1 -0
  126. package/dist/mongodb-types-B4HmhF1S.d.mts +2 -0
  127. package/dist/orm.d.mts +311 -0
  128. package/dist/orm.d.mts.map +1 -0
  129. package/dist/orm.mjs +664 -0
  130. package/dist/orm.mjs.map +1 -0
  131. package/dist/pack-D9aLY50F.d.mts +44 -0
  132. package/dist/pack-D9aLY50F.d.mts.map +1 -0
  133. package/dist/query-ast.d.mts +5 -0
  134. package/dist/query-ast.mjs +4 -0
  135. package/dist/query-ast__control.d.mts +4 -0
  136. package/dist/query-ast__control.mjs +3 -0
  137. package/dist/query-ast__execution.d.mts +3 -0
  138. package/dist/query-ast__execution.mjs +3 -0
  139. package/dist/query-builder.d.mts +836 -0
  140. package/dist/query-builder.d.mts.map +1 -0
  141. package/dist/query-builder.mjs +3 -0
  142. package/dist/query-builder__contract-free.d.mts +83 -0
  143. package/dist/query-builder__contract-free.d.mts.map +1 -0
  144. package/dist/query-builder__contract-free.mjs +107 -0
  145. package/dist/query-builder__contract-free.mjs.map +1 -0
  146. package/dist/query-plan-C0-Yu8hf-DdilEdW6.d.mts +822 -0
  147. package/dist/query-plan-C0-Yu8hf-DdilEdW6.d.mts.map +1 -0
  148. package/dist/runtime-DPkRW4iu.d.mts +1 -0
  149. package/dist/runtime.d.mts +286 -0
  150. package/dist/runtime.d.mts.map +1 -0
  151. package/dist/runtime.mjs +532 -0
  152. package/dist/runtime.mjs.map +1 -0
  153. package/dist/schema-ir.d.mts +2 -0
  154. package/dist/schema-ir.mjs +2 -0
  155. package/dist/schema-verify-DJGr28XW.d.mts +23 -0
  156. package/dist/schema-verify-DJGr28XW.d.mts.map +1 -0
  157. package/dist/value.d.mts +2 -0
  158. package/dist/value.mjs +2 -0
  159. package/dist/value__mongodb-types.d.mts +2 -0
  160. package/dist/value__mongodb-types.mjs +1 -0
  161. package/dist/verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs +447 -0
  162. package/dist/verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs.map +1 -0
  163. package/dist/wire.d.mts +3 -0
  164. package/dist/wire.mjs +190 -0
  165. package/dist/wire.mjs.map +1 -0
  166. package/package.json +89 -0
@@ -0,0 +1,1546 @@
1
+ import { r as MongoExistsExpr, t as MongoAndExpr } from "./filter-expressions-Uo8ZdzwB-53qnqceS.mjs";
2
+ import { A as MongoLookupStage, B as MongoSetWindowFieldsStage, C as MongoDensifyStage, D as MongoGraphLookupStage, E as MongoGeoNearStage, F as MongoRedactStage, G as MongoUnwindStage, H as MongoSortByCountStage, I as MongoReplaceRootStage, K as MongoVectorSearchStage, L as MongoSampleStage, M as MongoMergeStage, N as MongoOutStage, O as MongoGroupStage, P as MongoProjectStage, R as MongoSearchMetaStage, S as MongoCountStage, T as MongoFillStage, U as MongoSortStage, V as MongoSkipStage, W as MongoUnionWithStage, _ as MongoAggOperator, a as FindOneAndUpdateCommand, at as freezeMongoResultShape, b as MongoBucketAutoStage, c as MongoAddFieldsStage, d as MongoAggCond, f as MongoAggFieldRef, i as FindOneAndDeleteCommand, it as freezeMongoFieldShape, j as MongoMatchStage, k as MongoLimitStage, l as MongoAggAccumulator, m as MongoAggLiteral, n as DeleteManyCommand, nt as UpdateManyCommand, o as InsertManyCommand, r as DeleteOneCommand, rt as UpdateOneCommand, s as InsertOneCommand, t as AggregateCommand, w as MongoFacetStage, x as MongoBucketStage, z as MongoSearchStage } from "./execution-D5XyZ5XS.mjs";
3
+ import { i as resolveUpdaterResult, r as ormError, t as createFieldAccessor } from "./field-accessor-0oUt6RZC-B_Z30uAA.mjs";
4
+ import { structuredError } from "@prisma/orm-framework/utils/structured-error";
5
+ import { domainModelsAtDefaultNamespace } from "@prisma/orm-framework/contract/types";
6
+ import { blindCast, castAs } from "@prisma/orm-framework/utils/casts";
7
+ import { ifDefined } from "@prisma/orm-framework/utils/defined";
8
+ import { InternalError } from "@prisma/orm-framework/utils/internal-error";
9
+ //#region ../../../2-mongo-family/5-query-builders/query-builder/dist/index.mjs
10
+ function namedAccumulatorArgs(args) {
11
+ const result = {};
12
+ for (const [key, val] of Object.entries(args)) if (val !== void 0) result[key] = val.node;
13
+ return result;
14
+ }
15
+ const acc = {
16
+ sum(expr) {
17
+ return {
18
+ _field: void 0,
19
+ node: MongoAggAccumulator.sum(expr.node)
20
+ };
21
+ },
22
+ avg(expr) {
23
+ return {
24
+ _field: void 0,
25
+ node: MongoAggAccumulator.avg(expr.node)
26
+ };
27
+ },
28
+ min(expr) {
29
+ return {
30
+ _field: void 0,
31
+ node: MongoAggAccumulator.min(expr.node)
32
+ };
33
+ },
34
+ max(expr) {
35
+ return {
36
+ _field: void 0,
37
+ node: MongoAggAccumulator.max(expr.node)
38
+ };
39
+ },
40
+ first(expr) {
41
+ return {
42
+ _field: void 0,
43
+ node: MongoAggAccumulator.first(expr.node)
44
+ };
45
+ },
46
+ last(expr) {
47
+ return {
48
+ _field: void 0,
49
+ node: MongoAggAccumulator.last(expr.node)
50
+ };
51
+ },
52
+ push(expr) {
53
+ return {
54
+ _field: void 0,
55
+ node: MongoAggAccumulator.push(expr.node)
56
+ };
57
+ },
58
+ addToSet(expr) {
59
+ return {
60
+ _field: void 0,
61
+ node: MongoAggAccumulator.addToSet(expr.node)
62
+ };
63
+ },
64
+ count() {
65
+ return {
66
+ _field: void 0,
67
+ node: MongoAggAccumulator.count()
68
+ };
69
+ },
70
+ stdDevPop(expr) {
71
+ return {
72
+ _field: void 0,
73
+ node: MongoAggAccumulator.stdDevPop(expr.node)
74
+ };
75
+ },
76
+ stdDevSamp(expr) {
77
+ return {
78
+ _field: void 0,
79
+ node: MongoAggAccumulator.stdDevSamp(expr.node)
80
+ };
81
+ },
82
+ firstN(args) {
83
+ return {
84
+ _field: void 0,
85
+ node: MongoAggAccumulator.of("$firstN", namedAccumulatorArgs(args))
86
+ };
87
+ },
88
+ lastN(args) {
89
+ return {
90
+ _field: void 0,
91
+ node: MongoAggAccumulator.of("$lastN", namedAccumulatorArgs(args))
92
+ };
93
+ },
94
+ maxN(args) {
95
+ return {
96
+ _field: void 0,
97
+ node: MongoAggAccumulator.of("$maxN", namedAccumulatorArgs(args))
98
+ };
99
+ },
100
+ minN(args) {
101
+ return {
102
+ _field: void 0,
103
+ node: MongoAggAccumulator.of("$minN", namedAccumulatorArgs(args))
104
+ };
105
+ },
106
+ top(args) {
107
+ return {
108
+ _field: void 0,
109
+ node: MongoAggAccumulator.of("$top", {
110
+ output: args.output.node,
111
+ sortBy: MongoAggLiteral.of(args.sortBy)
112
+ })
113
+ };
114
+ },
115
+ bottom(args) {
116
+ return {
117
+ _field: void 0,
118
+ node: MongoAggAccumulator.of("$bottom", {
119
+ output: args.output.node,
120
+ sortBy: MongoAggLiteral.of(args.sortBy)
121
+ })
122
+ };
123
+ },
124
+ topN(args) {
125
+ return {
126
+ _field: void 0,
127
+ node: MongoAggAccumulator.of("$topN", {
128
+ output: args.output.node,
129
+ sortBy: MongoAggLiteral.of(args.sortBy),
130
+ n: args.n.node
131
+ })
132
+ };
133
+ },
134
+ bottomN(args) {
135
+ return {
136
+ _field: void 0,
137
+ node: MongoAggAccumulator.of("$bottomN", {
138
+ output: args.output.node,
139
+ sortBy: MongoAggLiteral.of(args.sortBy),
140
+ n: args.n.node
141
+ })
142
+ };
143
+ }
144
+ };
145
+ /**
146
+ * Construct the `from` callable for `PipelineChain.lookup`. The contract
147
+ * is captured so `from(name)` can resolve `roots[name]` to the foreign
148
+ * model name at runtime, look up the foreign collection name from
149
+ * `models[modelName].storage.collection`, and assemble a `LookupResult`
150
+ * for the outer `lookup` to consume.
151
+ *
152
+ * The `Shape`/`Nested` generics are erased at runtime — they exist only
153
+ * to type the local accessor inside the user's `on(...)` callback. The
154
+ * contract value at runtime carries the real model lookup table.
155
+ */
156
+ function createLookupFrom(contract) {
157
+ const callable = ((rootName) => {
158
+ const modelName = contract.roots[rootName]?.model;
159
+ if (!modelName) throw ormError("ORM.MODEL_UNKNOWN", `lookup() unknown root: "${rootName}". Valid roots: ${Object.keys(contract.roots).join(", ")}`);
160
+ return createLookupBuilder({
161
+ rootName,
162
+ modelName,
163
+ foreignCollection: domainModelsAtDefaultNamespace(contract.domain)[modelName]?.storage?.collection ?? rootName
164
+ });
165
+ });
166
+ return callable;
167
+ }
168
+ function createLookupBuilder(state) {
169
+ return { on(cb) {
170
+ const result = cb(createFieldAccessor(), createFieldAccessor());
171
+ assertLeafExpression(result.local, "local");
172
+ assertLeafExpression(result.foreign, "foreign");
173
+ return createLookupBuilderWithKey({
174
+ ...state,
175
+ localField: result.local._path,
176
+ foreignField: result.foreign._path
177
+ });
178
+ } };
179
+ }
180
+ function createLookupBuilderWithKey(state) {
181
+ return { as(name) {
182
+ return {
183
+ _brand: "mongo-query-builder/lookup-result@1",
184
+ _root: state.rootName,
185
+ _model: state.modelName,
186
+ _localField: state.localField,
187
+ _foreignField: state.foreignField,
188
+ _as: name
189
+ };
190
+ } };
191
+ }
192
+ /**
193
+ * Defensive runtime guard catching the case where a user returns a
194
+ * non-`LeafExpression` from the `on(...)` callback (e.g. by casting
195
+ * around the type system, or threading a value in from outside the
196
+ * callback). Compile-time gating via `LookupOnResult`'s `LeafExpression`
197
+ * type already rejects `fn.<op>(…)` returns at the type level — this
198
+ * guard is the runtime backstop matching the defensive style of
199
+ * `deconstructFindAndModifyChain` in builder.ts.
200
+ */
201
+ function assertLeafExpression(value, side) {
202
+ if (!value || typeof value._path !== "string" || value._path.length === 0) throw ormError("ORM.ARGUMENT_INVALID", `lookup().on() ${side} side must return a leaf field reference (e.g. \`${side}.<field>\`). Aggregation expressions and computed values are not supported.`);
203
+ }
204
+ /**
205
+ * Extract the runtime metadata from a `LookupResult` for `PipelineChain
206
+ * .lookup` to construct the `MongoLookupStage`. The internal fields are
207
+ * intentionally underscore-prefixed and brand-checked here so user code
208
+ * cannot synthesise a fake spec; this is the single ingress point.
209
+ */
210
+ function extractLookupResult(result, contract) {
211
+ if (result?._brand !== "mongo-query-builder/lookup-result@1") throw ormError("ORM.ARGUMENT_INVALID", "lookup() callback must return the result of `from(name).on(cb).as(name)`. Returning a hand-rolled options object is not supported.");
212
+ return {
213
+ foreignCollection: domainModelsAtDefaultNamespace(contract.domain)[result._model]?.storage?.collection ?? result._root,
214
+ localField: result._localField,
215
+ foreignField: result._foreignField,
216
+ as: result._as,
217
+ modelName: result._model
218
+ };
219
+ }
220
+ const identityStageKinds = /* @__PURE__ */ new Set([
221
+ "match",
222
+ "sort",
223
+ "limit",
224
+ "skip",
225
+ "sample",
226
+ "vectorSearch"
227
+ ]);
228
+ const unknownShape = { kind: "unknown" };
229
+ function fieldShapeAtPath(shape, path) {
230
+ if (shape.kind !== "document" || path.includes(".")) return unknownShape;
231
+ return shape.fields[path] ?? unknownShape;
232
+ }
233
+ function shapeForExpr(currentShape, expr) {
234
+ if (expr instanceof MongoAggFieldRef) return fieldShapeAtPath(currentShape, expr.path);
235
+ return unknownShape;
236
+ }
237
+ function resultShapeAfterProject(currentShape, stage) {
238
+ if (currentShape.kind !== "document") return { kind: "unknown" };
239
+ const fields = {};
240
+ for (const [key, value] of Object.entries(stage.projection)) {
241
+ if (value === 0) continue;
242
+ if (value === 1) {
243
+ fields[key] = currentShape.fields[key] ?? unknownShape;
244
+ continue;
245
+ }
246
+ fields[key] = shapeForExpr(currentShape, value);
247
+ }
248
+ if (!Object.hasOwn(stage.projection, "_id") && currentShape.fields["_id"]) fields["_id"] = currentShape.fields["_id"];
249
+ return freezeMongoResultShape({
250
+ kind: "document",
251
+ fields
252
+ });
253
+ }
254
+ function resultShapeAfterAddFields(currentShape, stage) {
255
+ if (currentShape.kind !== "document") return { kind: "unknown" };
256
+ const fields = { ...currentShape.fields };
257
+ for (const [key, expr] of Object.entries(stage.fields)) fields[key] = shapeForExpr(currentShape, expr);
258
+ return freezeMongoResultShape({
259
+ kind: "document",
260
+ fields
261
+ });
262
+ }
263
+ function computePipelineResultShape(stages, startShape) {
264
+ let shape = startShape;
265
+ for (const stage of stages) {
266
+ if (shape.kind === "unknown") return { kind: "unknown" };
267
+ if (identityStageKinds.has(stage.kind)) continue;
268
+ if (stage instanceof MongoProjectStage) {
269
+ shape = resultShapeAfterProject(shape, stage);
270
+ continue;
271
+ }
272
+ if (stage instanceof MongoAddFieldsStage) {
273
+ shape = resultShapeAfterAddFields(shape, stage);
274
+ continue;
275
+ }
276
+ return { kind: "unknown" };
277
+ }
278
+ return shape;
279
+ }
280
+ function contractFieldToMongoFieldShape(field) {
281
+ const { type, nullable, many } = field;
282
+ if (type.kind === "valueObject" || type.kind === "union") return Object.freeze({ kind: "unknown" });
283
+ if (type.kind !== "scalar") return Object.freeze({ kind: "unknown" });
284
+ if (field.dict === true) return Object.freeze({ kind: "unknown" });
285
+ if (many === true) return freezeMongoFieldShape({
286
+ kind: "array",
287
+ nullable,
288
+ element: {
289
+ kind: "leaf",
290
+ codecId: type.codecId,
291
+ nullable: false
292
+ }
293
+ });
294
+ return freezeMongoFieldShape({
295
+ kind: "leaf",
296
+ codecId: type.codecId,
297
+ nullable
298
+ });
299
+ }
300
+ function contractModelToMongoResultShape(model, options) {
301
+ const fields = {};
302
+ for (const rel of options?.includeRelationNames ?? []) fields[rel] = Object.freeze({ kind: "unknown" });
303
+ const modelFields = model.fields;
304
+ const keys = options?.selection !== void 0 ? options.selection : Object.keys(modelFields);
305
+ for (const key of keys) {
306
+ if (Object.hasOwn(fields, key)) continue;
307
+ const cf = modelFields[key];
308
+ if (!cf) {
309
+ fields[key] = Object.freeze({ kind: "unknown" });
310
+ continue;
311
+ }
312
+ fields[key] = contractFieldToMongoFieldShape(cf);
313
+ }
314
+ return freezeMongoResultShape({
315
+ kind: "document",
316
+ fields
317
+ });
318
+ }
319
+ /**
320
+ * The pipeline state in the query-builder state machine.
321
+ *
322
+ * Reached from `CollectionHandle` or `FilteredCollection` after the first
323
+ * pipeline-stage method call (or directly via `aggregate()` shortcuts). Holds
324
+ * the accumulated `MongoPipelineStage[]` and exposes pipeline-stage methods,
325
+ * the `merge`/`out` write terminals, and the `build`/`aggregate` read
326
+ * terminals.
327
+ *
328
+ * Two phantom type parameters gate the conditional terminals:
329
+ *
330
+ * - `U extends UpdateEnabled` — when `'update-ok'`, the no-arg `updateMany()` /
331
+ * `updateOne()` form is available (consume the chain as an
332
+ * update-with-pipeline spec). Cleared by stages that produce content the
333
+ * `update` AST cannot represent (e.g. `$group`, `$lookup`, `$limit`).
334
+ * - `F extends FindAndModifyEnabled` — when `'fam-ok'`, the
335
+ * `findOneAndUpdate(...)` / `findOneAndDelete(...)` terminals are
336
+ * available. Cleared by stages incompatible with their wire-command slots
337
+ * (`$limit`, `$group`, mutating stages, …).
338
+ *
339
+ * The marker semantics are encoded in the per-method return types — see the
340
+ * marker table (and rationale per row) in
341
+ * `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.
342
+ */
343
+ var PipelineChain = class PipelineChain {
344
+ #contract;
345
+ #state;
346
+ constructor(contract, state) {
347
+ this.#contract = contract;
348
+ this.#state = state;
349
+ }
350
+ /**
351
+ * Internal helper that appends a pipeline stage and branches into a new
352
+ * state-type. The fifth type parameter `NewN` carries the nested-path
353
+ * shape forward. It defaults to `Record<string, never>` so stages that
354
+ * fundamentally rewrite the document (`$group`, `$project`,
355
+ * `$replaceRoot`, …) automatically disable the callable form of
356
+ * `FieldAccessor` downstream. Additive stages (`match`, `addFields`,
357
+ * `sort`, `lookup`, …) explicitly re-thread the current `N`.
358
+ */
359
+ #withStage(stage) {
360
+ return new PipelineChain(this.#contract, {
361
+ ...this.#state,
362
+ stages: [...this.#state.stages, stage]
363
+ });
364
+ }
365
+ #writeMeta() {
366
+ return {
367
+ target: "mongo",
368
+ storageHash: this.#state.storageHash,
369
+ lane: "mongo-query"
370
+ };
371
+ }
372
+ match(filterOrFn) {
373
+ const filter = typeof filterOrFn === "function" ? filterOrFn(createFieldAccessor()) : filterOrFn;
374
+ return this.#withStage(new MongoMatchStage(filter));
375
+ }
376
+ /**
377
+ * `$sort`. Clears `UpdateEnabled` (`update` has no per-document sort) but
378
+ * preserves `FindAndModifyEnabled` (`findAndModify` has a `sort` slot).
379
+ */
380
+ sort(spec) {
381
+ return this.#withStage(new MongoSortStage(spec));
382
+ }
383
+ /**
384
+ * `$limit`. Clears both markers — `limit` is incompatible with the `update`
385
+ * wire command, and `findAndModify` already implies single-document
386
+ * semantics (so `.limit(...)` adds no meaning, only ambiguity).
387
+ */
388
+ limit(n) {
389
+ return this.#withStage(new MongoLimitStage(n));
390
+ }
391
+ /**
392
+ * `$skip`. Clears both markers — MongoDB's `findAndModify` wire command
393
+ * has no `skip` slot, so `deconstructFindAndModifyChain` rejects any
394
+ * `$skip` at runtime; keeping the marker `fam-cleared` makes the type
395
+ * system reflect the same constraint (see ADR 201 marker table).
396
+ */
397
+ skip(n) {
398
+ return this.#withStage(new MongoSkipStage(n));
399
+ }
400
+ sample(n) {
401
+ return this.#withStage(new MongoSampleStage(n));
402
+ }
403
+ /**
404
+ * `$addFields`. Preserves `UpdateEnabled` (representable as
405
+ * update-with-pipeline `$set`); clears `FindAndModifyEnabled` (no analogue
406
+ * in the find-and-modify wire commands). The nested-path shape `N` is
407
+ * preserved — newly added flat fields are reachable via property access
408
+ * (`f.newField`) but do not themselves carry nested structure.
409
+ */
410
+ addFields(fn) {
411
+ const newFields = fn(createFieldAccessor());
412
+ const exprRecord = {};
413
+ for (const [key, typed] of Object.entries(newFields)) exprRecord[key] = typed.node;
414
+ return this.#withStage(new MongoAddFieldsStage(exprRecord));
415
+ }
416
+ /**
417
+ * `$lookup`. Clears both markers — joins are not representable in either
418
+ * the `update` or `findAndModify` wire commands. The original document's
419
+ * nested-path shape `N` is preserved (the lookup adds a sidecar array
420
+ * field; existing keys are untouched).
421
+ *
422
+ * The single callback receives a `from` callable that grounds the
423
+ * foreign-root literal sequentially before the inner `on(...)`
424
+ * callback is type-checked — see `lookup-builder.ts`. The resulting
425
+ * `Shape` gains the `As` key as a `ModelArrayField<ModelName>` so
426
+ * `ResolveRow` produces `Array<ForeignRow>` (with concrete leaf
427
+ * types) instead of the legacy `unknown[]`.
428
+ */
429
+ lookup(fn) {
430
+ const extracted = extractLookupResult(fn(createLookupFrom(this.#contract)), this.#contract);
431
+ return this.#withStage(new MongoLookupStage({
432
+ from: extracted.foreignCollection,
433
+ localField: extracted.localField,
434
+ foreignField: extracted.foreignField,
435
+ as: extracted.as
436
+ }));
437
+ }
438
+ project(...args) {
439
+ if (args.length === 1 && typeof args[0] === "function") {
440
+ const fn = args[0];
441
+ const spec = fn(createFieldAccessor());
442
+ const projection = {};
443
+ for (const [key, val] of Object.entries(spec)) projection[key] = val === 1 ? 1 : val.node;
444
+ return this.#withStage(new MongoProjectStage(projection));
445
+ }
446
+ const keys = args;
447
+ const projection = {};
448
+ for (const key of keys) projection[key] = 1;
449
+ return this.#withStage(new MongoProjectStage(projection));
450
+ }
451
+ /**
452
+ * `$unwind`. Clears both markers — array unrolling produces multiple output
453
+ * documents per input, incompatible with both single-document update and
454
+ * find-and-modify wire commands. The original `N` is preserved: unwind
455
+ * replaces the unwound array slot with its element but leaves the rest
456
+ * of the document structurally intact.
457
+ */
458
+ unwind(field, options) {
459
+ return this.#withStage(new MongoUnwindStage(`$${field}`, options?.preserveNullAndEmptyArrays ?? false));
460
+ }
461
+ /**
462
+ * `$group`. Clears both markers — group output bears no relation to source
463
+ * documents; neither `update` nor `findAndModify` can consume it. Nested
464
+ * path shape is reset (the source document's path tree is gone).
465
+ */
466
+ group(fn) {
467
+ const { _id: groupIdExpr, ...rest } = fn(createFieldAccessor());
468
+ const groupId = groupIdExpr === null ? null : groupIdExpr.node;
469
+ const accumulators = {};
470
+ for (const [key, typed] of Object.entries(rest)) {
471
+ if (typed === null) throw ormError("ORM.ARGUMENT_INVALID", `group() field "${key}" must not be null. Only _id can be null.`);
472
+ if (typed.node.kind !== "accumulator") throw ormError("ORM.ARGUMENT_INVALID", `group() field "${key}" must use an accumulator (e.g. acc.sum(), acc.count()). Got "${typed.node.kind}" expression.`);
473
+ accumulators[key] = typed.node;
474
+ }
475
+ return this.#withStage(new MongoGroupStage(groupId, accumulators));
476
+ }
477
+ /**
478
+ * `$replaceRoot`. Preserves `UpdateEnabled` (representable as
479
+ * update-with-pipeline `$replaceRoot`); clears `FindAndModifyEnabled`.
480
+ * Nested path shape is reset — the replaced root has no relation to
481
+ * the original document structure.
482
+ */
483
+ replaceRoot(fn) {
484
+ const expr = fn(createFieldAccessor());
485
+ return this.#withStage(new MongoReplaceRootStage(expr.node));
486
+ }
487
+ count(field) {
488
+ return this.#withStage(new MongoCountStage(field));
489
+ }
490
+ sortByCount(fn) {
491
+ const expr = fn(createFieldAccessor());
492
+ return this.#withStage(new MongoSortByCountStage(expr.node));
493
+ }
494
+ /**
495
+ * `$redact`. Preserves `UpdateEnabled`; clears `FindAndModifyEnabled`.
496
+ * Shape- and nested-path-preserving (the document tree is unchanged).
497
+ */
498
+ redact(fn) {
499
+ const expr = fn(createFieldAccessor());
500
+ return this.#withStage(new MongoRedactStage(expr.node));
501
+ }
502
+ /**
503
+ * `$out` write terminal. Materialises the pipeline output into
504
+ * `collection` (optionally in `db`), replacing any prior contents. Unlike
505
+ * the other pipeline-stage methods, this **terminates** the chain — it
506
+ * returns a `MongoQueryPlan` rather than another `PipelineChain`, since
507
+ * `$out` must be the final stage and there is nothing further to chain.
508
+ *
509
+ * Lane is `mongo-query` (matching all other terminals in this package) so
510
+ * middleware can dispatch on intent without inspecting the command.
511
+ *
512
+ * The result row stream is empty (`unknown` row type) — the data lives
513
+ * in the destination collection, not the response.
514
+ */
515
+ out(collection, db) {
516
+ return this.#writeTerminal(new MongoOutStage(collection, db));
517
+ }
518
+ /**
519
+ * `$merge` write terminal. Streams the pipeline output into the target
520
+ * collection per the supplied merge semantics (`whenMatched` /
521
+ * `whenNotMatched`). Like `out()`, terminates the chain — `$merge` must
522
+ * be the final stage.
523
+ */
524
+ merge(options) {
525
+ return this.#writeTerminal(new MongoMergeStage(options));
526
+ }
527
+ #writeTerminal(stage) {
528
+ const pipeline = [...this.#state.stages, stage];
529
+ const command = new AggregateCommand(this.#state.collection, pipeline);
530
+ const meta = {
531
+ target: "mongo",
532
+ storageHash: this.#state.storageHash,
533
+ lane: "mongo-query"
534
+ };
535
+ return {
536
+ collection: this.#state.collection,
537
+ command,
538
+ meta
539
+ };
540
+ }
541
+ unionWith(collection, pipeline) {
542
+ return this.#withStage(new MongoUnionWithStage(collection, pipeline));
543
+ }
544
+ bucket(options) {
545
+ return this.#withStage(new MongoBucketStage(options));
546
+ }
547
+ bucketAuto(options) {
548
+ return this.#withStage(new MongoBucketAutoStage(options));
549
+ }
550
+ geoNear(options) {
551
+ return this.#withStage(new MongoGeoNearStage(options));
552
+ }
553
+ facet(facets) {
554
+ return this.#withStage(new MongoFacetStage(facets));
555
+ }
556
+ graphLookup(options) {
557
+ return this.#withStage(new MongoGraphLookupStage(options));
558
+ }
559
+ setWindowFields(options) {
560
+ return this.#withStage(new MongoSetWindowFieldsStage(options));
561
+ }
562
+ densify(options) {
563
+ return this.#withStage(new MongoDensifyStage(options));
564
+ }
565
+ fill(options) {
566
+ return this.#withStage(new MongoFillStage(options));
567
+ }
568
+ search(config, index) {
569
+ return this.#withStage(new MongoSearchStage(config, index));
570
+ }
571
+ searchMeta(config, index) {
572
+ return this.#withStage(new MongoSearchMetaStage(config, index));
573
+ }
574
+ vectorSearch(options) {
575
+ return this.#withStage(new MongoVectorSearchStage(options));
576
+ }
577
+ pipe(stage) {
578
+ return this.#withStage(stage);
579
+ }
580
+ /**
581
+ * No-arg `updateMany()`: deconstruct the chain into leading `$match`
582
+ * stages (folded into the filter) and remaining stages (which must all
583
+ * be valid pipeline-update stages). Available only when `U = 'update-ok'`.
584
+ *
585
+ * The optional callback parameter exists for subclass-override
586
+ * compatibility with `FilteredCollection.updateMany(updaterFn)` — TS's
587
+ * strict override check requires the parent's parameter to accept at
588
+ * least what the child's signature does. A runtime guard throws if a
589
+ * callback is actually passed on a bare `PipelineChain`. Note that
590
+ * because nothing in the public surface transitions `U` from
591
+ * `'update-cleared'` (the initial state on `CollectionHandle` /
592
+ * `FilteredCollection`) back to `'update-ok'`, the no-arg form is
593
+ * reachable only via explicit type casts in internal tests — the
594
+ * callback-form "type hole" is therefore not reachable from user
595
+ * code. See `docs/architecture docs/adrs/ADR 201 - State-machine
596
+ * pattern for typed DSL builders.md` for the marker-transition table.
597
+ */
598
+ updateMany(updaterFn) {
599
+ if (updaterFn !== void 0) throw ormError("ORM.ARGUMENT_INVALID", "updateMany() on a PipelineChain expects no arguments — the chain itself is the update pipeline. To update with an operator callback, call .updateMany(fn) on a FilteredCollection (i.e. after .match()).");
600
+ const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);
601
+ const command = new UpdateManyCommand(this.#state.collection, filter, updatePipeline);
602
+ return {
603
+ collection: this.#state.collection,
604
+ command,
605
+ meta: this.#writeMeta()
606
+ };
607
+ }
608
+ /**
609
+ * No-arg `updateOne()`: same as `updateMany()` but maps to a single-doc
610
+ * update. Carries the same optional-callback/subclass-compat caveat
611
+ * documented above — the callback form is reachable only via forced
612
+ * casts in internal tests.
613
+ */
614
+ updateOne(updaterFn) {
615
+ if (updaterFn !== void 0) throw ormError("ORM.ARGUMENT_INVALID", "updateOne() on a PipelineChain expects no arguments — the chain itself is the update pipeline. To update with an operator callback, call .updateOne(fn) on a FilteredCollection (i.e. after .match()).");
616
+ const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);
617
+ const command = new UpdateOneCommand(this.#state.collection, filter, updatePipeline);
618
+ return {
619
+ collection: this.#state.collection,
620
+ command,
621
+ meta: this.#writeMeta()
622
+ };
623
+ }
624
+ /**
625
+ * Find a single document matching the accumulated pipeline (which must
626
+ * consist solely of leading `$match` stages followed by at most one
627
+ * `$sort`) and apply `updaterFn`. Available only when
628
+ * `FindAndModifyEnabled` is `'fam-ok'` — stages that clear the marker
629
+ * (including `$skip`, which MongoDB's `findAndModify` has no slot for)
630
+ * make this method invisible at the type level.
631
+ *
632
+ * The pipeline stages are deconstructed into the wire command's `filter`
633
+ * and `sort` slots. If any non-deconstructable stage is present, a
634
+ * runtime error is thrown as a defensive check (the type system should
635
+ * prevent this).
636
+ */
637
+ findOneAndUpdate(updaterFn, opts = {}) {
638
+ const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);
639
+ const update = resolveUpdaterResult(updaterFn(createFieldAccessor()));
640
+ const command = new FindOneAndUpdateCommand(this.#state.collection, filter, update, opts.upsert ?? false, sort, opts.returnDocument ?? "after");
641
+ const meta = {
642
+ target: "mongo",
643
+ storageHash: this.#state.storageHash,
644
+ lane: "mongo-query"
645
+ };
646
+ return {
647
+ collection: this.#state.collection,
648
+ command,
649
+ meta
650
+ };
651
+ }
652
+ /**
653
+ * Find a single document matching the accumulated pipeline and delete it.
654
+ * Same marker gating and deconstruction as `findOneAndUpdate`.
655
+ */
656
+ findOneAndDelete() {
657
+ const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);
658
+ const command = new FindOneAndDeleteCommand(this.#state.collection, filter, sort);
659
+ const meta = {
660
+ target: "mongo",
661
+ storageHash: this.#state.storageHash,
662
+ lane: "mongo-query"
663
+ };
664
+ return {
665
+ collection: this.#state.collection,
666
+ command,
667
+ meta
668
+ };
669
+ }
670
+ /**
671
+ * Materialise the chain as a `MongoQueryPlan` wrapping an `AggregateCommand`.
672
+ */
673
+ build() {
674
+ const command = new AggregateCommand(this.#state.collection, this.#state.stages);
675
+ const meta = {
676
+ target: "mongo",
677
+ storageHash: this.#state.storageHash,
678
+ lane: "mongo-query"
679
+ };
680
+ const modelName = this.#state.modelName;
681
+ const contractNarrow = this.#contract;
682
+ let resultShape;
683
+ if (modelName !== void 0) {
684
+ const model = castAs(domainModelsAtDefaultNamespace(contractNarrow.domain)[modelName]);
685
+ resultShape = model ? computePipelineResultShape(this.#state.stages, contractModelToMongoResultShape(model)) : { kind: "unknown" };
686
+ }
687
+ return {
688
+ collection: this.#state.collection,
689
+ command,
690
+ meta,
691
+ ...ifDefined("resultShape", resultShape)
692
+ };
693
+ }
694
+ /**
695
+ * Alias for `build()` — surfaces the read intent at the call site.
696
+ */
697
+ aggregate() {
698
+ return this.build();
699
+ }
700
+ };
701
+ /**
702
+ * Walk the accumulated pipeline stages and extract the `filter` and `sort`
703
+ * slots for a `findOneAndUpdate` / `findOneAndDelete` wire command.
704
+ *
705
+ * The helper accepts exactly the canonical shape `match+ -> sort?` and
706
+ * nothing else:
707
+ *
708
+ * - one or more `$match` stages (AND-folded into a single filter),
709
+ * - optionally followed by a single `$sort` stage.
710
+ *
711
+ * Anything else — a `$sort` before `$match`, multiple `$sort` stages, a
712
+ * `$skip` stage, or any non-`$match`/`$sort` stage — is rejected with a
713
+ * clear error. The type system already prevents most of these at compile
714
+ * time via the `FindAndModifyEnabled` marker, but the runtime check
715
+ * guards the escape hatches (e.g. `.pipe(...)`) and future marker gaps.
716
+ *
717
+ * `$skip` is rejected outright because MongoDB's `findAndModify` command
718
+ * has no skip slot; a silently-dropped skip is a latent correctness bug
719
+ * waiting to happen. (A02 removed skip from the typed AST for the same
720
+ * reason.)
721
+ */
722
+ function deconstructFindAndModifyChain(stages) {
723
+ const matchFilters = [];
724
+ let sort;
725
+ let seenNonMatch = false;
726
+ for (const stage of stages) if (stage instanceof MongoMatchStage) {
727
+ if (seenNonMatch) throw ormError("ORM.ARGUMENT_INVALID", "findOneAndUpdate/findOneAndDelete requires the canonical $match+ -> $sort? shape, but a $match stage was found after a $sort. Re-order the chain so every .match() call precedes the .sort() call.");
728
+ matchFilters.push(stage.filter);
729
+ } else if (stage instanceof MongoSortStage) {
730
+ if (sort !== void 0) throw ormError("ORM.ARGUMENT_INVALID", "findOneAndUpdate/findOneAndDelete accepts at most one $sort stage; drop the extra .sort() call or combine the keys into a single sort spec.");
731
+ sort = { ...stage.sort };
732
+ seenNonMatch = true;
733
+ } else if (stage instanceof MongoSkipStage) throw ormError("ORM.OPERATION_UNSUPPORTED", "findOneAndUpdate/findOneAndDelete does not support .skip() — MongoDB findAndModify has no skip slot. Remove the .skip() call, or use .aggregate()/.build() if the chain needs skip semantics.");
734
+ else throw ormError("ORM.ARGUMENT_INVALID", `findOneAndUpdate/findOneAndDelete requires the canonical \$match+ -> \$sort? shape, but encountered a '${stage.constructor.name}' stage. This is likely a bug — the type system should have prevented this chain.`);
735
+ if (matchFilters.length === 0) throw ormError("ORM.ARGUMENT_INVALID", "findOneAndUpdate/findOneAndDelete requires at least one .match() call.");
736
+ const first = matchFilters[0];
737
+ if (first === void 0) throw new InternalError("Unreachable: matchFilters.length > 0 but first is undefined");
738
+ return {
739
+ filter: matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters),
740
+ sort
741
+ };
742
+ }
743
+ /**
744
+ * Walk the accumulated pipeline stages: leading `$match` stages become the
745
+ * filter, remaining stages must all be valid `MongoUpdatePipelineStage`
746
+ * members (currently `$addFields`, `$project`, `$replaceRoot`).
747
+ */
748
+ function deconstructUpdateChain(stages) {
749
+ const matchFilters = [];
750
+ let boundary = 0;
751
+ for (const stage of stages) {
752
+ if (!(stage instanceof MongoMatchStage)) break;
753
+ matchFilters.push(stage.filter);
754
+ boundary++;
755
+ }
756
+ if (matchFilters.length === 0) throw ormError("ORM.ARGUMENT_INVALID", "No-arg updateMany/updateOne requires at least one .match() call.");
757
+ const remaining = stages.slice(boundary);
758
+ if (remaining.length === 0) throw ormError("ORM.ARGUMENT_INVALID", "No-arg updateMany/updateOne requires at least one pipeline-update stage (e.g. .addFields(), .project(), .replaceRoot()) after the .match() stages.");
759
+ const updatePipeline = [];
760
+ for (const stage of remaining) if (stage instanceof MongoAddFieldsStage || stage instanceof MongoProjectStage || stage instanceof MongoReplaceRootStage) updatePipeline.push(stage);
761
+ else throw ormError("ORM.ARGUMENT_INVALID", `No-arg updateMany/updateOne: encountered non-update stage '${stage.constructor.name}' after the leading \$match stages. Only \$addFields/\$set, \$project/\$unset, and \$replaceRoot/\$replaceWith stages are valid in an update pipeline.`);
762
+ const first = matchFilters[0];
763
+ if (first === void 0) throw new InternalError("Unreachable: matchFilters.length > 0 but first is undefined");
764
+ return {
765
+ filter: matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters),
766
+ updatePipeline
767
+ };
768
+ }
769
+ function numericExpr(op, args) {
770
+ return {
771
+ _field: {
772
+ codecId: "mongo/double@1",
773
+ nullable: false
774
+ },
775
+ node: MongoAggOperator.of(op, args.map((a) => a.node))
776
+ };
777
+ }
778
+ function numericUnaryExpr(op, arg) {
779
+ return {
780
+ _field: {
781
+ codecId: "mongo/double@1",
782
+ nullable: false
783
+ },
784
+ node: MongoAggOperator.of(op, arg.node)
785
+ };
786
+ }
787
+ function stringExpr(op, args) {
788
+ return {
789
+ _field: {
790
+ codecId: "mongo/string@1",
791
+ nullable: false
792
+ },
793
+ node: MongoAggOperator.of(op, args.map((a) => a.node))
794
+ };
795
+ }
796
+ function stringUnaryExpr(op, arg) {
797
+ return {
798
+ _field: {
799
+ codecId: "mongo/string@1",
800
+ nullable: false
801
+ },
802
+ node: MongoAggOperator.of(op, arg.node)
803
+ };
804
+ }
805
+ function booleanExpr(op, args) {
806
+ return {
807
+ _field: {
808
+ codecId: "mongo/bool@1",
809
+ nullable: false
810
+ },
811
+ node: MongoAggOperator.of(op, args.map((a) => a.node))
812
+ };
813
+ }
814
+ function booleanUnaryExpr(op, arg) {
815
+ return {
816
+ _field: {
817
+ codecId: "mongo/bool@1",
818
+ nullable: false
819
+ },
820
+ node: MongoAggOperator.of(op, arg.node)
821
+ };
822
+ }
823
+ function dateUnaryExpr(op, arg) {
824
+ return {
825
+ _field: {
826
+ codecId: "mongo/date@1",
827
+ nullable: false
828
+ },
829
+ node: MongoAggOperator.of(op, arg.node)
830
+ };
831
+ }
832
+ function arrayExpr(op, args) {
833
+ return {
834
+ _field: {
835
+ codecId: "mongo/array@1",
836
+ nullable: false
837
+ },
838
+ node: MongoAggOperator.of(op, args.map((a) => a.node))
839
+ };
840
+ }
841
+ function arrayUnaryExpr(op, arg) {
842
+ return {
843
+ _field: {
844
+ codecId: "mongo/array@1",
845
+ nullable: false
846
+ },
847
+ node: MongoAggOperator.of(op, arg.node)
848
+ };
849
+ }
850
+ function docUnaryExpr(op, arg) {
851
+ return {
852
+ _field: {
853
+ codecId: arg._field.codecId,
854
+ nullable: false
855
+ },
856
+ node: MongoAggOperator.of(op, arg.node)
857
+ };
858
+ }
859
+ function namedArgsExpr(op, args, _field) {
860
+ const nodeArgs = {};
861
+ for (const [key, val] of Object.entries(args)) if (val !== void 0) nodeArgs[key] = val.node;
862
+ return {
863
+ _field,
864
+ node: MongoAggOperator.of(op, nodeArgs)
865
+ };
866
+ }
867
+ const NUMERIC = {
868
+ codecId: "mongo/double@1",
869
+ nullable: false
870
+ };
871
+ const STRING = {
872
+ codecId: "mongo/string@1",
873
+ nullable: false
874
+ };
875
+ const BOOLEAN = {
876
+ codecId: "mongo/bool@1",
877
+ nullable: false
878
+ };
879
+ const DATE = {
880
+ codecId: "mongo/date@1",
881
+ nullable: false
882
+ };
883
+ const ARRAY = {
884
+ codecId: "mongo/array@1",
885
+ nullable: false
886
+ };
887
+ const DOC = {
888
+ codecId: "mongo/document@1",
889
+ nullable: false
890
+ };
891
+ function literal(value) {
892
+ return {
893
+ _field: void 0,
894
+ node: MongoAggLiteral.of(value)
895
+ };
896
+ }
897
+ const fn = {
898
+ add(...args) {
899
+ return numericExpr("$add", args);
900
+ },
901
+ subtract(a, b) {
902
+ return numericExpr("$subtract", [a, b]);
903
+ },
904
+ multiply(...args) {
905
+ return numericExpr("$multiply", args);
906
+ },
907
+ divide(a, b) {
908
+ return numericExpr("$divide", [a, b]);
909
+ },
910
+ concat(...args) {
911
+ return stringExpr("$concat", args);
912
+ },
913
+ toLower(a) {
914
+ return stringUnaryExpr("$toLower", a);
915
+ },
916
+ toUpper(a) {
917
+ return stringUnaryExpr("$toUpper", a);
918
+ },
919
+ size(a) {
920
+ return numericUnaryExpr("$size", a);
921
+ },
922
+ cond(condition, thenExpr, elseExpr) {
923
+ return {
924
+ _field: thenExpr._field,
925
+ node: new MongoAggCond(condition, thenExpr.node, elseExpr.node)
926
+ };
927
+ },
928
+ literal,
929
+ year(a) {
930
+ return numericUnaryExpr("$year", a);
931
+ },
932
+ month(a) {
933
+ return numericUnaryExpr("$month", a);
934
+ },
935
+ dayOfMonth(a) {
936
+ return numericUnaryExpr("$dayOfMonth", a);
937
+ },
938
+ hour(a) {
939
+ return numericUnaryExpr("$hour", a);
940
+ },
941
+ minute(a) {
942
+ return numericUnaryExpr("$minute", a);
943
+ },
944
+ second(a) {
945
+ return numericUnaryExpr("$second", a);
946
+ },
947
+ millisecond(a) {
948
+ return numericUnaryExpr("$millisecond", a);
949
+ },
950
+ dateToString(args) {
951
+ return namedArgsExpr("$dateToString", args, STRING);
952
+ },
953
+ dateFromString(args) {
954
+ return namedArgsExpr("$dateFromString", args, DATE);
955
+ },
956
+ dateDiff(args) {
957
+ return namedArgsExpr("$dateDiff", args, NUMERIC);
958
+ },
959
+ dateAdd(args) {
960
+ return namedArgsExpr("$dateAdd", args, DATE);
961
+ },
962
+ dateSubtract(args) {
963
+ return namedArgsExpr("$dateSubtract", args, DATE);
964
+ },
965
+ dateTrunc(args) {
966
+ return namedArgsExpr("$dateTrunc", args, DATE);
967
+ },
968
+ substr(str, start, length) {
969
+ return stringExpr("$substr", [
970
+ str,
971
+ start,
972
+ length
973
+ ]);
974
+ },
975
+ substrBytes(str, start, count) {
976
+ return stringExpr("$substrBytes", [
977
+ str,
978
+ start,
979
+ count
980
+ ]);
981
+ },
982
+ trim(args) {
983
+ return namedArgsExpr("$trim", args, STRING);
984
+ },
985
+ ltrim(args) {
986
+ return namedArgsExpr("$ltrim", args, STRING);
987
+ },
988
+ rtrim(args) {
989
+ return namedArgsExpr("$rtrim", args, STRING);
990
+ },
991
+ split(str, delimiter) {
992
+ return arrayExpr("$split", [str, delimiter]);
993
+ },
994
+ strLenCP(a) {
995
+ return numericUnaryExpr("$strLenCP", a);
996
+ },
997
+ strLenBytes(a) {
998
+ return numericUnaryExpr("$strLenBytes", a);
999
+ },
1000
+ regexMatch(args) {
1001
+ return namedArgsExpr("$regexMatch", args, BOOLEAN);
1002
+ },
1003
+ regexFind(args) {
1004
+ return namedArgsExpr("$regexFind", args, DOC);
1005
+ },
1006
+ regexFindAll(args) {
1007
+ return namedArgsExpr("$regexFindAll", args, ARRAY);
1008
+ },
1009
+ replaceOne(args) {
1010
+ return namedArgsExpr("$replaceOne", args, STRING);
1011
+ },
1012
+ replaceAll(args) {
1013
+ return namedArgsExpr("$replaceAll", args, STRING);
1014
+ },
1015
+ cmp(a, b) {
1016
+ return numericExpr("$cmp", [a, b]);
1017
+ },
1018
+ eq(a, b) {
1019
+ return booleanExpr("$eq", [a, b]);
1020
+ },
1021
+ ne(a, b) {
1022
+ return booleanExpr("$ne", [a, b]);
1023
+ },
1024
+ gt(a, b) {
1025
+ return booleanExpr("$gt", [a, b]);
1026
+ },
1027
+ gte(a, b) {
1028
+ return booleanExpr("$gte", [a, b]);
1029
+ },
1030
+ lt(a, b) {
1031
+ return booleanExpr("$lt", [a, b]);
1032
+ },
1033
+ lte(a, b) {
1034
+ return booleanExpr("$lte", [a, b]);
1035
+ },
1036
+ arrayElemAt(arr, idx) {
1037
+ return {
1038
+ _field: {
1039
+ codecId: DOC.codecId,
1040
+ nullable: true
1041
+ },
1042
+ node: MongoAggOperator.of("$arrayElemAt", [arr.node, idx.node])
1043
+ };
1044
+ },
1045
+ concatArrays(...args) {
1046
+ return arrayExpr("$concatArrays", args);
1047
+ },
1048
+ firstElem(a) {
1049
+ return {
1050
+ _field: {
1051
+ codecId: DOC.codecId,
1052
+ nullable: true
1053
+ },
1054
+ node: MongoAggOperator.of("$first", a.node)
1055
+ };
1056
+ },
1057
+ lastElem(a) {
1058
+ return {
1059
+ _field: {
1060
+ codecId: DOC.codecId,
1061
+ nullable: true
1062
+ },
1063
+ node: MongoAggOperator.of("$last", a.node)
1064
+ };
1065
+ },
1066
+ isIn(elem, arr) {
1067
+ return booleanExpr("$in", [elem, arr]);
1068
+ },
1069
+ indexOfArray(arr, value, ...rest) {
1070
+ return numericExpr("$indexOfArray", [
1071
+ arr,
1072
+ value,
1073
+ ...rest
1074
+ ]);
1075
+ },
1076
+ isArray(a) {
1077
+ return booleanUnaryExpr("$isArray", a);
1078
+ },
1079
+ reverseArray(a) {
1080
+ return arrayUnaryExpr("$reverseArray", a);
1081
+ },
1082
+ slice(arr, ...rest) {
1083
+ return arrayExpr("$slice", [arr, ...rest]);
1084
+ },
1085
+ zip(args) {
1086
+ const nodeArgs = { inputs: args.inputs.map((a) => a.node) };
1087
+ if (args.useLongestLength) nodeArgs["useLongestLength"] = args.useLongestLength.node;
1088
+ if (args.defaults) nodeArgs["defaults"] = args.defaults.node;
1089
+ return {
1090
+ _field: ARRAY,
1091
+ node: MongoAggOperator.of("$zip", nodeArgs)
1092
+ };
1093
+ },
1094
+ range(start, end, step) {
1095
+ return arrayExpr("$range", [
1096
+ start,
1097
+ end,
1098
+ step
1099
+ ]);
1100
+ },
1101
+ setUnion(...args) {
1102
+ return arrayExpr("$setUnion", args);
1103
+ },
1104
+ setIntersection(...args) {
1105
+ return arrayExpr("$setIntersection", args);
1106
+ },
1107
+ setDifference(a, b) {
1108
+ return arrayExpr("$setDifference", [a, b]);
1109
+ },
1110
+ setEquals(...args) {
1111
+ return booleanExpr("$setEquals", args);
1112
+ },
1113
+ setIsSubset(a, b) {
1114
+ return booleanExpr("$setIsSubset", [a, b]);
1115
+ },
1116
+ anyElementTrue(a) {
1117
+ return booleanUnaryExpr("$anyElementTrue", a);
1118
+ },
1119
+ allElementsTrue(a) {
1120
+ return booleanUnaryExpr("$allElementsTrue", a);
1121
+ },
1122
+ typeOf(a) {
1123
+ return stringUnaryExpr("$type", a);
1124
+ },
1125
+ convert(args) {
1126
+ return namedArgsExpr("$convert", args, DOC);
1127
+ },
1128
+ toInt(a) {
1129
+ return numericUnaryExpr("$toInt", a);
1130
+ },
1131
+ toLong(a) {
1132
+ return numericUnaryExpr("$toLong", a);
1133
+ },
1134
+ toDouble(a) {
1135
+ return numericUnaryExpr("$toDouble", a);
1136
+ },
1137
+ toDecimal(a) {
1138
+ return numericUnaryExpr("$toDecimal", a);
1139
+ },
1140
+ toString_(a) {
1141
+ return stringUnaryExpr("$toString", a);
1142
+ },
1143
+ toObjectId(a) {
1144
+ return docUnaryExpr("$toObjectId", a);
1145
+ },
1146
+ toBool(a) {
1147
+ return booleanUnaryExpr("$toBool", a);
1148
+ },
1149
+ toDate(a) {
1150
+ return dateUnaryExpr("$toDate", a);
1151
+ },
1152
+ objectToArray(a) {
1153
+ return arrayUnaryExpr("$objectToArray", a);
1154
+ },
1155
+ arrayToObject(a) {
1156
+ return {
1157
+ _field: DOC,
1158
+ node: MongoAggOperator.of("$arrayToObject", a.node)
1159
+ };
1160
+ },
1161
+ getField(args) {
1162
+ return namedArgsExpr("$getField", args, DOC);
1163
+ },
1164
+ setField(args) {
1165
+ return namedArgsExpr("$setField", args, DOC);
1166
+ }
1167
+ };
1168
+ function contractError(code, message, options) {
1169
+ return structuredError(code, message, options);
1170
+ }
1171
+ /**
1172
+ * "Match-all" filter used by the unqualified-write terminals
1173
+ * (`updateAll`/`deleteAll`). The canonical representation is still
1174
+ * undecided — `MongoAndExpr` with an empty conjunction and a dedicated
1175
+ * `MongoMatchAllExpr` node are both candidates. For now we use
1176
+ * `_id $exists: true`, which is trivially true on every document and
1177
+ * avoids introducing a new AST node before the wider question is
1178
+ * resolved. Centralised so the eventual switch is a one-line change.
1179
+ */
1180
+ function matchAllFilter() {
1181
+ return MongoExistsExpr.exists("_id");
1182
+ }
1183
+ /**
1184
+ * Resolve an updater callback into a `MongoUpdateSpec` (either the folded
1185
+ * operator object or a pipeline-stage array). Centralised so all write
1186
+ * terminals share the same fold / dispatch semantics.
1187
+ */
1188
+ function resolveUpdaterCallback(updaterFn) {
1189
+ return resolveUpdaterResult(updaterFn(createFieldAccessor()));
1190
+ }
1191
+ /**
1192
+ * Build the `PlanMeta` envelope shared by every write terminal in this
1193
+ * package. Lane is `mongo-query` (single lane for all query-builder terminals)
1194
+ * so middleware can dispatch on intent without inspecting the command.
1195
+ */
1196
+ function writeMeta(storageHash) {
1197
+ return {
1198
+ target: "mongo",
1199
+ storageHash,
1200
+ lane: "mongo-query"
1201
+ };
1202
+ }
1203
+ /**
1204
+ * Root state of the query-builder state machine. Returned from
1205
+ * `mongoQuery(...).from(name)` and bound to a single collection.
1206
+ *
1207
+ * Inherits the entire pipeline-stage surface from `PipelineChain` (since an
1208
+ * empty `CollectionHandle` is observably an empty pipeline). Adds:
1209
+ *
1210
+ * - `match(...)` — overridden to transition to `FilteredCollection`, which
1211
+ * accumulates filters for eventual splatting into write/find-and-modify
1212
+ * wire commands.
1213
+ * - **Insert / unqualified-write methods** (M2): `insertOne`, `insertMany`,
1214
+ * `updateAll`, `deleteAll`. These live *only* here — the corresponding
1215
+ * methods are absent from `FilteredCollection`, so a caller cannot
1216
+ * accidentally produce an unqualified write by forgetting to `.match(...)`
1217
+ * later in the chain. Bodies land in M2.
1218
+ */
1219
+ var CollectionHandle = class extends PipelineChain {
1220
+ #ctx;
1221
+ #modelName;
1222
+ constructor(ctx, modelName) {
1223
+ super(ctx.contract, {
1224
+ collection: ctx.collection,
1225
+ stages: [],
1226
+ storageHash: ctx.storageHash,
1227
+ modelName
1228
+ });
1229
+ this.#ctx = ctx;
1230
+ this.#modelName = modelName;
1231
+ }
1232
+ /**
1233
+ * Bound model name. Exposed so type tests can assert the binding without
1234
+ * flipping into a pipeline. Not part of the public-API contract.
1235
+ */
1236
+ get _modelName() {
1237
+ return this.#modelName;
1238
+ }
1239
+ match(filterOrFn) {
1240
+ const resolved = typeof filterOrFn === "function" ? filterOrFn(createFieldAccessor()) : filterOrFn;
1241
+ return new FilteredCollection(this.#ctx, this.#modelName, [resolved]);
1242
+ }
1243
+ /**
1244
+ * Insert a single document. Document fields are passed straight through to
1245
+ * the wire `InsertOneCommand` — codec normalisation happens at the
1246
+ * adapter/driver boundary, identically to the SQL builder (see Open Item
1247
+ * #14 confirmation in the design conversation).
1248
+ *
1249
+ * Returns a `MongoQueryPlan<InsertOneResult>` whose row stream yields a
1250
+ * single result document with the server-assigned `insertedId`.
1251
+ */
1252
+ insertOne(document) {
1253
+ const command = new InsertOneCommand(this.#ctx.collection, document);
1254
+ return {
1255
+ collection: this.#ctx.collection,
1256
+ command,
1257
+ meta: writeMeta(this.#ctx.storageHash)
1258
+ };
1259
+ }
1260
+ /**
1261
+ * Insert a batch of documents. Order is preserved in the returned
1262
+ * `insertedIds` array.
1263
+ */
1264
+ insertMany(documents) {
1265
+ if (documents.length === 0) throw ormError("ORM.MUTATION_DATA_MISSING", "insertMany() requires at least one document.");
1266
+ const command = new InsertManyCommand(this.#ctx.collection, documents);
1267
+ return {
1268
+ collection: this.#ctx.collection,
1269
+ command,
1270
+ meta: writeMeta(this.#ctx.storageHash)
1271
+ };
1272
+ }
1273
+ /**
1274
+ * Update *every* document in the collection. Lives only on
1275
+ * `CollectionHandle` — the corresponding method is intentionally absent
1276
+ * from `FilteredCollection` so a caller cannot accidentally produce an
1277
+ * unqualified write by forgetting to `.match(...)` first. Pair with
1278
+ * `.match(...).updateMany(...)` for the filtered case.
1279
+ */
1280
+ updateAll(updaterFn) {
1281
+ const update = resolveUpdaterCallback(updaterFn);
1282
+ const command = new UpdateManyCommand(this.#ctx.collection, matchAllFilter(), update);
1283
+ return {
1284
+ collection: this.#ctx.collection,
1285
+ command,
1286
+ meta: writeMeta(this.#ctx.storageHash)
1287
+ };
1288
+ }
1289
+ /**
1290
+ * Delete *every* document in the collection. See `updateAll` for the
1291
+ * rationale around the unqualified-write surface being limited to this
1292
+ * state class.
1293
+ */
1294
+ deleteAll() {
1295
+ const command = new DeleteManyCommand(this.#ctx.collection, matchAllFilter());
1296
+ return {
1297
+ collection: this.#ctx.collection,
1298
+ command,
1299
+ meta: writeMeta(this.#ctx.storageHash)
1300
+ };
1301
+ }
1302
+ /**
1303
+ * Insert-or-update the document matching `filterFn`. The filter is
1304
+ * mandatory (vs. `updateAll`'s tautological match) because an upsert
1305
+ * without a discriminating predicate would either match every existing
1306
+ * document or insert an indistinguishable new one.
1307
+ *
1308
+ * Maps to `UpdateOneCommand` with `upsert: true`. The driver inserts a
1309
+ * new document derived from the filter equality fields plus the update
1310
+ * spec when no match is found; otherwise updates the matched document.
1311
+ */
1312
+ upsertOne(filterFn, updaterFn) {
1313
+ const filter = filterFn(createFieldAccessor());
1314
+ const update = resolveUpdaterCallback(updaterFn);
1315
+ const command = new UpdateOneCommand(this.#ctx.collection, filter, update, true);
1316
+ return {
1317
+ collection: this.#ctx.collection,
1318
+ command,
1319
+ meta: writeMeta(this.#ctx.storageHash)
1320
+ };
1321
+ }
1322
+ };
1323
+ /**
1324
+ * State reached after one or more `.match(...)` calls on `CollectionHandle`.
1325
+ *
1326
+ * Inherits the pipeline-stage surface from `PipelineChain`, with the
1327
+ * accumulated filters baked in as a leading `$match` stage on the underlying
1328
+ * pipeline state. This means read-terminal output (`.aggregate()` /
1329
+ * `.build()`) and any subsequent pipeline-stage chain see the filtered
1330
+ * collection as input — the read story works through pure inheritance.
1331
+ *
1332
+ * Adds:
1333
+ *
1334
+ * - `match(...)` — pushes another `$match` stage *and* records the filter in
1335
+ * the accumulator, so the eventual write/find-and-modify terminal can
1336
+ * splat the AND-folded filter into the wire command's `filter` slot.
1337
+ * - **Filtered writes** (M2): `updateMany`, `updateOne`, `deleteMany`,
1338
+ * `deleteOne`, `upsertOne`. Stubbed in M1. (Upsert-many is an open
1339
+ * question in the spec — see TML-2267 — and is intentionally absent.)
1340
+ * - **Find-and-modify** (M3): `findOneAndUpdate`, `findOneAndDelete`.
1341
+ * Stubbed in M1.
1342
+ *
1343
+ * Notably *does not* expose `insertOne`/`insertMany`/`updateAll`/`deleteAll`
1344
+ * — those are insert or unqualified-write operations that are nonsense
1345
+ * after a filter has been applied.
1346
+ */
1347
+ var FilteredCollection = class FilteredCollection extends PipelineChain {
1348
+ #ctx;
1349
+ #modelName;
1350
+ #filters;
1351
+ constructor(ctx, modelName, filters) {
1352
+ if (filters.length === 0) throw new InternalError("FilteredCollection requires at least one accumulated filter");
1353
+ const first = filters[0];
1354
+ if (first === void 0) throw new InternalError("FilteredCollection: unreachable empty-filters branch");
1355
+ const leading = filters.length === 1 ? first : foldAnd(filters);
1356
+ super(ctx.contract, {
1357
+ collection: ctx.collection,
1358
+ stages: [new MongoMatchStage(leading)],
1359
+ storageHash: ctx.storageHash,
1360
+ modelName
1361
+ });
1362
+ this.#ctx = ctx;
1363
+ this.#modelName = modelName;
1364
+ this.#filters = filters;
1365
+ }
1366
+ get _modelName() {
1367
+ return this.#modelName;
1368
+ }
1369
+ /**
1370
+ * Accumulated filter list. Exposed for the M2/M3 write/find-and-modify
1371
+ * terminals to splat into wire-command `filter` slots; not part of the
1372
+ * public-API contract.
1373
+ */
1374
+ get _filters() {
1375
+ return this.#filters;
1376
+ }
1377
+ match(filterOrFn) {
1378
+ const resolved = typeof filterOrFn === "function" ? filterOrFn(createFieldAccessor()) : filterOrFn;
1379
+ return new FilteredCollection(this.#ctx, this.#modelName, [...this.#filters, resolved]);
1380
+ }
1381
+ /**
1382
+ * AND-fold the accumulated filters into a single `MongoFilterExpr` for
1383
+ * splatting into a write/find-and-modify wire command's `filter` slot.
1384
+ * Length-1 short-circuits to avoid a redundant `$and` wrapper.
1385
+ */
1386
+ #foldedFilter() {
1387
+ const first = this.#filters[0];
1388
+ if (first === void 0) throw new InternalError("FilteredCollection: invariant violated — empty filter accumulator");
1389
+ return this.#filters.length === 1 ? first : foldAnd(this.#filters);
1390
+ }
1391
+ /**
1392
+ * Update every matching document. `updaterFn` receives a `FieldAccessor`
1393
+ * and returns an array of `TypedUpdateOp` (e.g. `[f.amount.inc(1),
1394
+ * f.status.set('done')]`). Operators are folded into the wire-format
1395
+ * update spec by `foldUpdateOps`, which throws on operator+path
1396
+ * collisions.
1397
+ */
1398
+ updateMany(updaterFn) {
1399
+ const update = resolveUpdaterCallback(updaterFn);
1400
+ const command = new UpdateManyCommand(this.#ctx.collection, this.#foldedFilter(), update);
1401
+ return {
1402
+ collection: this.#ctx.collection,
1403
+ command,
1404
+ meta: writeMeta(this.#ctx.storageHash)
1405
+ };
1406
+ }
1407
+ /**
1408
+ * Update at most one matching document. The driver picks the document
1409
+ * (typically the first one matched by the underlying scan); no ordering
1410
+ * guarantee is implied — chain `.sort(...)` and use the M3
1411
+ * `.findOneAndUpdate(...)` terminal when ordering matters.
1412
+ */
1413
+ updateOne(updaterFn) {
1414
+ const update = resolveUpdaterCallback(updaterFn);
1415
+ const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update);
1416
+ return {
1417
+ collection: this.#ctx.collection,
1418
+ command,
1419
+ meta: writeMeta(this.#ctx.storageHash)
1420
+ };
1421
+ }
1422
+ /**
1423
+ * Delete every matching document.
1424
+ */
1425
+ deleteMany() {
1426
+ const command = new DeleteManyCommand(this.#ctx.collection, this.#foldedFilter());
1427
+ return {
1428
+ collection: this.#ctx.collection,
1429
+ command,
1430
+ meta: writeMeta(this.#ctx.storageHash)
1431
+ };
1432
+ }
1433
+ /**
1434
+ * Delete at most one matching document. See the `updateOne` note about
1435
+ * driver-chosen victim selection.
1436
+ */
1437
+ deleteOne() {
1438
+ const command = new DeleteOneCommand(this.#ctx.collection, this.#foldedFilter());
1439
+ return {
1440
+ collection: this.#ctx.collection,
1441
+ command,
1442
+ meta: writeMeta(this.#ctx.storageHash)
1443
+ };
1444
+ }
1445
+ /**
1446
+ * Insert-or-update against the accumulated filter. Maps to
1447
+ * `UpdateOneCommand` with `upsert: true`. Equivalent to
1448
+ * `CollectionHandle.upsertOne(f => filter, updaterFn)` but reuses the
1449
+ * already-accumulated `.match(...)` filter chain.
1450
+ */
1451
+ upsertOne(updaterFn) {
1452
+ const update = resolveUpdaterCallback(updaterFn);
1453
+ const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update, true);
1454
+ return {
1455
+ collection: this.#ctx.collection,
1456
+ command,
1457
+ meta: writeMeta(this.#ctx.storageHash)
1458
+ };
1459
+ }
1460
+ /**
1461
+ * Find a single matching document and apply `updaterFn` to it.
1462
+ *
1463
+ * `opts.upsert` (default `false`) toggles insert-on-miss behaviour.
1464
+ * `opts.returnDocument` (default `'after'`) controls whether the row
1465
+ * stream yields the document as it was before or after the update.
1466
+ */
1467
+ findOneAndUpdate(updaterFn, opts = {}) {
1468
+ const update = resolveUpdaterCallback(updaterFn);
1469
+ const command = new FindOneAndUpdateCommand(this.#ctx.collection, this.#foldedFilter(), update, opts.upsert ?? false, void 0, opts.returnDocument ?? "after");
1470
+ return {
1471
+ collection: this.#ctx.collection,
1472
+ command,
1473
+ meta: writeMeta(this.#ctx.storageHash)
1474
+ };
1475
+ }
1476
+ /**
1477
+ * Find a single matching document and delete it. Returns the deleted
1478
+ * document via the row stream.
1479
+ */
1480
+ findOneAndDelete() {
1481
+ const command = new FindOneAndDeleteCommand(this.#ctx.collection, this.#foldedFilter());
1482
+ return {
1483
+ collection: this.#ctx.collection,
1484
+ command,
1485
+ meta: writeMeta(this.#ctx.storageHash)
1486
+ };
1487
+ }
1488
+ };
1489
+ function foldAnd(filters) {
1490
+ return MongoAndExpr.of(filters);
1491
+ }
1492
+ /**
1493
+ * Narrow a `MongoContractWithTypeMaps`-shaped value down to its underlying
1494
+ * `MongoContract` view. `MongoContractWithTypeMaps<C, ...>` is defined as
1495
+ * `C & { readonly [phantom]?: TTypeMaps }`, so every contract we accept is
1496
+ * structurally a `MongoContract` — the phantom is type-only. This helper
1497
+ * centralises that narrowing so callers don't reach for `as unknown as
1498
+ * MongoContract` double-casts.
1499
+ */
1500
+ function asMongoContract(contract) {
1501
+ return contract;
1502
+ }
1503
+ /**
1504
+ * Construct a `CollectionHandle` from a validated contract + root name.
1505
+ * Used by `mongoQuery(...).from(name)` to enter the state machine.
1506
+ */
1507
+ function createCollectionHandle(contract, rootName) {
1508
+ const c = asMongoContract(contract);
1509
+ const modelName = c.roots[rootName]?.model;
1510
+ if (!modelName) throw ormError("ORM.MODEL_UNKNOWN", `Unknown root: "${rootName}". Valid roots: ${Object.keys(c.roots).join(", ")}`);
1511
+ const model = domainModelsAtDefaultNamespace(c.domain)[modelName];
1512
+ if (!model) throw contractError("CONTRACT.MODEL_UNKNOWN", `Unknown model: "${modelName}" referenced by root "${rootName}".`);
1513
+ const collectionName = model.storage.collection ?? rootName;
1514
+ if (!c.storage?.storageHash) throw contractError("CONTRACT.VALIDATION_FAILED", "Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().");
1515
+ return new CollectionHandle({
1516
+ contract,
1517
+ collection: collectionName,
1518
+ storageHash: String(c.storage.storageHash)
1519
+ }, modelName);
1520
+ }
1521
+ function mongoQuery(options) {
1522
+ const contract = blindCast(options.contractJson);
1523
+ return {
1524
+ from(rootName) {
1525
+ return createCollectionHandle(contract, rootName);
1526
+ },
1527
+ rawCommand(command) {
1528
+ const storageHash = asMongoContract(contract).storage?.storageHash;
1529
+ if (!storageHash) throw contractError("CONTRACT.VALIDATION_FAILED", "Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().");
1530
+ const meta = {
1531
+ target: "mongo",
1532
+ storageHash: String(storageHash),
1533
+ lane: "mongo-query"
1534
+ };
1535
+ return {
1536
+ collection: command.collection,
1537
+ command,
1538
+ meta
1539
+ };
1540
+ }
1541
+ };
1542
+ }
1543
+ //#endregion
1544
+ export { contractFieldToMongoFieldShape as a, mongoQuery as c, acc as i, FilteredCollection as n, contractModelToMongoResultShape as o, PipelineChain as r, fn as s, CollectionHandle as t };
1545
+
1546
+ //# sourceMappingURL=dist-Dyp05u64.mjs.map