@prisma-next/mongo-runtime 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { RuntimeAdapterDescriptor, RuntimeAdapterInstance, RuntimeDriverDescriptor, RuntimeDriverInstance, RuntimeExtensionDescriptor, RuntimeExtensionInstance, RuntimeTargetDescriptor, RuntimeTargetInstance, RuntimeTargetInstance as RuntimeTargetInstance$1 } from "@prisma-next/framework-components/execution";
2
2
  import { AfterExecuteResult, AsyncIterableResult, ExecutionPlan, ParamRefMutator, RuntimeExecuteOptions, RuntimeMiddleware, RuntimeMiddlewareContext } from "@prisma-next/framework-components/runtime";
3
3
  import { MongoCodec, MongoCodecRegistry } from "@prisma-next/mongo-codec";
4
+ import { MongoParamRef } from "@prisma-next/mongo-value";
4
5
  import { MongoQueryPlan, MongoResultShape } from "@prisma-next/mongo-query-ast/execution";
5
6
  import { AnyMongoWireCommand } from "@prisma-next/mongo-wire";
6
- import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
7
+ import { MongoAdapter, MongoDriver, MongoLoweredDraft } from "@prisma-next/mongo-lowering";
7
8
 
8
9
  //#region src/mongo-execution-plan.d.ts
9
10
  /**
@@ -11,8 +12,8 @@ import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
11
12
  * that a Mongo driver can run.
12
13
  *
13
14
  * The plan carries:
14
- * - `command` — the wire command (e.g. `InsertOneWireCommand`,
15
- * `AggregateWireCommand`) produced by `MongoAdapter.lower(plan)`
15
+ * - `command` — dual lifecycle (see field JSDoc): unresolved draft during
16
+ * `beforeExecute`, frozen wire command afterward
16
17
  * - `meta` — family-agnostic plan metadata (target, lane, hashes, ...)
17
18
  * - `_row` — phantom row type, propagated from the originating
18
19
  * `MongoQueryPlan`
@@ -27,6 +28,14 @@ import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
27
28
  * cannot depend on.
28
29
  */
29
30
  interface MongoExecutionPlan<Row = unknown> extends ExecutionPlan<Row> {
31
+ /**
32
+ * Lowered command payload. **Lifecycle:** during `beforeExecute` this slot
33
+ * holds the unresolved `MongoLoweredDraft` (plain object, `MongoParamRef`
34
+ * leaves intact). After `resolveParams` and in later middleware hooks
35
+ * (`afterExecute`, `onRow`, intercept-after-resolve) it is the frozen wire
36
+ * command (`InsertOneWireCommand`, `AggregateWireCommand`, …). Do not read
37
+ * `command` structurally in `beforeExecute` — use the `params` mutator.
38
+ */
30
39
  readonly command: AnyMongoWireCommand;
31
40
  readonly resultShape?: MongoResultShape;
32
41
  }
@@ -88,8 +97,116 @@ declare function createMongoExecutionContext<TTargetId extends string = 'mongo'>
88
97
  readonly stack: MongoExecutionStack<TTargetId>;
89
98
  }): MongoExecutionContext<TTargetId>;
90
99
  //#endregion
