@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 +134 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +291 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -20
- package/src/content-hash.ts +34 -5
- package/src/exports/index.ts +11 -0
- package/src/mongo-execution-plan.ts +10 -2
- package/src/mongo-middleware.ts +27 -3
- package/src/mongo-runtime.ts +84 -10
- package/src/param-ref-mutator.ts +435 -0
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` —
|
|
15
|
-
* `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/index.d.mts.map
CHANGED
|
@@ -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":"
|
|
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
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|