100
+ //#region src/param-ref-mutator.d.ts
101
+ /**
102
+ * Phantom brand on {@link MongoParamRefHandle} so handles produced by
103
+ * {@link MongoParamRefMutator.entries} are distinguishable at the type level
104
+ * from user-constructed `MongoParamRef` instances. There is no runtime token —
105
+ * the handle IS the underlying `MongoParamRef` instance, cast through the brand.
106
+ */
107
+ declare const mongoParamRefHandleBrand: unique symbol;
108
+ /**
109
+ * Opaque token identifying a single `MongoParamRef` in the draft tree.
110
+ * Produced by {@link MongoParamRefMutator.entries}; consumed by
111
+ * `replaceValue` / `replaceValues`. The `TCodecId` phantom parameter
112
+ * records the codec id so typed overloads can route replacement values
113
+ * through a `TCodecMap`.
114
+ */
115
+ interface MongoParamRefHandle<TCodecId extends string | undefined = string | undefined> {
116
+ readonly [mongoParamRefHandleBrand]: TCodecId;
117
+ }
118
+ /**
119
+ * One outbound `MongoParamRef` slot in the draft exposed to middleware.
120
+ * `value` is the current effective value (post any prior mutations);
121
+ * `codecId` is the codec id declared on the underlying `MongoParamRef`.
122
+ */
123
+ interface MongoParamRefEntry<TCodecId extends string | undefined = string | undefined> {
124
+ readonly ref: MongoParamRefHandle<TCodecId>;
125
+ readonly value: unknown;
126
+ readonly codecId: TCodecId;
127
+ }
128
+ /**
129
+ * Discriminated entry union over a codec map. For each `K` in `TCodecMap`,
130
+ * `entries()` may yield a `MongoParamRefEntry<K>`; refs with no codec id (or
131
+ * an unrecognised codec id) yield `MongoParamRefEntry<undefined>`. Pattern-
132
+ * matching on `entry.codecId` narrows `entry.ref` to `MongoParamRefHandle<K>`.
133
+ */
134
+ type MongoParamRefEntryUnion<TCodecMap extends Record<string, unknown>> = { [K in keyof TCodecMap & string]: MongoParamRefEntry<K> }[keyof TCodecMap & string] | MongoParamRefEntry<undefined>;
135
+ /**
136
+ * Mongo-family mutator threaded into `MongoMiddleware.beforeExecute` as
137
+ * `params`. Scope is `MongoParamRef.value` slots only — middleware cannot
138
+ * insert or remove refs, rewrite the filter shape, or modify the pipeline
139
+ * structure. The phantom `MongoParamRefHandle` brand and the typed
140
+ * `replaceValue` overload enforce this at compile time.
141
+ *
142
+ * `entries()` performs a flat walk over the `MongoLoweredDraft` tree via
143
+ * {@link flattenMongoParamRefs}, yielding every `MongoParamRef` leaf in
144
+ * document fields, array elements, filter predicates, update operators, and
145
+ * pipeline stages. The walk matches `resolveDraftSlot` in the Mongo adapter
146
+ * (plain-object and array slots only; `Date` and other non-plain objects are
147
+ * leaves in both paths).
148
+ *
149
+ * Allocation discipline: the working-overrides map is only allocated on the
150
+ * first `replaceValue` / `replaceValues` call. If no middleware mutates,
151
+ * `currentDraft()` returns the original draft by reference identity without
152
+ * allocating a new tree (the AC-MUT5 fast path).
153
+ */
154
+ interface MongoParamRefMutator<TCodecMap extends Record<string, unknown> = Record<string, unknown>> extends ParamRefMutator {
155
+ entries(): IterableIterator<MongoParamRefEntryUnion<TCodecMap>>;
156
+ replaceValue<TCodecId extends keyof TCodecMap & string>(ref: MongoParamRefHandle<TCodecId>, newValue: TCodecMap[TCodecId]): void;
157
+ replaceValue(ref: MongoParamRefHandle<undefined>, newValue: unknown): void;
158
+ replaceValues(updates: Iterable<{
159
+ readonly ref: MongoParamRefHandle<(keyof TCodecMap & string) | undefined>;
160
+ readonly newValue: unknown;
161
+ }>): void;
162
+ }
163
+ /**
164
+ * Internal-only view that exposes `currentDraft()` to the Mongo runtime.
165
+ * The runtime calls this after the `beforeExecute` chain; the result is the
166
+ * original draft by reference if nothing was mutated, otherwise a new tree
167
+ * with the mutations applied. `MongoMiddleware` consumers never see this
168
+ * shape; they receive the public `MongoParamRefMutator` view.
169
+ */
170
+ interface MongoParamRefMutatorInternal<TCodecMap extends Record<string, unknown> = Record<string, unknown>> extends MongoParamRefMutator<TCodecMap> {
171
+ currentDraft(): MongoLoweredDraft;
172
+ }
173
+ /**
174
+ * Flat walk over a `MongoLoweredDraft` yielding every `MongoParamRef` leaf
175
+ * regardless of nesting — object values, array elements, filter predicate
176
+ * values, update operator values, and pipeline stage values. Raw command
177
+ * variants carry no `MongoParamRef` nodes so they yield zero entries.
178
+ *
179
+ * **Walk parity:** slot traversal matches `resolveDraftSlot` / `resolveParams`
180
+ * — refs appear only in plain-object and array containers; `Date` and other
181
+ * non-plain objects are leaves (not descended into), so middleware sees every
182
+ * ref the resolve pass will encode.
183
+ */
184
+ declare function flattenMongoParamRefs(draft: MongoLoweredDraft): Generator<MongoParamRef>;
185
+ /**
186
+ * Build a {@link MongoParamRefMutatorInternal} for the given lowered draft.
187
+ *
188
+ * The mutator captures the draft by reference and uses `flattenMongoParamRefs`
189
+ * on demand to produce `entries()`. Replacements are stored in a lazily-
190
+ * allocated `Map`; the fast path (no replacements) preserves bit-for-bit
191
+ * reference identity to the original draft in `currentDraft()`.
192
+ */
193
+ declare function createMongoParamRefMutator<TCodecMap extends Record<string, unknown> = Record<string, unknown>>(draft: MongoLoweredDraft): MongoParamRefMutatorInternal<TCodecMap>;
194
+ //#endregion
91
195
  //#region src/mongo-middleware.d.ts
92
- interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
196
+ /**
197
+ * Per-execute middleware context for Mongo. See {@link MongoMiddleware} for
198
+ * plan/command lifecycle during `beforeExecute` vs later hooks.
199
+ */
200
+ interface MongoMiddlewareContext extends RuntimeMiddlewareContext {
201
+ /**
202
+ * Stable digest of `meta.storageHash` plus the **resolved** wire command.
203
+ * Valid only on post-resolution plans (typically `afterExecute` or intercept
204
+ * after `resolveParams`). Calling this from `beforeExecute` throws
205
+ * `RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND` because `plan.command`
206
+ * is still an unresolved draft at that point.
207
+ */
208
+ contentHash(exec: MongoExecutionPlan): Promise<string>;
209
+ }
93
210
  /**
94
211
  * Mongo-domain middleware. Extends the framework `RuntimeMiddleware`
95
212
  * parameterized over `MongoExecutionPlan` because `runWithMiddleware`
@@ -100,10 +217,21 @@ interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
100
217
  * telemetry) — which carry no `familyId` — remain assignable. When
101
218
  * present, it must be `'mongo'`; the runtime rejects mismatches at
102
219
  * construction time via `checkMiddlewareCompatibility`.
220
+ *
221
+ * **Pre-resolve `beforeExecute` contract:** `plan.command` holds the
222
+ * unresolved `MongoLoweredDraft`, not a wire command. Observe and mutate
223
+ * parameters via `params.entries()` / `replaceValue` / `replaceValues` only.
224
+ * Do not inspect `plan.command` structurally or call `ctx.contentHash` in
225
+ * this hook. After the chain, `resolveParams` produces the frozen wire
226
+ * command used in `afterExecute` and for `contentHash`.
103
227
  */
104
228
  interface MongoMiddleware extends RuntimeMiddleware<MongoExecutionPlan> {
105
229
  readonly familyId?: 'mongo';
106
- beforeExecute?(plan: MongoExecutionPlan, ctx: MongoMiddlewareContext, params?: ParamRefMutator): void | Promise<void>;
230
+ /**
231
+ * Runs after structural lower, before `resolveParams`. `plan.command` is the
232
+ * unresolved draft; use `params` for param-ref access, not `plan.command`.
233
+ */
234
+ beforeExecute?(plan: MongoExecutionPlan, ctx: MongoMiddlewareContext, params?: MongoParamRefMutator): void | Promise<void>;
107
235
  onRow?(row: Record<string, unknown>, plan: MongoExecutionPlan, ctx: MongoMiddlewareContext): Promise<void>;
108
236
  afterExecute?(plan: MongoExecutionPlan, result: AfterExecuteResult, ctx: MongoMiddlewareContext): Promise<void>;
109
237
  }
@@ -153,5 +281,5 @@ interface MongoRuntime {
153
281
  }
154
282
  declare function createMongoRuntime(options: MongoRuntimeOptions): MongoRuntime;
155
283
  //#endregion
156
- export { type MongoCodecLookup, type MongoExecutionContext, type MongoExecutionPlan, type MongoExecutionStack, type MongoMiddleware, type MongoMiddlewareContext, type MongoRuntime, type MongoRuntimeAdapterDescriptor, type MongoRuntimeAdapterInstance, type MongoRuntimeExtensionDescriptor, type MongoRuntimeExtensionInstance, type MongoRuntimeOptions, type MongoRuntimeTargetDescriptor, type MongoStaticContributions, type RuntimeTargetInstance, createMongoExecutionContext, createMongoExecutionStack, createMongoRuntime };
284
+ export { type MongoCodecLookup, type MongoExecutionContext, type MongoExecutionPlan, type MongoExecutionStack, type MongoMiddleware, type MongoMiddlewareContext, type MongoParamRefEntry, type MongoParamRefEntryUnion, type MongoParamRefHandle, type MongoParamRefMutator, type MongoParamRefMutatorInternal, type MongoRuntime, type MongoRuntimeAdapterDescriptor, type MongoRuntimeAdapterInstance, type MongoRuntimeExtensionDescriptor, type MongoRuntimeExtensionInstance, type MongoRuntimeOptions, type MongoRuntimeTargetDescriptor, type MongoStaticContributions, type RuntimeTargetInstance, createMongoExecutionContext, createMongoExecutionStack, createMongoParamRefMutator, createMongoRuntime, flattenMongoParamRefs };
157
285
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/mongo-execution-plan.ts","../src/mongo-execution-stack.ts","../src/mongo-middleware.ts","../src/mongo-runtime.ts"],"mappings":";;;;;;;;;;;;;AAwBA;;;;;;;;;;;;;;;UAAiB,kBAAA,wBAA0C,aAAA,CAAc,GAAA;EAAA,SAC9D,OAAA,EAAS,mBAAA;EAAA,SACT,WAAA,GAAc,gBAAA;AAAA;;;;;;;AAFzB;UCFiB,wBAAA;EAAA,SACN,MAAA,QAAc,kBAAA;AAAA;AAAA,UAGR,4BAAA,6DAES,uBAAA,UAA+B,SAAA,IAAa,uBAAA,UAElE,SAAA,WAEM,uBAAA,UAAiC,SAAA,EAAW,eAAA,GAClD,wBAAA;AAAA,UAEa,2BAAA,6CACP,sBAAA,UAAgC,SAAA,GACtC,YAAA;AAAA,UAEa,6BAAA,8DAEU,sBAAA,UAEvB,SAAA,IACE,2BAAA,CAA4B,SAAA,WACxB,wBAAA,UAAkC,SAAA,EAAW,gBAAA,GACnD,wBAAA;AAAA,UAEa,6BAAA,6CACP,wBAAA,UAAkC,SAAA;AAAA,UAE3B,+BAAA,6CACP,0BAAA,UAAoC,SAAA,EAAW,6BAAA,CAA8B,SAAA,IACnF,wBAAA;EACF,MAAA,IAAU,6BAAA,CAA8B,SAAA;AAAA;;;;UAMzB,mBAAA;EAAA,SACN,MAAA,EAAQ,4BAAA,CAA6B,SAAA;EAAA,SACrC,OAAA,EAAS,6BAAA,CAA8B,SAAA;EAAA,SACvC,MAAA,EACL,uBAAA,UAEE,SAAA,WAEA,qBAAA,UAA+B,SAAA;EAAA,SAG5B,cAAA,WAAyB,+BAAA,CAAgC,SAAA;AAAA;AAAA,iBAGpD,yBAAA,oCAAA,CAA8D,OAAA;EAAA,SACnE,MAAA,EAAQ,4BAAA,CAA6B,SAAA;EAAA,SACrC,OAAA,EAAS,6BAAA,CAA8B,SAAA;EAAA,SACvC,MAAA,GACL,uBAAA,UAEE,SAAA,WAEA,qBAAA,UAA+B,SAAA;EAAA,SAG5B,cAAA,YAA0B,+BAAA,CAAgC,SAAA;AAAA,IACjE,mBAAA,CAAoB,SAAA;;;;;;UAeP,gBAAA;EACf,GAAA,CAAI,EAAA,WAAa,UAAA;EACjB,GAAA,CAAI,EAAA;AAAA;;;;;;;;UAUW,qBAAA;EAAA,SACN,QAAA;EAAA,SACA,MAAA,EAAQ,gBAAA;EAAA,SACR,KAAA,EAAO,mBAAA,CAAoB,SAAA;AAAA;AAAA,iBAGtB,2BAAA,oCAAA,CAAgE,OAAA;EAAA,SACrE,QAAA;EAAA,SACA,KAAA,EAAO,mBAAA,CAAoB,SAAA;AAAA,IAClC,qBAAA,CAAsB,SAAA;;;UClHT,sBAAA,SAA+B,wBAAA;;;;;AFgBhD;;;;;;;UEHiB,eAAA,SAAwB,iBAAA,CAAkB,kBAAA;EAAA,SAChD,QAAA;EACT,aAAA,EACE,IAAA,EAAM,kBAAA,EACN,GAAA,EAAK,sBAAA,EACL,MAAA,GAAS,eAAA,UACD,OAAA;EACV,KAAA,EACE,GAAA,EAAK,MAAA,mBACL,IAAA,EAAM,kBAAA,EACN,GAAA,EAAK,sBAAA,GACJ,OAAA;EACH,YAAA,EACE,IAAA,EAAM,kBAAA,EACN,MAAA,EAAQ,kBAAA,EACR,GAAA,EAAK,sBAAA,GACJ,OAAA;AAAA;;;;;;AFbL;;;;;;;;UGQiB,mBAAA;EAAA,SACN,OAAA,EAAS,qBAAA;EAAA,SACT,MAAA,EAAQ,WAAA;EAAA,SACR,UAAA,YAAsB,eAAA;EAAA,SACtB,IAAA;AAAA;AAAA,UAGM,YAAA;EHbQ;;;;;;ACJzB;;;;;AAIA;;;;;;;;;;EEmCE,OAAA,MACE,IAAA,EAAM,cAAA,CAAe,GAAA,GACrB,OAAA,GAAU,qBAAA,GACT,mBAAA,CAAoB,GAAA;EACvB,KAAA,IAAS,OAAA;AAAA;AAAA,iBAsGK,kBAAA,CAAmB,OAAA,EAAS,mBAAA,GAAsB,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/mongo-execution-plan.ts","../src/mongo-execution-stack.ts","../src/param-ref-mutator.ts","../src/mongo-middleware.ts","../src/mongo-runtime.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,9 +1,11 @@
1
1
  import { createExecutionStack } from "@prisma-next/framework-components/execution";
2
2
  import { AsyncIterableResult, RuntimeCore, checkAborted, checkMiddlewareCompatibility, runBeforeExecuteChain, runWithMiddleware, runtimeError } from "@prisma-next/framework-components/runtime";
3
3
  import { newMongoCodecRegistry } from "@prisma-next/mongo-codec";
4
+ import { blindCast } from "@prisma-next/utils/casts";
4
5
  import { ifDefined } from "@prisma-next/utils/defined";
5
6
  import { canonicalStringify } from "@prisma-next/utils/canonical-stringify";
6
7
  import { hashContent } from "@prisma-next/utils/hash-content";
8
+ import { MongoParamRef } from "@prisma-next/mongo-value";
7
9
  //#region src/mongo-execution-stack.ts
8
10
  function createMongoExecutionStack(options) {
9
11
  return createExecutionStack({
@@ -140,6 +142,22 @@ async function decodeMongoRow(row, shape, registry, collection, ctx = {}) {
140
142
  }
141
143
  //#endregion
142
144
  //#region src/content-hash.ts
145
+ /** @internal */
146
+ const RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND = "RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND";
147
+ /**
148
+ * Resolved wire commands are frozen class instances (`InsertOneWireCommand`, …);
149
+ * pre-resolve `beforeExecute` plans hold a plain-object `MongoLoweredDraft` in the
150
+ * command slot. O(1) prototype check — no tree walk on the hot path.
151
+ */
152
+ function isResolvedMongoWireCommand(command) {
153
+ if (command === null || typeof command !== "object") return false;
154
+ const proto = Object.getPrototypeOf(command);
155
+ return proto !== null && proto !== Object.prototype;
156
+ }
157
+ function assertContentHashOnResolvedCommand(command) {
158
+ if (isResolvedMongoWireCommand(command)) return;
159
+ throw runtimeError(RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND, "contentHash and computeMongoContentHash are only valid on a resolved wire command (after param resolution, e.g. from afterExecute). During beforeExecute, plan.command holds an unresolved MongoLoweredDraft — use params.entries() and the param mutator instead of contentHash or structural reads of plan.command.", { phase: "beforeExecute" });
160
+ }
143
161
  /**
144
162
  * Computes a stable content hash for a lowered Mongo execution plan.
145
163
  *
@@ -174,15 +192,262 @@ async function decodeMongoRow(row, shape, registry, collection, ctx = {}) {
174
192
  * bounded, opaque digest. See `@prisma-next/utils/hash-content` for the
175
193
  * rationale.
176
194
  *
195
+ * @throws {RuntimeErrorEnvelope} {@link RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND}
196
+ * when `exec.command` is still a pre-resolve draft (plain object), e.g. when
197
+ * `contentHash` is called from `beforeExecute`.
198
+ *
177
199
  * @internal
178
200
  */
179
201
  function computeMongoContentHash(exec) {
202
+ assertContentHashOnResolvedCommand(exec.command);
180
203
  return hashContent(canonicalStringify({
181
204
  storageHash: exec.meta.storageHash,
182
205
  command: { ...exec.command }
183
206
  }));
184
207
  }
185
208
  //#endregion
209
+ //#region src/param-ref-mutator.ts
210
+ function isPlainRecord(value) {
211
+ return value !== null && typeof value === "object" && !Array.isArray(value);
212
+ }
213
+ function* flattenDraftSlot(value) {
214
+ if (value instanceof MongoParamRef) {
215
+ yield value;
216
+ return;
217
+ }
218
+ if (Array.isArray(value)) {
219
+ for (const item of value) yield* flattenDraftSlot(item);
220
+ return;
221
+ }
222
+ if (isPlainRecord(value)) for (const v of Object.values(value)) yield* flattenDraftSlot(v);
223
+ }
224
+ /**
225
+ * Flat walk over a `MongoLoweredDraft` yielding every `MongoParamRef` leaf
226
+ * regardless of nesting — object values, array elements, filter predicate
227
+ * values, update operator values, and pipeline stage values. Raw command
228
+ * variants carry no `MongoParamRef` nodes so they yield zero entries.
229
+ *
230
+ * **Walk parity:** slot traversal matches `resolveDraftSlot` / `resolveParams`
231
+ * — refs appear only in plain-object and array containers; `Date` and other
232
+ * non-plain objects are leaves (not descended into), so middleware sees every
233
+ * ref the resolve pass will encode.
234
+ */
235
+ function* flattenMongoParamRefs(draft) {
236
+ switch (draft.kind) {
237
+ case "insertOne":
238
+ case "rawInsertOne":
239
+ yield* flattenDraftSlot(draft.document);
240
+ break;
241
+ case "insertMany":
242
+ case "rawInsertMany":
243
+ for (const doc of draft.documents) yield* flattenDraftSlot(doc);
244
+ break;
245
+ case "updateOne":
246
+ case "updateMany":
247
+ case "rawUpdateOne":
248
+ case "rawUpdateMany":
249
+ yield* flattenDraftSlot(draft.filter);
250
+ yield* flattenDraftSlot(draft.update);
251
+ break;
252
+ case "findOneAndUpdate":
253
+ case "rawFindOneAndUpdate":
254
+ yield* flattenDraftSlot(draft.filter);
255
+ yield* flattenDraftSlot(draft.update);
256
+ break;
257
+ case "deleteOne":
258
+ case "deleteMany":
259
+ case "rawDeleteOne":
260
+ case "rawDeleteMany":
261
+ yield* flattenDraftSlot(draft.filter);
262
+ break;
263
+ case "findOneAndDelete":
264
+ case "rawFindOneAndDelete":
265
+ yield* flattenDraftSlot(draft.filter);
266
+ break;
267
+ case "aggregate":
268
+ case "rawAggregate":
269
+ for (const stage of draft.pipeline) yield* flattenDraftSlot(stage);
270
+ break;
271
+ }
272
+ }
273
+ function substituteSlot(value, overrides) {
274
+ if (value instanceof MongoParamRef) {
275
+ if (overrides.has(value)) {
276
+ const opts = {};
277
+ if (value.name !== void 0) opts.name = value.name;
278
+ if (value.codecId !== void 0) opts.codecId = value.codecId;
279
+ return new MongoParamRef(overrides.get(value), opts);
280
+ }
281
+ return value;
282
+ }
283
+ if (Array.isArray(value)) return value.map((item) => substituteSlot(item, overrides));
284
+ if (isPlainRecord(value)) {
285
+ const out = {};
286
+ for (const [k, v] of Object.entries(value)) out[k] = substituteSlot(v, overrides);
287
+ return out;
288
+ }
289
+ return value;
290
+ }
291
+ function substituteDoc(doc, overrides) {
292
+ return blindCast(substituteSlot(doc, overrides));
293
+ }
294
+ function isUpdatePipeline(update) {
295
+ return Array.isArray(update);
296
+ }
297
+ function substituteUpdate(update, overrides) {
298
+ if (isUpdatePipeline(update)) return update.map((stage) => substituteDoc(stage, overrides));
299
+ return substituteDoc(update, overrides);
300
+ }
301
+ function buildMutatedDraft(draft, overrides) {
302
+ switch (draft.kind) {
303
+ case "insertOne": return {
304
+ kind: "insertOne",
305
+ collection: draft.collection,
306
+ document: substituteDoc(draft.document, overrides)
307
+ };
308
+ case "rawInsertOne": return {
309
+ kind: "rawInsertOne",
310
+ collection: draft.collection,
311
+ document: substituteDoc(draft.document, overrides)
312
+ };
313
+ case "insertMany": return {
314
+ kind: "insertMany",
315
+ collection: draft.collection,
316
+ documents: draft.documents.map((d) => substituteDoc(d, overrides))
317
+ };
318
+ case "rawInsertMany": return {
319
+ kind: "rawInsertMany",
320
+ collection: draft.collection,
321
+ documents: draft.documents.map((d) => substituteDoc(d, overrides))
322
+ };
323
+ case "updateOne": return {
324
+ kind: "updateOne",
325
+ collection: draft.collection,
326
+ filter: substituteDoc(draft.filter, overrides),
327
+ update: substituteUpdate(draft.update, overrides),
328
+ upsert: draft.upsert
329
+ };
330
+ case "updateMany": return {
331
+ kind: "updateMany",
332
+ collection: draft.collection,
333
+ filter: substituteDoc(draft.filter, overrides),
334
+ update: substituteUpdate(draft.update, overrides),
335
+ upsert: draft.upsert
336
+ };
337
+ case "rawUpdateOne": return {
338
+ kind: "rawUpdateOne",
339
+ collection: draft.collection,
340
+ filter: substituteDoc(draft.filter, overrides),
341
+ update: substituteUpdate(draft.update, overrides)
342
+ };
343
+ case "rawUpdateMany": return {
344
+ kind: "rawUpdateMany",
345
+ collection: draft.collection,
346
+ filter: substituteDoc(draft.filter, overrides),
347
+ update: substituteUpdate(draft.update, overrides)
348
+ };
349
+ case "deleteOne": return {
350
+ kind: "deleteOne",
351
+ collection: draft.collection,
352
+ filter: substituteDoc(draft.filter, overrides)
353
+ };
354
+ case "deleteMany": return {
355
+ kind: "deleteMany",
356
+ collection: draft.collection,
357
+ filter: substituteDoc(draft.filter, overrides)
358
+ };
359
+ case "rawDeleteOne": return {
360
+ kind: "rawDeleteOne",
361
+ collection: draft.collection,
362
+ filter: substituteDoc(draft.filter, overrides)
363
+ };
364
+ case "rawDeleteMany": return {
365
+ kind: "rawDeleteMany",
366
+ collection: draft.collection,
367
+ filter: substituteDoc(draft.filter, overrides)
368
+ };
369
+ case "findOneAndUpdate": return {
370
+ kind: "findOneAndUpdate",
371
+ collection: draft.collection,
372
+ filter: substituteDoc(draft.filter, overrides),
373
+ update: substituteUpdate(draft.update, overrides),
374
+ upsert: draft.upsert,
375
+ sort: draft.sort,
376
+ returnDocument: draft.returnDocument
377
+ };
378
+ case "rawFindOneAndUpdate": return {
379
+ kind: "rawFindOneAndUpdate",
380
+ collection: draft.collection,
381
+ filter: substituteDoc(draft.filter, overrides),
382
+ update: substituteUpdate(draft.update, overrides),
383
+ upsert: draft.upsert,
384
+ sort: draft.sort,
385
+ returnDocument: draft.returnDocument
386
+ };
387
+ case "findOneAndDelete": return {
388
+ kind: "findOneAndDelete",
389
+ collection: draft.collection,
390
+ filter: substituteDoc(draft.filter, overrides),
391
+ sort: draft.sort
392
+ };
393
+ case "rawFindOneAndDelete": return {
394
+ kind: "rawFindOneAndDelete",
395
+ collection: draft.collection,
396
+ filter: substituteDoc(draft.filter, overrides),
397
+ sort: draft.sort
398
+ };
399
+ case "aggregate": return {
400
+ kind: "aggregate",
401
+ collection: draft.collection,
402
+ pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides))
403
+ };
404
+ case "rawAggregate": return {
405
+ kind: "rawAggregate",
406
+ collection: draft.collection,
407
+ pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides))
408
+ };
409
+ }
410
+ }
411
+ /**
412
+ * Build a {@link MongoParamRefMutatorInternal} for the given lowered draft.
413
+ *
414
+ * The mutator captures the draft by reference and uses `flattenMongoParamRefs`
415
+ * on demand to produce `entries()`. Replacements are stored in a lazily-
416
+ * allocated `Map`; the fast path (no replacements) preserves bit-for-bit
417
+ * reference identity to the original draft in `currentDraft()`.
418
+ */
419
+ function createMongoParamRefMutator(draft) {
420
+ const originalDraft = draft;
421
+ let overrides;
422
+ const ensureOverrides = () => {
423
+ if (!overrides) overrides = /* @__PURE__ */ new Map();
424
+ return overrides;
425
+ };
426
+ function* entries() {
427
+ for (const ref of flattenMongoParamRefs(originalDraft)) yield blindCast({
428
+ ref: blindCast(ref),
429
+ value: overrides?.has(ref) ? overrides.get(ref) : ref.value,
430
+ codecId: ref.codecId
431
+ });
432
+ }
433
+ function replaceValue(handle, newValue) {
434
+ ensureOverrides().set(blindCast(handle), newValue);
435
+ }
436
+ function replaceValues(updates) {
437
+ const map = ensureOverrides();
438
+ for (const { ref, newValue } of updates) map.set(blindCast(ref), newValue);
439
+ }
440
+ return {
441
+ entries,
442
+ replaceValue: blindCast(replaceValue),
443
+ replaceValues,
444
+ currentDraft() {
445
+ if (!overrides || overrides.size === 0) return originalDraft;
446
+ return buildMutatedDraft(originalDraft, overrides);
447
+ }
448
+ };
449
+ }
450
+ //#endregion
186
451
  //#region src/mongo-runtime.ts
187
452
  function noop() {}
188
453
  var MongoRuntimeImpl = class extends RuntimeCore {
@@ -202,8 +467,9 @@ var MongoRuntimeImpl = class extends RuntimeCore {
202
467
  warn: noop,
203
468
  error: noop
204
469
  },
205
- contentHash: (exec) => computeMongoContentHash(exec),
206
- scope: "runtime"
470
+ contentHash: (exec) => computeMongoContentHash(blindCast(exec)),
471
+ scope: "runtime",
472
+ planExecutionId: ""
207
473
  };
208
474
  super({
209
475
  middleware,
@@ -214,6 +480,7 @@ var MongoRuntimeImpl = class extends RuntimeCore {
214
480
  this.#driver = options.driver;
215
481
  this.#codecs = options.context.codecs;
216
482
  }
483
+ /* v8 ignore start -- one-phase lower satisfies RuntimeCore; execute uses structuralLower + resolveParams */
217
484
  async lower(plan, ctx) {
218
485
  return {
219
486
  command: await this.#adapter.lower(plan, ctx),
@@ -221,6 +488,7 @@ var MongoRuntimeImpl = class extends RuntimeCore {
221
488
  ...ifDefined("resultShape", plan.resultShape)
222
489
  };
223
490
  }
491
+ /* v8 ignore stop */
224
492
  runDriver(exec) {
225
493
  return this.#driver.execute(exec.command);
226
494
  }
@@ -228,14 +496,29 @@ var MongoRuntimeImpl = class extends RuntimeCore {
228
496
  const self = this;
229
497
  const signal = options?.signal;
230
498
  const codecCtx = signal === void 0 ? {} : { signal };
499
+ const execCtx = {
500
+ ...self.ctx,
501
+ planExecutionId: crypto.randomUUID()
502
+ };
231
503
  const generator = async function* () {
232
504
  checkAborted(codecCtx, "stream");
233
505
  const compiled = await self.runBeforeCompile(plan);
234
- const exec = await self.lower(compiled, codecCtx);
235
- await runBeforeExecuteChain(exec, self.middleware, self.ctx);
236
- const stream = runWithMiddleware(exec, self.middleware, self.ctx, () => self.runDriver(exec));
237
- for await (const rawRow of stream) if (exec.resultShape === void 0) yield rawRow;
238
- else yield await decodeMongoRow(rawRow, exec.resultShape, self.#codecs, exec.command.collection, codecCtx);
506
+ const draft = self.#adapter.structuralLower(compiled);
507
+ const mutator = createMongoParamRefMutator(draft);
508
+ await runBeforeExecuteChain({
509
+ meta: compiled.meta,
510
+ ...ifDefined("resultShape", compiled.resultShape),
511
+ command: blindCast(draft)
512
+ }, self.middleware, execCtx, mutator);
513
+ const resolvedCommand = await self.#adapter.resolveParams(mutator.currentDraft(), codecCtx);
514
+ const exec = {
515
+ meta: compiled.meta,
516
+ ...ifDefined("resultShape", compiled.resultShape),
517
+ command: resolvedCommand
518
+ };
519
+ const stream = runWithMiddleware(exec, self.middleware, execCtx, () => self.runDriver(exec));
520
+ for await (const rawRow of stream) if (exec.resultShape === void 0) yield blindCast(rawRow);
521
+ else yield blindCast(await decodeMongoRow(rawRow, exec.resultShape, self.#codecs, exec.command.collection, codecCtx));
239
522
  };
240
523
  return new AsyncIterableResult(generator());
241
524
  }
@@ -247,6 +530,6 @@ function createMongoRuntime(options) {
247
530
  return new MongoRuntimeImpl(options);
248
531
  }
249
532
  //#endregion
250
- export { createMongoExecutionContext, createMongoExecutionStack, createMongoRuntime };
533
+ export { createMongoExecutionContext, createMongoExecutionStack, createMongoParamRefMutator, createMongoRuntime, flattenMongoParamRefs };
251
534
 
252
535
  //# sourceMappingURL=index.mjs.map