@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.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["#adapter","#driver","#codecs"],"sources":["../src/mongo-execution-stack.ts","../src/codecs/decoding.ts","../src/content-hash.ts","../src/mongo-runtime.ts"],"sourcesContent":["import {\n createExecutionStack,\n type ExecutionStack,\n type RuntimeAdapterDescriptor,\n type RuntimeAdapterInstance,\n type RuntimeDriverDescriptor,\n type RuntimeDriverInstance,\n type RuntimeExtensionDescriptor,\n type RuntimeExtensionInstance,\n type RuntimeTargetDescriptor,\n type RuntimeTargetInstance,\n} from '@prisma-next/framework-components/execution';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport type { MongoCodec } from '@prisma-next/mongo-codec';\nimport { type MongoCodecRegistry, newMongoCodecRegistry } from '@prisma-next/mongo-codec';\nimport type { MongoAdapter } from '@prisma-next/mongo-lowering';\n\n/**\n * Mongo-specific static contributions a runtime descriptor declares.\n *\n * Mirrors `SqlStaticContributions` in shape: a `codecs()` getter that yields a `MongoCodecRegistry` populated with this contributor's codecs. The registry is then walked by `createMongoExecutionContext` and folded into the single per-execution registry the runtime reads from at decode time.\n */\nexport interface MongoStaticContributions {\n readonly codecs: () => MongoCodecRegistry;\n}\n\nexport interface MongoRuntimeTargetDescriptor<\n TTargetId extends string = 'mongo',\n TTargetInstance extends RuntimeTargetInstance<'mongo', TTargetId> = RuntimeTargetInstance<\n 'mongo',\n TTargetId\n >,\n> extends RuntimeTargetDescriptor<'mongo', TTargetId, TTargetInstance>,\n MongoStaticContributions {}\n\nexport interface MongoRuntimeAdapterInstance<TTargetId extends string = 'mongo'>\n extends RuntimeAdapterInstance<'mongo', TTargetId>,\n MongoAdapter {}\n\nexport interface MongoRuntimeAdapterDescriptor<\n TTargetId extends string = 'mongo',\n TAdapterInstance extends RuntimeAdapterInstance<\n 'mongo',\n TTargetId\n > = MongoRuntimeAdapterInstance<TTargetId>,\n> extends RuntimeAdapterDescriptor<'mongo', TTargetId, TAdapterInstance>,\n MongoStaticContributions {}\n\nexport interface MongoRuntimeExtensionInstance<TTargetId extends string = 'mongo'>\n extends RuntimeExtensionInstance<'mongo', TTargetId> {}\n\nexport interface MongoRuntimeExtensionDescriptor<TTargetId extends string = 'mongo'>\n extends RuntimeExtensionDescriptor<'mongo', TTargetId, MongoRuntimeExtensionInstance<TTargetId>>,\n MongoStaticContributions {\n create(): MongoRuntimeExtensionInstance<TTargetId>;\n}\n\n/**\n * The Mongo execution stack: target + adapter + optional driver + extension packs. Mirrors `SqlExecutionStack`. Constructed via `createMongoExecutionStack`.\n */\nexport interface MongoExecutionStack<TTargetId extends string = 'mongo'> {\n readonly target: MongoRuntimeTargetDescriptor<TTargetId>;\n readonly adapter: MongoRuntimeAdapterDescriptor<TTargetId>;\n readonly driver:\n | RuntimeDriverDescriptor<\n 'mongo',\n TTargetId,\n unknown,\n RuntimeDriverInstance<'mongo', TTargetId>\n >\n | undefined;\n readonly extensionPacks: readonly MongoRuntimeExtensionDescriptor<TTargetId>[];\n}\n\nexport function createMongoExecutionStack<TTargetId extends string = 'mongo'>(options: {\n readonly target: MongoRuntimeTargetDescriptor<TTargetId>;\n readonly adapter: MongoRuntimeAdapterDescriptor<TTargetId>;\n readonly driver?:\n | RuntimeDriverDescriptor<\n 'mongo',\n TTargetId,\n unknown,\n RuntimeDriverInstance<'mongo', TTargetId>\n >\n | undefined;\n readonly extensionPacks?: readonly MongoRuntimeExtensionDescriptor<TTargetId>[] | undefined;\n}): MongoExecutionStack<TTargetId> {\n const stack = createExecutionStack({\n target: options.target,\n adapter: options.adapter,\n driver: options.driver,\n extensionPacks: options.extensionPacks,\n });\n return stack as ExecutionStack<'mongo', TTargetId> as MongoExecutionStack<TTargetId>;\n}\n\n/**\n * Read-only view of the codec registry exposed on `MongoExecutionContext`.\n *\n * Hides `register()` and the iterator from public surface — users do not mutate the per-execution codec registry. Internal aggregation in `createMongoExecutionContext` keeps using the full `MongoCodecRegistry` (it needs `register()`).\n */\nexport interface MongoCodecLookup {\n get(id: string): MongoCodec<string> | undefined;\n has(id: string): boolean;\n}\n\n/**\n * Per-execution context aggregated from a `MongoExecutionStack`.\n *\n * Carries the user's contract, a read-only lookup over the codec registry composed from every stack contributor, and a back-reference to the stack itself so the runtime can reach the adapter without users threading it explicitly.\n *\n * Mirrors SQL's `ExecutionContext` in role; Mongo's flavour is leaner because there are no parameterised codecs, JSON-schema validators, or mutation-default generators in scope yet.\n */\nexport interface MongoExecutionContext<TTargetId extends string = 'mongo'> {\n readonly contract: unknown;\n readonly codecs: MongoCodecLookup;\n readonly stack: MongoExecutionStack<TTargetId>;\n}\n\nexport function createMongoExecutionContext<TTargetId extends string = 'mongo'>(options: {\n readonly contract: unknown;\n readonly stack: MongoExecutionStack<TTargetId>;\n}): MongoExecutionContext<TTargetId> {\n const registry = newMongoCodecRegistry();\n const owners = new Map<string, string>();\n\n const contributors: ReadonlyArray<MongoStaticContributions & { readonly id: string }> = [\n options.stack.target,\n options.stack.adapter,\n ...options.stack.extensionPacks,\n ];\n\n for (const contributor of contributors) {\n const contributed = contributor.codecs();\n for (const codec of iterateCodecs(contributed)) {\n const existingOwner = owners.get(codec.id);\n if (existingOwner !== undefined) {\n throw runtimeError(\n 'RUNTIME.DUPLICATE_CODEC',\n `Duplicate Mongo codec id '${codec.id}' contributed by '${contributor.id}' (already registered by '${existingOwner}').`,\n { codecId: codec.id, existingOwner, incomingOwner: contributor.id },\n );\n }\n registry.register(codec);\n owners.set(codec.id, contributor.id);\n }\n }\n\n return Object.freeze({\n contract: options.contract,\n codecs: registry,\n stack: options.stack,\n });\n}\n\nfunction* iterateCodecs(registry: MongoCodecRegistry): Iterable<MongoCodec<string>> {\n yield* registry.values();\n}\n","import type { CodecCallContext } from '@prisma-next/framework-components/codec';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport type { MongoFieldShape, MongoResultShape } from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoCodecLookup } from '../mongo-execution-stack';\n\nconst WIRE_PREVIEW_LIMIT = 100;\n\nfunction previewWireValue(wireValue: unknown): string {\n if (typeof wireValue === 'string') {\n return wireValue.length > WIRE_PREVIEW_LIMIT\n ? `${wireValue.substring(0, WIRE_PREVIEW_LIMIT)}...`\n : wireValue;\n }\n return String(wireValue).substring(0, WIRE_PREVIEW_LIMIT);\n}\n\nfunction wrapDecodeFailure(\n error: unknown,\n collection: string,\n path: string,\n codecId: string,\n wireValue: unknown,\n): never {\n const message = error instanceof Error ? error.message : String(error);\n const wrapped = runtimeError(\n 'RUNTIME.DECODE_FAILED',\n `Failed to decode field ${path} in collection '${collection}' with codec '${codecId}': ${message}`,\n {\n collection,\n path,\n codec: codecId,\n wirePreview: previewWireValue(wireValue),\n },\n );\n wrapped.cause = error;\n throw wrapped;\n}\n\nexport async function decodeMongoRow(\n row: unknown,\n shape: MongoResultShape,\n registry: MongoCodecLookup,\n collection: string,\n ctx: CodecCallContext = {},\n): Promise<unknown> {\n if (shape.kind === 'unknown') {\n return row;\n }\n if (typeof row !== 'object' || row === null) {\n return row;\n }\n const rowObj = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n const tasks: Array<Promise<void>> = [];\n\n function scheduleLeaf(\n path: string,\n codecId: string,\n wire: unknown,\n assign: (v: unknown) => void,\n ): void {\n const codec = registry.get(codecId);\n if (!codec) {\n assign(wire);\n return;\n }\n tasks.push(\n (async () => {\n try {\n assign(await codec.decode(wire, ctx));\n } catch (error) {\n wrapDecodeFailure(error, collection, path, codecId, wire);\n }\n })(),\n );\n }\n\n function walkField(\n value: unknown,\n fieldShape: MongoFieldShape,\n path: string,\n assign: (v: unknown) => void,\n ): void {\n // Exhaustive over `MongoFieldShape['kind']` by construction:\n // adding a new variant must add a corresponding arm or the\n // `satisfies never` below would error at type-check time.\n switch (fieldShape.kind) {\n case 'unknown':\n assign(value);\n return;\n case 'leaf':\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n scheduleLeaf(path, fieldShape.codecId, value, assign);\n return;\n case 'document': {\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n assign(value);\n return;\n }\n const vObj = value as Record<string, unknown>;\n // Pre-seed with a shallow copy so unshaped subdocument keys\n // round-trip verbatim. Subsequent walkField assignments overwrite\n // shaped keys with their decoded values. Mirrors the top-level\n // pass-through invariant — the decode path is structurally\n // additive at every nesting depth, not just the root.\n const nested: Record<string, unknown> = { ...vObj };\n assign(nested);\n for (const [fk, fShape] of Object.entries(fieldShape.fields)) {\n walkField(vObj[fk], fShape, `${path}.${fk}`, (v) => {\n nested[fk] = v;\n });\n }\n return;\n }\n case 'array': {\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n if (!Array.isArray(value)) {\n assign(value);\n return;\n }\n const arr: unknown[] = [];\n assign(arr);\n for (let i = 0; i < value.length; i++) {\n const el = value[i];\n walkField(el, fieldShape.element, `${path}.${i}`, (v) => {\n arr[i] = v;\n });\n }\n return;\n }\n }\n // The switch above is exhaustive over `MongoFieldShape['kind']`. The\n // `satisfies never` below is a compile-time guard that fails if a new\n // variant is added without a corresponding arm.\n /* v8 ignore start */\n fieldShape satisfies never;\n /* v8 ignore stop */\n }\n\n for (const [k, fShape] of Object.entries(shape.fields)) {\n walkField(rowObj[k], fShape, k, (v) => {\n out[k] = v;\n });\n }\n\n // Pass through any row fields the shape does not describe. The shape is a\n // partial, lane-vouched description of what the runtime knows how to decode;\n // fields outside that description (e.g. polymorphic variant fields the base\n // model's shape doesn't enumerate, sidecar fields a future schema migration\n // adds) round-trip verbatim. Drop semantics belongs to explicit projection\n // (`select` / `$project`), not to the structural decode path.\n for (const k of Object.keys(rowObj)) {\n if (!Object.hasOwn(shape.fields, k)) {\n out[k] = rowObj[k];\n }\n }\n\n await Promise.all(tasks);\n return out;\n}\n","import { canonicalStringify } from '@prisma-next/utils/canonical-stringify';\nimport { hashContent } from '@prisma-next/utils/hash-content';\nimport type { MongoExecutionPlan } from './mongo-execution-plan';\n\n/**\n * Computes a stable content hash for a lowered Mongo execution plan.\n *\n * Internally builds an unambiguous canonical-stringified preimage from\n * two components:\n *\n * 1. `meta.storageHash` — discriminates by schema. A migration changes the\n * storage hash, which invalidates cached entries automatically (no\n * per-app invalidation logic needed for schema changes).\n * 2. `exec.command` — the wire command. `canonicalStringify` produces a\n * deterministic serialization that is stable across object key\n * insertion order and that distinguishes types JSON would otherwise\n * conflate (e.g. `BigInt(1)` vs `1`, `Date` vs ISO string, `Buffer`\n * vs number array). The spread converts the frozen wire-command\n * class instance (`InsertOneWireCommand`, `AggregateWireCommand`, …)\n * into a plain object exposing its own enumerable properties\n * (`kind`, `collection`, plus the payload-specific fields like\n * `document`/`filter`/`update`/`pipeline`/…), which is what\n * `canonicalStringify` accepts; class instances are rejected\n * outright to prevent silent collisions.\n *\n * Unlike SQL, there is no separate \"rendered statement\" component because\n * a Mongo `MongoExecutionPlan.command` is the wire command itself —\n * canonicalizing it captures both structure and parameters in one pass.\n *\n * The components are wrapped in an object and canonicalized as a single\n * unit (rather than concatenated with a delimiter) so component\n * boundaries are unambiguous and cannot collide with a different split\n * of the same characters.\n *\n * The canonical string is then piped through `hashContent` to produce a\n * bounded, opaque digest. See `@prisma-next/utils/hash-content` for the\n * rationale.\n *\n * @internal\n */\nexport function computeMongoContentHash(exec: MongoExecutionPlan): Promise<string> {\n // Spread `exec.command` to a plain object: `canonicalStringify`\n // rejects class instances by design (so `Map`/`Set`/class instances\n // cannot collapse to `{}` and silently collide). All wire-command\n // data lives on own enumerable properties, so this preserves the\n // same canonical form and therefore the same hash.\n return hashContent(\n canonicalStringify({\n storageHash: exec.meta.storageHash,\n command: { ...exec.command },\n }),\n );\n}\n","import type { CodecCallContext } from '@prisma-next/framework-components/codec';\nimport {\n AsyncIterableResult,\n checkAborted,\n checkMiddlewareCompatibility,\n RuntimeCore,\n type RuntimeExecuteOptions,\n runBeforeExecuteChain,\n runWithMiddleware,\n} from '@prisma-next/framework-components/runtime';\nimport type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';\nimport type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { decodeMongoRow } from './codecs/decoding';\nimport { computeMongoContentHash } from './content-hash';\nimport type { MongoExecutionPlan } from './mongo-execution-plan';\nimport type { MongoCodecLookup, MongoExecutionContext } from './mongo-execution-stack';\nimport type { MongoMiddleware, MongoMiddlewareContext } from './mongo-middleware';\n\nfunction noop() {}\n\n/**\n * Mongo runtime options.\n *\n * The runtime takes a {@link MongoExecutionContext} (built via\n * `createMongoExecutionContext`) and a driver. Codec resolution flows from\n * the context — there is no `codecs` field on this options bag. The adapter\n * is reached via `context.stack.adapter` (instantiated lazily through the\n * stack's `create(stack)` factory). See ADR — Mongo result-shape as a\n * structural plan field, § Codec registry: stack aggregation, not user\n * threading.\n */\nexport interface MongoRuntimeOptions {\n readonly context: MongoExecutionContext;\n readonly driver: MongoDriver;\n readonly middleware?: readonly MongoMiddleware[];\n readonly mode?: 'strict' | 'permissive';\n}\n\nexport interface MongoRuntime {\n /**\n * Execute a `MongoQueryPlan` and return an async iterable of rows.\n *\n * The optional `options.signal` is threaded through\n * `lower → adapter.lower → resolveValue → codec.encode` so codec authors\n * who forward the signal to their underlying SDK get true cancellation\n * of in-flight network calls. The runtime additionally observes the\n * signal at two boundaries:\n *\n * - **Already-aborted at entry** — first `next()` throws\n * `RUNTIME.ABORTED { phase: 'stream' }` before any work is done.\n * (Inherited from `RuntimeCore.execute`.)\n * - **Mid-encode abort** — surfaces as\n * `RUNTIME.ABORTED { phase: 'encode' }` from inside `resolveValue`'s\n * per-level `Promise.all` race.\n *\n * Mongo's read path decodes rows via `resultShape` (per ADR 209). The\n * same `CodecCallContext` is forwarded into each `codec.decode(wire, ctx)`\n * call, so async decoders that respect the signal get cancellation; the\n * runtime itself does not currently emit a `phase: 'decode'` envelope.\n */\n execute<Row>(\n plan: MongoQueryPlan<Row>,\n options?: RuntimeExecuteOptions,\n ): AsyncIterableResult<Row>;\n close(): Promise<void>;\n}\n\nclass MongoRuntimeImpl\n extends RuntimeCore<MongoQueryPlan, MongoExecutionPlan, MongoMiddleware>\n implements MongoRuntime\n{\n readonly #adapter: MongoAdapter;\n readonly #driver: MongoDriver;\n readonly #codecs: MongoCodecLookup;\n\n constructor(options: MongoRuntimeOptions) {\n const middleware = options.middleware ? [...options.middleware] : [];\n const targetId = options.context.stack.target.targetId;\n for (const mw of middleware) {\n checkMiddlewareCompatibility(mw, 'mongo', targetId);\n }\n\n const ctx: MongoMiddlewareContext = {\n contract: options.context.contract,\n mode: options.mode ?? 'strict',\n now: () => Date.now(),\n log: { info: noop, warn: noop, error: noop },\n // ctx is only invoked by runWithMiddleware with execs this runtime lowered;\n // the framework parameter type is the cross-family base.\n contentHash: (exec) => computeMongoContentHash(exec as MongoExecutionPlan),\n // When MongoRuntimeImpl grows connection()/transaction() surfaces,\n // derive a scope-narrowed ctx per call (mirror\n // SqlRuntimeImpl#executeAgainstQueryable in `sql-runtime.ts`).\n scope: 'runtime',\n };\n\n super({ middleware, ctx });\n\n const adapterDescriptor = options.context.stack.adapter;\n const adapterInstance = adapterDescriptor.create(options.context.stack);\n this.#adapter = adapterInstance;\n this.#driver = options.driver;\n this.#codecs = options.context.codecs;\n }\n\n protected override async lower(\n plan: MongoQueryPlan,\n ctx: CodecCallContext,\n ): Promise<MongoExecutionPlan> {\n return {\n command: await this.#adapter.lower(plan, ctx),\n meta: plan.meta,\n ...ifDefined('resultShape', plan.resultShape),\n };\n }\n\n protected override runDriver(exec: MongoExecutionPlan): AsyncIterable<Record<string, unknown>> {\n return this.#driver.execute<Record<string, unknown>>(exec.command);\n }\n\n override execute<Row>(\n plan: MongoQueryPlan & { readonly _row?: Row },\n options?: RuntimeExecuteOptions,\n ): AsyncIterableResult<Row> {\n const self = this;\n const signal = options?.signal;\n const codecCtx: CodecCallContext = signal === undefined ? {} : { signal };\n const generator = async function* (): AsyncGenerator<Row, void, unknown> {\n checkAborted(codecCtx, 'stream');\n const compiled = await self.runBeforeCompile(plan);\n const exec = await self.lower(compiled, codecCtx);\n await runBeforeExecuteChain<MongoExecutionPlan>(exec, self.middleware, self.ctx);\n const stream = runWithMiddleware<MongoExecutionPlan, Record<string, unknown>>(\n exec,\n self.middleware,\n self.ctx,\n () => self.runDriver(exec),\n );\n for await (const rawRow of stream) {\n if (exec.resultShape === undefined) {\n yield rawRow as Row;\n } else {\n // Source the collection from the lowered exec rather than the\n // pre-lowering plan: a `runBeforeCompile` middleware is allowed to\n // rewrite collection names during compilation, and the wire\n // command carried by `exec` is always authoritative for what just\n // ran.\n const decoded = await decodeMongoRow(\n rawRow,\n exec.resultShape,\n self.#codecs,\n exec.command.collection,\n codecCtx,\n );\n yield decoded as Row;\n }\n }\n };\n return new AsyncIterableResult(generator());\n }\n\n override async close(): Promise<void> {\n await this.#driver.close();\n }\n}\n\nexport function createMongoRuntime(options: MongoRuntimeOptions): MongoRuntime {\n return new MongoRuntimeImpl(options);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["#adapter","#driver","#codecs"],"sources":["../src/mongo-execution-stack.ts","../src/codecs/decoding.ts","../src/content-hash.ts","../src/param-ref-mutator.ts","../src/mongo-runtime.ts"],"sourcesContent":["import {\n createExecutionStack,\n type ExecutionStack,\n type RuntimeAdapterDescriptor,\n type RuntimeAdapterInstance,\n type RuntimeDriverDescriptor,\n type RuntimeDriverInstance,\n type RuntimeExtensionDescriptor,\n type RuntimeExtensionInstance,\n type RuntimeTargetDescriptor,\n type RuntimeTargetInstance,\n} from '@prisma-next/framework-components/execution';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport type { MongoCodec } from '@prisma-next/mongo-codec';\nimport { type MongoCodecRegistry, newMongoCodecRegistry } from '@prisma-next/mongo-codec';\nimport type { MongoAdapter } from '@prisma-next/mongo-lowering';\n\n/**\n * Mongo-specific static contributions a runtime descriptor declares.\n *\n * Mirrors `SqlStaticContributions` in shape: a `codecs()` getter that yields a `MongoCodecRegistry` populated with this contributor's codecs. The registry is then walked by `createMongoExecutionContext` and folded into the single per-execution registry the runtime reads from at decode time.\n */\nexport interface MongoStaticContributions {\n readonly codecs: () => MongoCodecRegistry;\n}\n\nexport interface MongoRuntimeTargetDescriptor<\n TTargetId extends string = 'mongo',\n TTargetInstance extends RuntimeTargetInstance<'mongo', TTargetId> = RuntimeTargetInstance<\n 'mongo',\n TTargetId\n >,\n> extends RuntimeTargetDescriptor<'mongo', TTargetId, TTargetInstance>,\n MongoStaticContributions {}\n\nexport interface MongoRuntimeAdapterInstance<TTargetId extends string = 'mongo'>\n extends RuntimeAdapterInstance<'mongo', TTargetId>,\n MongoAdapter {}\n\nexport interface MongoRuntimeAdapterDescriptor<\n TTargetId extends string = 'mongo',\n TAdapterInstance extends RuntimeAdapterInstance<\n 'mongo',\n TTargetId\n > = MongoRuntimeAdapterInstance<TTargetId>,\n> extends RuntimeAdapterDescriptor<'mongo', TTargetId, TAdapterInstance>,\n MongoStaticContributions {}\n\nexport interface MongoRuntimeExtensionInstance<TTargetId extends string = 'mongo'>\n extends RuntimeExtensionInstance<'mongo', TTargetId> {}\n\nexport interface MongoRuntimeExtensionDescriptor<TTargetId extends string = 'mongo'>\n extends RuntimeExtensionDescriptor<'mongo', TTargetId, MongoRuntimeExtensionInstance<TTargetId>>,\n MongoStaticContributions {\n create(): MongoRuntimeExtensionInstance<TTargetId>;\n}\n\n/**\n * The Mongo execution stack: target + adapter + optional driver + extension packs. Mirrors `SqlExecutionStack`. Constructed via `createMongoExecutionStack`.\n */\nexport interface MongoExecutionStack<TTargetId extends string = 'mongo'> {\n readonly target: MongoRuntimeTargetDescriptor<TTargetId>;\n readonly adapter: MongoRuntimeAdapterDescriptor<TTargetId>;\n readonly driver:\n | RuntimeDriverDescriptor<\n 'mongo',\n TTargetId,\n unknown,\n RuntimeDriverInstance<'mongo', TTargetId>\n >\n | undefined;\n readonly extensionPacks: readonly MongoRuntimeExtensionDescriptor<TTargetId>[];\n}\n\nexport function createMongoExecutionStack<TTargetId extends string = 'mongo'>(options: {\n readonly target: MongoRuntimeTargetDescriptor<TTargetId>;\n readonly adapter: MongoRuntimeAdapterDescriptor<TTargetId>;\n readonly driver?:\n | RuntimeDriverDescriptor<\n 'mongo',\n TTargetId,\n unknown,\n RuntimeDriverInstance<'mongo', TTargetId>\n >\n | undefined;\n readonly extensionPacks?: readonly MongoRuntimeExtensionDescriptor<TTargetId>[] | undefined;\n}): MongoExecutionStack<TTargetId> {\n const stack = createExecutionStack({\n target: options.target,\n adapter: options.adapter,\n driver: options.driver,\n extensionPacks: options.extensionPacks,\n });\n return stack as ExecutionStack<'mongo', TTargetId> as MongoExecutionStack<TTargetId>;\n}\n\n/**\n * Read-only view of the codec registry exposed on `MongoExecutionContext`.\n *\n * Hides `register()` and the iterator from public surface — users do not mutate the per-execution codec registry. Internal aggregation in `createMongoExecutionContext` keeps using the full `MongoCodecRegistry` (it needs `register()`).\n */\nexport interface MongoCodecLookup {\n get(id: string): MongoCodec<string> | undefined;\n has(id: string): boolean;\n}\n\n/**\n * Per-execution context aggregated from a `MongoExecutionStack`.\n *\n * Carries the user's contract, a read-only lookup over the codec registry composed from every stack contributor, and a back-reference to the stack itself so the runtime can reach the adapter without users threading it explicitly.\n *\n * Mirrors SQL's `ExecutionContext` in role; Mongo's flavour is leaner because there are no parameterised codecs, JSON-schema validators, or mutation-default generators in scope yet.\n */\nexport interface MongoExecutionContext<TTargetId extends string = 'mongo'> {\n readonly contract: unknown;\n readonly codecs: MongoCodecLookup;\n readonly stack: MongoExecutionStack<TTargetId>;\n}\n\nexport function createMongoExecutionContext<TTargetId extends string = 'mongo'>(options: {\n readonly contract: unknown;\n readonly stack: MongoExecutionStack<TTargetId>;\n}): MongoExecutionContext<TTargetId> {\n const registry = newMongoCodecRegistry();\n const owners = new Map<string, string>();\n\n const contributors: ReadonlyArray<MongoStaticContributions & { readonly id: string }> = [\n options.stack.target,\n options.stack.adapter,\n ...options.stack.extensionPacks,\n ];\n\n for (const contributor of contributors) {\n const contributed = contributor.codecs();\n for (const codec of iterateCodecs(contributed)) {\n const existingOwner = owners.get(codec.id);\n if (existingOwner !== undefined) {\n throw runtimeError(\n 'RUNTIME.DUPLICATE_CODEC',\n `Duplicate Mongo codec id '${codec.id}' contributed by '${contributor.id}' (already registered by '${existingOwner}').`,\n { codecId: codec.id, existingOwner, incomingOwner: contributor.id },\n );\n }\n registry.register(codec);\n owners.set(codec.id, contributor.id);\n }\n }\n\n return Object.freeze({\n contract: options.contract,\n codecs: registry,\n stack: options.stack,\n });\n}\n\nfunction* iterateCodecs(registry: MongoCodecRegistry): Iterable<MongoCodec<string>> {\n yield* registry.values();\n}\n","import type { CodecCallContext } from '@prisma-next/framework-components/codec';\nimport { runtimeError } from '@prisma-next/framework-components/runtime';\nimport type { MongoFieldShape, MongoResultShape } from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoCodecLookup } from '../mongo-execution-stack';\n\nconst WIRE_PREVIEW_LIMIT = 100;\n\nfunction previewWireValue(wireValue: unknown): string {\n if (typeof wireValue === 'string') {\n return wireValue.length > WIRE_PREVIEW_LIMIT\n ? `${wireValue.substring(0, WIRE_PREVIEW_LIMIT)}...`\n : wireValue;\n }\n return String(wireValue).substring(0, WIRE_PREVIEW_LIMIT);\n}\n\nfunction wrapDecodeFailure(\n error: unknown,\n collection: string,\n path: string,\n codecId: string,\n wireValue: unknown,\n): never {\n const message = error instanceof Error ? error.message : String(error);\n const wrapped = runtimeError(\n 'RUNTIME.DECODE_FAILED',\n `Failed to decode field ${path} in collection '${collection}' with codec '${codecId}': ${message}`,\n {\n collection,\n path,\n codec: codecId,\n wirePreview: previewWireValue(wireValue),\n },\n );\n wrapped.cause = error;\n throw wrapped;\n}\n\nexport async function decodeMongoRow(\n row: unknown,\n shape: MongoResultShape,\n registry: MongoCodecLookup,\n collection: string,\n ctx: CodecCallContext = {},\n): Promise<unknown> {\n if (shape.kind === 'unknown') {\n return row;\n }\n if (typeof row !== 'object' || row === null) {\n return row;\n }\n const rowObj = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n const tasks: Array<Promise<void>> = [];\n\n function scheduleLeaf(\n path: string,\n codecId: string,\n wire: unknown,\n assign: (v: unknown) => void,\n ): void {\n const codec = registry.get(codecId);\n if (!codec) {\n assign(wire);\n return;\n }\n tasks.push(\n (async () => {\n try {\n assign(await codec.decode(wire, ctx));\n } catch (error) {\n wrapDecodeFailure(error, collection, path, codecId, wire);\n }\n })(),\n );\n }\n\n function walkField(\n value: unknown,\n fieldShape: MongoFieldShape,\n path: string,\n assign: (v: unknown) => void,\n ): void {\n // Exhaustive over `MongoFieldShape['kind']` by construction:\n // adding a new variant must add a corresponding arm or the\n // `satisfies never` below would error at type-check time.\n switch (fieldShape.kind) {\n case 'unknown':\n assign(value);\n return;\n case 'leaf':\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n scheduleLeaf(path, fieldShape.codecId, value, assign);\n return;\n case 'document': {\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n assign(value);\n return;\n }\n const vObj = value as Record<string, unknown>;\n // Pre-seed with a shallow copy so unshaped subdocument keys\n // round-trip verbatim. Subsequent walkField assignments overwrite\n // shaped keys with their decoded values. Mirrors the top-level\n // pass-through invariant — the decode path is structurally\n // additive at every nesting depth, not just the root.\n const nested: Record<string, unknown> = { ...vObj };\n assign(nested);\n for (const [fk, fShape] of Object.entries(fieldShape.fields)) {\n walkField(vObj[fk], fShape, `${path}.${fk}`, (v) => {\n nested[fk] = v;\n });\n }\n return;\n }\n case 'array': {\n if (value === null || value === undefined) {\n assign(value);\n return;\n }\n if (!Array.isArray(value)) {\n assign(value);\n return;\n }\n const arr: unknown[] = [];\n assign(arr);\n for (let i = 0; i < value.length; i++) {\n const el = value[i];\n walkField(el, fieldShape.element, `${path}.${i}`, (v) => {\n arr[i] = v;\n });\n }\n return;\n }\n }\n // The switch above is exhaustive over `MongoFieldShape['kind']`. The\n // `satisfies never` below is a compile-time guard that fails if a new\n // variant is added without a corresponding arm.\n /* v8 ignore start */\n fieldShape satisfies never;\n /* v8 ignore stop */\n }\n\n for (const [k, fShape] of Object.entries(shape.fields)) {\n walkField(rowObj[k], fShape, k, (v) => {\n out[k] = v;\n });\n }\n\n // Pass through any row fields the shape does not describe. The shape is a\n // partial, lane-vouched description of what the runtime knows how to decode;\n // fields outside that description (e.g. polymorphic variant fields the base\n // model's shape doesn't enumerate, sidecar fields a future schema migration\n // adds) round-trip verbatim. Drop semantics belongs to explicit projection\n // (`select` / `$project`), not to the structural decode path.\n for (const k of Object.keys(rowObj)) {\n if (!Object.hasOwn(shape.fields, k)) {\n out[k] = rowObj[k];\n }\n }\n\n await Promise.all(tasks);\n return out;\n}\n","import { runtimeError } from '@prisma-next/framework-components/runtime';\nimport { canonicalStringify } from '@prisma-next/utils/canonical-stringify';\nimport { hashContent } from '@prisma-next/utils/hash-content';\nimport type { MongoExecutionPlan } from './mongo-execution-plan';\n\n/** @internal */\nexport const RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND =\n 'RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND' as const;\n\n/**\n * Resolved wire commands are frozen class instances (`InsertOneWireCommand`, …);\n * pre-resolve `beforeExecute` plans hold a plain-object `MongoLoweredDraft` in the\n * command slot. O(1) prototype check — no tree walk on the hot path.\n */\nfunction isResolvedMongoWireCommand(command: unknown): boolean {\n if (command === null || typeof command !== 'object') {\n return false;\n }\n const proto = Object.getPrototypeOf(command);\n return proto !== null && proto !== Object.prototype;\n}\n\nfunction assertContentHashOnResolvedCommand(command: unknown): void {\n if (isResolvedMongoWireCommand(command)) {\n return;\n }\n throw runtimeError(\n RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND,\n '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.',\n { phase: 'beforeExecute' },\n );\n}\n\n/**\n * Computes a stable content hash for a lowered Mongo execution plan.\n *\n * Internally builds an unambiguous canonical-stringified preimage from\n * two components:\n *\n * 1. `meta.storageHash` — discriminates by schema. A migration changes the\n * storage hash, which invalidates cached entries automatically (no\n * per-app invalidation logic needed for schema changes).\n * 2. `exec.command` — the wire command. `canonicalStringify` produces a\n * deterministic serialization that is stable across object key\n * insertion order and that distinguishes types JSON would otherwise\n * conflate (e.g. `BigInt(1)` vs `1`, `Date` vs ISO string, `Buffer`\n * vs number array). The spread converts the frozen wire-command\n * class instance (`InsertOneWireCommand`, `AggregateWireCommand`, …)\n * into a plain object exposing its own enumerable properties\n * (`kind`, `collection`, plus the payload-specific fields like\n * `document`/`filter`/`update`/`pipeline`/…), which is what\n * `canonicalStringify` accepts; class instances are rejected\n * outright to prevent silent collisions.\n *\n * Unlike SQL, there is no separate \"rendered statement\" component because\n * a Mongo `MongoExecutionPlan.command` is the wire command itself —\n * canonicalizing it captures both structure and parameters in one pass.\n *\n * The components are wrapped in an object and canonicalized as a single\n * unit (rather than concatenated with a delimiter) so component\n * boundaries are unambiguous and cannot collide with a different split\n * of the same characters.\n *\n * The canonical string is then piped through `hashContent` to produce a\n * bounded, opaque digest. See `@prisma-next/utils/hash-content` for the\n * rationale.\n *\n * @throws {RuntimeErrorEnvelope} {@link RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND}\n * when `exec.command` is still a pre-resolve draft (plain object), e.g. when\n * `contentHash` is called from `beforeExecute`.\n *\n * @internal\n */\nexport function computeMongoContentHash(exec: MongoExecutionPlan): Promise<string> {\n assertContentHashOnResolvedCommand(exec.command);\n return hashContent(\n canonicalStringify({\n storageHash: exec.meta.storageHash,\n command: { ...exec.command },\n }),\n );\n}\n","import type { ParamRefMutator } from '@prisma-next/framework-components/runtime';\nimport type { MongoLoweredDraft } from '@prisma-next/mongo-lowering';\nimport { MongoParamRef } from '@prisma-next/mongo-value';\nimport { blindCast } from '@prisma-next/utils/casts';\n\n/**\n * Phantom brand on {@link MongoParamRefHandle} so handles produced by\n * {@link MongoParamRefMutator.entries} are distinguishable at the type level\n * from user-constructed `MongoParamRef` instances. There is no runtime token —\n * the handle IS the underlying `MongoParamRef` instance, cast through the brand.\n */\ndeclare const mongoParamRefHandleBrand: unique symbol;\n\n/**\n * Opaque token identifying a single `MongoParamRef` in the draft tree.\n * Produced by {@link MongoParamRefMutator.entries}; consumed by\n * `replaceValue` / `replaceValues`. The `TCodecId` phantom parameter\n * records the codec id so typed overloads can route replacement values\n * through a `TCodecMap`.\n */\nexport interface MongoParamRefHandle<TCodecId extends string | undefined = string | undefined> {\n readonly [mongoParamRefHandleBrand]: TCodecId;\n}\n\n/**\n * One outbound `MongoParamRef` slot in the draft exposed to middleware.\n * `value` is the current effective value (post any prior mutations);\n * `codecId` is the codec id declared on the underlying `MongoParamRef`.\n */\nexport interface MongoParamRefEntry<TCodecId extends string | undefined = string | undefined> {\n readonly ref: MongoParamRefHandle<TCodecId>;\n readonly value: unknown;\n readonly codecId: TCodecId;\n}\n\n/**\n * Discriminated entry union over a codec map. For each `K` in `TCodecMap`,\n * `entries()` may yield a `MongoParamRefEntry<K>`; refs with no codec id (or\n * an unrecognised codec id) yield `MongoParamRefEntry<undefined>`. Pattern-\n * matching on `entry.codecId` narrows `entry.ref` to `MongoParamRefHandle<K>`.\n */\nexport type MongoParamRefEntryUnion<TCodecMap extends Record<string, unknown>> =\n | { [K in keyof TCodecMap & string]: MongoParamRefEntry<K> }[keyof TCodecMap & string]\n | MongoParamRefEntry<undefined>;\n\n/**\n * Mongo-family mutator threaded into `MongoMiddleware.beforeExecute` as\n * `params`. Scope is `MongoParamRef.value` slots only — middleware cannot\n * insert or remove refs, rewrite the filter shape, or modify the pipeline\n * structure. The phantom `MongoParamRefHandle` brand and the typed\n * `replaceValue` overload enforce this at compile time.\n *\n * `entries()` performs a flat walk over the `MongoLoweredDraft` tree via\n * {@link flattenMongoParamRefs}, yielding every `MongoParamRef` leaf in\n * document fields, array elements, filter predicates, update operators, and\n * pipeline stages. The walk matches `resolveDraftSlot` in the Mongo adapter\n * (plain-object and array slots only; `Date` and other non-plain objects are\n * leaves in both paths).\n *\n * Allocation discipline: the working-overrides map is only allocated on the\n * first `replaceValue` / `replaceValues` call. If no middleware mutates,\n * `currentDraft()` returns the original draft by reference identity without\n * allocating a new tree (the AC-MUT5 fast path).\n */\nexport interface MongoParamRefMutator<\n TCodecMap extends Record<string, unknown> = Record<string, unknown>,\n> extends ParamRefMutator {\n entries(): IterableIterator<MongoParamRefEntryUnion<TCodecMap>>;\n\n replaceValue<TCodecId extends keyof TCodecMap & string>(\n ref: MongoParamRefHandle<TCodecId>,\n newValue: TCodecMap[TCodecId],\n ): void;\n replaceValue(ref: MongoParamRefHandle<undefined>, newValue: unknown): void;\n\n replaceValues(\n updates: Iterable<{\n readonly ref: MongoParamRefHandle<(keyof TCodecMap & string) | undefined>;\n readonly newValue: unknown;\n }>,\n ): void;\n}\n\n/**\n * Internal-only view that exposes `currentDraft()` to the Mongo runtime.\n * The runtime calls this after the `beforeExecute` chain; the result is the\n * original draft by reference if nothing was mutated, otherwise a new tree\n * with the mutations applied. `MongoMiddleware` consumers never see this\n * shape; they receive the public `MongoParamRefMutator` view.\n */\nexport interface MongoParamRefMutatorInternal<\n TCodecMap extends Record<string, unknown> = Record<string, unknown>,\n> extends MongoParamRefMutator<TCodecMap> {\n currentDraft(): MongoLoweredDraft;\n}\n\ntype AnyMongoHandle = MongoParamRefHandle<string | undefined>;\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n// ─── Internal tree-walk helpers ────────────────────────────────────────────\n// Descent mirrors resolveDraftSlot in adapter-mongo/resolve-value.ts: recurse\n// arrays and plain records; treat MongoParamRef, primitives, Date, and other\n// non-plain objects as leaves.\n\nfunction* flattenDraftSlot(value: unknown): Generator<MongoParamRef> {\n if (value instanceof MongoParamRef) {\n yield value;\n return;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n yield* flattenDraftSlot(item);\n }\n return;\n }\n if (isPlainRecord(value)) {\n for (const v of Object.values(value)) {\n yield* flattenDraftSlot(v);\n }\n }\n}\n\n/**\n * Flat walk over a `MongoLoweredDraft` yielding every `MongoParamRef` leaf\n * regardless of nesting — object values, array elements, filter predicate\n * values, update operator values, and pipeline stage values. Raw command\n * variants carry no `MongoParamRef` nodes so they yield zero entries.\n *\n * **Walk parity:** slot traversal matches `resolveDraftSlot` / `resolveParams`\n * — refs appear only in plain-object and array containers; `Date` and other\n * non-plain objects are leaves (not descended into), so middleware sees every\n * ref the resolve pass will encode.\n */\nexport function* flattenMongoParamRefs(draft: MongoLoweredDraft): Generator<MongoParamRef> {\n switch (draft.kind) {\n case 'insertOne':\n case 'rawInsertOne':\n yield* flattenDraftSlot(draft.document);\n break;\n case 'insertMany':\n case 'rawInsertMany':\n for (const doc of draft.documents) {\n yield* flattenDraftSlot(doc);\n }\n break;\n case 'updateOne':\n case 'updateMany':\n case 'rawUpdateOne':\n case 'rawUpdateMany':\n yield* flattenDraftSlot(draft.filter);\n yield* flattenDraftSlot(draft.update);\n break;\n case 'findOneAndUpdate':\n case 'rawFindOneAndUpdate':\n yield* flattenDraftSlot(draft.filter);\n yield* flattenDraftSlot(draft.update);\n break;\n case 'deleteOne':\n case 'deleteMany':\n case 'rawDeleteOne':\n case 'rawDeleteMany':\n yield* flattenDraftSlot(draft.filter);\n break;\n case 'findOneAndDelete':\n case 'rawFindOneAndDelete':\n yield* flattenDraftSlot(draft.filter);\n break;\n case 'aggregate':\n case 'rawAggregate':\n for (const stage of draft.pipeline) {\n yield* flattenDraftSlot(stage);\n }\n break;\n }\n}\n\n// ─── Draft reconstruction for the mutated path ─────────────────────────────\n\nfunction substituteSlot(value: unknown, overrides: ReadonlyMap<MongoParamRef, unknown>): unknown {\n if (value instanceof MongoParamRef) {\n if (overrides.has(value)) {\n const opts: { name?: string; codecId?: string } = {};\n if (value.name !== undefined) opts.name = value.name;\n if (value.codecId !== undefined) opts.codecId = value.codecId;\n return new MongoParamRef(overrides.get(value), opts);\n }\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((item) => substituteSlot(item, overrides));\n }\n if (isPlainRecord(value)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n out[k] = substituteSlot(v, overrides);\n }\n return out;\n }\n return value;\n}\n\nfunction substituteDoc(\n doc: Record<string, unknown>,\n overrides: ReadonlyMap<MongoParamRef, unknown>,\n): Record<string, unknown> {\n return blindCast<\n Record<string, unknown>,\n 'substituteSlot preserves plain-object shape for document inputs'\n >(substituteSlot(doc, overrides));\n}\n\nfunction isUpdatePipeline(\n update: Record<string, unknown> | ReadonlyArray<Record<string, unknown>>,\n): update is ReadonlyArray<Record<string, unknown>> {\n return Array.isArray(update);\n}\n\nfunction substituteUpdate(\n update: Record<string, unknown> | ReadonlyArray<Record<string, unknown>>,\n overrides: ReadonlyMap<MongoParamRef, unknown>,\n): Record<string, unknown> | Array<Record<string, unknown>> {\n if (isUpdatePipeline(update)) {\n return update.map((stage) => substituteDoc(stage, overrides));\n }\n return substituteDoc(update, overrides);\n}\n\nfunction buildMutatedDraft(\n draft: MongoLoweredDraft,\n overrides: ReadonlyMap<MongoParamRef, unknown>,\n): MongoLoweredDraft {\n switch (draft.kind) {\n case 'insertOne':\n return {\n kind: 'insertOne',\n collection: draft.collection,\n document: substituteDoc(draft.document, overrides),\n };\n case 'rawInsertOne':\n return {\n kind: 'rawInsertOne',\n collection: draft.collection,\n document: substituteDoc(draft.document, overrides),\n };\n case 'insertMany':\n return {\n kind: 'insertMany',\n collection: draft.collection,\n documents: draft.documents.map((d) => substituteDoc(d, overrides)),\n };\n case 'rawInsertMany':\n return {\n kind: 'rawInsertMany',\n collection: draft.collection,\n documents: draft.documents.map((d) => substituteDoc(d, overrides)),\n };\n case 'updateOne':\n return {\n kind: 'updateOne',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n upsert: draft.upsert,\n };\n case 'updateMany':\n return {\n kind: 'updateMany',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n upsert: draft.upsert,\n };\n case 'rawUpdateOne':\n return {\n kind: 'rawUpdateOne',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n };\n case 'rawUpdateMany':\n return {\n kind: 'rawUpdateMany',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n };\n case 'deleteOne':\n return {\n kind: 'deleteOne',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n };\n case 'deleteMany':\n return {\n kind: 'deleteMany',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n };\n case 'rawDeleteOne':\n return {\n kind: 'rawDeleteOne',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n };\n case 'rawDeleteMany':\n return {\n kind: 'rawDeleteMany',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n };\n case 'findOneAndUpdate':\n return {\n kind: 'findOneAndUpdate',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n upsert: draft.upsert,\n sort: draft.sort,\n returnDocument: draft.returnDocument,\n };\n case 'rawFindOneAndUpdate':\n return {\n kind: 'rawFindOneAndUpdate',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n update: substituteUpdate(draft.update, overrides),\n upsert: draft.upsert,\n sort: draft.sort,\n returnDocument: draft.returnDocument,\n };\n case 'findOneAndDelete':\n return {\n kind: 'findOneAndDelete',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n sort: draft.sort,\n };\n case 'rawFindOneAndDelete':\n return {\n kind: 'rawFindOneAndDelete',\n collection: draft.collection,\n filter: substituteDoc(draft.filter, overrides),\n sort: draft.sort,\n };\n case 'aggregate':\n return {\n kind: 'aggregate',\n collection: draft.collection,\n pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides)),\n };\n case 'rawAggregate':\n return {\n kind: 'rawAggregate',\n collection: draft.collection,\n pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides)),\n };\n }\n}\n\n// ─── Factory ────────────────────────────────────────────────────────────────\n\n/**\n * Build a {@link MongoParamRefMutatorInternal} for the given lowered draft.\n *\n * The mutator captures the draft by reference and uses `flattenMongoParamRefs`\n * on demand to produce `entries()`. Replacements are stored in a lazily-\n * allocated `Map`; the fast path (no replacements) preserves bit-for-bit\n * reference identity to the original draft in `currentDraft()`.\n */\nexport function createMongoParamRefMutator<\n TCodecMap extends Record<string, unknown> = Record<string, unknown>,\n>(draft: MongoLoweredDraft): MongoParamRefMutatorInternal<TCodecMap> {\n const originalDraft = draft;\n let overrides: Map<MongoParamRef, unknown> | undefined;\n\n const ensureOverrides = (): Map<MongoParamRef, unknown> => {\n if (!overrides) {\n overrides = new Map();\n }\n return overrides;\n };\n\n function* entries(): IterableIterator<MongoParamRefEntryUnion<TCodecMap>> {\n for (const ref of flattenMongoParamRefs(originalDraft)) {\n const handle = blindCast<\n MongoParamRefHandle<string | undefined>,\n 'MongoParamRef instance is the runtime handle token'\n >(ref);\n const value = overrides?.has(ref) ? overrides.get(ref) : ref.value;\n const codecId: string | undefined = ref.codecId;\n const entry: MongoParamRefEntry<string | undefined> = { ref: handle, value, codecId };\n yield blindCast<\n MongoParamRefEntryUnion<TCodecMap>,\n 'entry codecId widened to TCodecMap union'\n >(entry);\n }\n }\n\n function replaceValue(handle: AnyMongoHandle, newValue: unknown): void {\n ensureOverrides().set(\n blindCast<MongoParamRef, 'MongoParamRefHandle brand is the underlying ref instance'>(handle),\n newValue,\n );\n }\n\n function replaceValues(\n updates: Iterable<{ readonly ref: AnyMongoHandle; readonly newValue: unknown }>,\n ): void {\n const map = ensureOverrides();\n for (const { ref, newValue } of updates) {\n map.set(\n blindCast<MongoParamRef, 'MongoParamRefHandle brand is the underlying ref instance'>(ref),\n newValue,\n );\n }\n }\n\n return {\n entries,\n replaceValue: blindCast<\n MongoParamRefMutator<TCodecMap>['replaceValue'],\n 'replaceValue overloads are enforced at the interface; implementation accepts AnyMongoHandle'\n >(replaceValue),\n replaceValues,\n currentDraft(): MongoLoweredDraft {\n if (!overrides || overrides.size === 0) {\n return originalDraft;\n }\n return buildMutatedDraft(originalDraft, overrides);\n },\n };\n}\n","import type { CodecCallContext } from '@prisma-next/framework-components/codec';\nimport {\n AsyncIterableResult,\n checkAborted,\n checkMiddlewareCompatibility,\n RuntimeCore,\n type RuntimeExecuteOptions,\n type RuntimeMiddlewareContext,\n runBeforeExecuteChain,\n runWithMiddleware,\n} from '@prisma-next/framework-components/runtime';\nimport type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';\nimport type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { decodeMongoRow } from './codecs/decoding';\nimport { computeMongoContentHash } from './content-hash';\nimport type { MongoExecutionPlan } from './mongo-execution-plan';\nimport type { MongoCodecLookup, MongoExecutionContext } from './mongo-execution-stack';\nimport type { MongoMiddleware, MongoMiddlewareContext } from './mongo-middleware';\nimport {\n createMongoParamRefMutator,\n type MongoParamRefMutator,\n type MongoParamRefMutatorInternal,\n} from './param-ref-mutator';\n\nfunction noop() {}\n\n/**\n * Mongo runtime options.\n *\n * The runtime takes a {@link MongoExecutionContext} (built via\n * `createMongoExecutionContext`) and a driver. Codec resolution flows from\n * the context — there is no `codecs` field on this options bag. The adapter\n * is reached via `context.stack.adapter` (instantiated lazily through the\n * stack's `create(stack)` factory). See ADR — Mongo result-shape as a\n * structural plan field, § Codec registry: stack aggregation, not user\n * threading.\n */\nexport interface MongoRuntimeOptions {\n readonly context: MongoExecutionContext;\n readonly driver: MongoDriver;\n readonly middleware?: readonly MongoMiddleware[];\n readonly mode?: 'strict' | 'permissive';\n}\n\nexport interface MongoRuntime {\n /**\n * Execute a `MongoQueryPlan` and return an async iterable of rows.\n *\n * The optional `options.signal` is threaded through\n * `lower → adapter.lower → resolveValue → codec.encode` so codec authors\n * who forward the signal to their underlying SDK get true cancellation\n * of in-flight network calls. The runtime additionally observes the\n * signal at two boundaries:\n *\n * - **Already-aborted at entry** — first `next()` throws\n * `RUNTIME.ABORTED { phase: 'stream' }` before any work is done.\n * (Inherited from `RuntimeCore.execute`.)\n * - **Mid-encode abort** — surfaces as\n * `RUNTIME.ABORTED { phase: 'encode' }` from inside `resolveValue`'s\n * per-level `Promise.all` race.\n *\n * Mongo's read path decodes rows via `resultShape` (per ADR 209). The\n * same `CodecCallContext` is forwarded into each `codec.decode(wire, ctx)`\n * call, so async decoders that respect the signal get cancellation; the\n * runtime itself does not currently emit a `phase: 'decode'` envelope.\n */\n execute<Row>(\n plan: MongoQueryPlan<Row>,\n options?: RuntimeExecuteOptions,\n ): AsyncIterableResult<Row>;\n close(): Promise<void>;\n}\n\nclass MongoRuntimeImpl\n extends RuntimeCore<MongoQueryPlan, MongoExecutionPlan, MongoMiddleware>\n implements MongoRuntime\n{\n readonly #adapter: MongoAdapter;\n readonly #driver: MongoDriver;\n readonly #codecs: MongoCodecLookup;\n\n constructor(options: MongoRuntimeOptions) {\n const middleware = options.middleware ? [...options.middleware] : [];\n const targetId = options.context.stack.target.targetId;\n for (const mw of middleware) {\n checkMiddlewareCompatibility(mw, 'mongo', targetId);\n }\n\n const ctx: MongoMiddlewareContext = {\n contract: options.context.contract,\n mode: options.mode ?? 'strict',\n now: () => Date.now(),\n log: { info: noop, warn: noop, error: noop },\n // ctx is only invoked by runWithMiddleware with execs this runtime lowered;\n // the framework parameter type is the cross-family base.\n contentHash: (exec) =>\n computeMongoContentHash(\n blindCast<MongoExecutionPlan, 'runWithMiddleware passes execs this runtime lowered'>(\n exec,\n ),\n ),\n // When MongoRuntimeImpl grows connection()/transaction() surfaces,\n // derive a scope-narrowed ctx per call (mirror\n // SqlRuntimeImpl#executeAgainstQueryable in `sql-runtime.ts`).\n scope: 'runtime',\n // Placeholder satisfying the required field on the cross-family base. The\n // stored ctx is a runtime-level template; the per-execute ctx constructed\n // in `execute()` spreads this template and overrides `planExecutionId`\n // with a fresh UUID. ADR 220.\n planExecutionId: '',\n };\n\n super({ middleware, ctx });\n\n const adapterDescriptor = options.context.stack.adapter;\n const adapterInstance = adapterDescriptor.create(options.context.stack);\n this.#adapter = adapterInstance;\n this.#driver = options.driver;\n this.#codecs = options.context.codecs;\n }\n\n /* v8 ignore start -- one-phase lower satisfies RuntimeCore; execute uses structuralLower + resolveParams */\n protected override async lower(\n plan: MongoQueryPlan,\n ctx: CodecCallContext,\n ): Promise<MongoExecutionPlan> {\n return {\n command: await this.#adapter.lower(plan, ctx),\n meta: plan.meta,\n ...ifDefined('resultShape', plan.resultShape),\n };\n }\n /* v8 ignore stop */\n\n protected override runDriver(exec: MongoExecutionPlan): AsyncIterable<Record<string, unknown>> {\n return this.#driver.execute<Record<string, unknown>>(exec.command);\n }\n\n override execute<Row>(\n plan: MongoQueryPlan & { readonly _row?: Row },\n options?: RuntimeExecuteOptions,\n ): AsyncIterableResult<Row> {\n const self = this;\n const signal = options?.signal;\n const codecCtx: CodecCallContext = signal === undefined ? {} : { signal };\n\n // Per-execute middleware context. Spread the stored runtime-level\n // template and mint a fresh `planExecutionId` so every hook in this\n // call observes the same value, and two executions of the same plan\n // observe distinct values. ADR 220. The plan itself flows through\n // unchanged.\n const execCtx: RuntimeMiddlewareContext = {\n ...self.ctx,\n planExecutionId: crypto.randomUUID(),\n };\n\n const generator = async function* (): AsyncGenerator<Row, void, unknown> {\n checkAborted(codecCtx, 'stream');\n const compiled = await self.runBeforeCompile(plan);\n\n // Phase 1: structural lower — transforms the AST but leaves MongoParamRef\n // nodes in place so middleware can inspect and rewrite them before\n // codec resolution.\n const draft = self.#adapter.structuralLower(compiled);\n const mutator: MongoParamRefMutatorInternal = createMongoParamRefMutator(draft);\n\n // Build the plan view for the beforeExecute chain. Middleware accesses\n // plan.meta and the mutator's entries(); plan.command carries the\n // unresolved draft at this stage.\n // The cast is necessary because MongoExecutionPlan.command is typed as\n // AnyMongoWireCommand (the post-resolution shape). No beforeExecute\n // middleware reads plan.command structurally — params are observed via\n // the mutator's entries(). The cast is narrowed to the command slot\n // only so no whole-object information is lost.\n const draftExec: MongoExecutionPlan = {\n meta: compiled.meta,\n ...ifDefined('resultShape', compiled.resultShape),\n command: blindCast<\n MongoExecutionPlan['command'],\n 'MongoLoweredDraft held in command slot for the beforeExecute view; resolveParams runs after the chain'\n >(draft),\n };\n\n await runBeforeExecuteChain<MongoExecutionPlan, MongoParamRefMutator>(\n draftExec,\n self.middleware,\n execCtx,\n mutator,\n );\n\n // Phase 2: resolve params — converts the (possibly mutated) draft into\n // a frozen wire command. currentDraft() returns the original draft by\n // reference when no middleware called replaceValue/replaceValues (fast path).\n const resolvedCommand = await self.#adapter.resolveParams(mutator.currentDraft(), codecCtx);\n const exec: MongoExecutionPlan = {\n meta: compiled.meta,\n ...ifDefined('resultShape', compiled.resultShape),\n command: resolvedCommand,\n };\n\n // Phase 3: driver pipeline — runWithMiddleware and decodeMongoRow both\n // receive the fully resolved exec. computeMongoContentHash (called via\n // ctx.contentHash during intercept/afterExecute) therefore hashes the\n // resolved command; no MongoParamRef instance reaches canonicalStringify.\n const stream = runWithMiddleware<MongoExecutionPlan, Record<string, unknown>>(\n exec,\n self.middleware,\n execCtx,\n () => self.runDriver(exec),\n );\n for await (const rawRow of stream) {\n if (exec.resultShape === undefined) {\n yield blindCast<Row, 'driver row matches plan _row phantom when resultShape is absent'>(\n rawRow,\n );\n } else {\n // Source the collection from the lowered exec rather than the\n // pre-lowering plan: a runBeforeCompile middleware is allowed to\n // rewrite collection names during compilation, and the wire command\n // carried by exec is always authoritative for what just ran.\n const decoded = await decodeMongoRow(\n rawRow,\n exec.resultShape,\n self.#codecs,\n exec.command.collection,\n codecCtx,\n );\n yield blindCast<Row, 'decodeMongoRow output matches plan _row phantom'>(decoded);\n }\n }\n };\n return new AsyncIterableResult(generator());\n }\n\n override async close(): Promise<void> {\n await this.#driver.close();\n }\n}\n\nexport function createMongoRuntime(options: MongoRuntimeOptions): MongoRuntime {\n return new MongoRuntimeImpl(options);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,45 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/mongo-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "MongoDB runtime implementation for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/contract": "0.
|
|
10
|
-
"@prisma-next/framework-components": "0.
|
|
11
|
-
"@prisma-next/mongo-codec": "0.
|
|
12
|
-
"@prisma-next/mongo-lowering": "0.
|
|
13
|
-
"@prisma-next/mongo-query-ast": "0.
|
|
14
|
-
"@prisma-next/mongo-
|
|
15
|
-
"@prisma-next/
|
|
9
|
+
"@prisma-next/contract": "0.12.0",
|
|
10
|
+
"@prisma-next/framework-components": "0.12.0",
|
|
11
|
+
"@prisma-next/mongo-codec": "0.12.0",
|
|
12
|
+
"@prisma-next/mongo-lowering": "0.12.0",
|
|
13
|
+
"@prisma-next/mongo-query-ast": "0.12.0",
|
|
14
|
+
"@prisma-next/mongo-value": "0.12.0",
|
|
15
|
+
"@prisma-next/mongo-wire": "0.12.0",
|
|
16
|
+
"@prisma-next/utils": "0.12.0"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
|
-
"@prisma-next/adapter-mongo": "0.
|
|
19
|
-
"@prisma-next/driver-mongo": "0.
|
|
20
|
-
"@prisma-next/family-mongo": "0.
|
|
21
|
-
"@prisma-next/mongo-contract": "0.
|
|
22
|
-
"@prisma-next/mongo-query-builder": "0.
|
|
23
|
-
"@prisma-next/mongo
|
|
24
|
-
"@prisma-next/
|
|
25
|
-
"@prisma-next/
|
|
26
|
-
"@prisma-next/
|
|
27
|
-
"
|
|
28
|
-
"mongodb": "^6.16.0",
|
|
19
|
+
"@prisma-next/adapter-mongo": "0.12.0",
|
|
20
|
+
"@prisma-next/driver-mongo": "0.12.0",
|
|
21
|
+
"@prisma-next/family-mongo": "0.12.0",
|
|
22
|
+
"@prisma-next/mongo-contract": "0.12.0",
|
|
23
|
+
"@prisma-next/mongo-query-builder": "0.12.0",
|
|
24
|
+
"@prisma-next/target-mongo": "0.12.0",
|
|
25
|
+
"@prisma-next/test-utils": "0.12.0",
|
|
26
|
+
"@prisma-next/tsconfig": "0.12.0",
|
|
27
|
+
"@prisma-next/tsdown": "0.12.0",
|
|
28
|
+
"mongodb": "^7.2.0",
|
|
29
29
|
"mongodb-memory-server": "11.1.0",
|
|
30
30
|
"tsdown": "0.22.0",
|
|
31
31
|
"typescript": "5.9.3",
|
|
32
32
|
"vitest": "4.1.6"
|
|
33
33
|
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"typescript": ">=5.9"
|
|
36
|
+
},
|
|
37
|
+
"peerDependenciesMeta": {
|
|
38
|
+
"typescript": {
|
|
39
|
+
"optional": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
34
42
|
"files": [
|
|
35
43
|
"dist",
|
|
36
44
|
"src"
|
|
37
45
|
],
|
|
46
|
+
"types": "./dist/index.d.mts",
|
|
38
47
|
"exports": {
|
|
39
48
|
".": "./dist/index.mjs",
|
|
40
49
|
"./package.json": "./package.json"
|
|
41
50
|
},
|
|
42
|
-
"
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=24"
|
|
53
|
+
},
|
|
43
54
|
"repository": {
|
|
44
55
|
"type": "git",
|
|
45
56
|
"url": "https://github.com/prisma/prisma-next.git",
|
package/src/content-hash.ts
CHANGED
|
@@ -1,7 +1,36 @@
|
|
|
1
|
+
import { runtimeError } from '@prisma-next/framework-components/runtime';
|
|
1
2
|
import { canonicalStringify } from '@prisma-next/utils/canonical-stringify';
|
|
2
3
|
import { hashContent } from '@prisma-next/utils/hash-content';
|
|
3
4
|
import type { MongoExecutionPlan } from './mongo-execution-plan';
|
|
4
5
|
|
|
6
|
+
/** @internal */
|
|
7
|
+
export const RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND =
|
|
8
|
+
'RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND' as const;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolved wire commands are frozen class instances (`InsertOneWireCommand`, …);
|
|
12
|
+
* pre-resolve `beforeExecute` plans hold a plain-object `MongoLoweredDraft` in the
|
|
13
|
+
* command slot. O(1) prototype check — no tree walk on the hot path.
|
|
14
|
+
*/
|
|
15
|
+
function isResolvedMongoWireCommand(command: unknown): boolean {
|
|
16
|
+
if (command === null || typeof command !== 'object') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const proto = Object.getPrototypeOf(command);
|
|
20
|
+
return proto !== null && proto !== Object.prototype;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function assertContentHashOnResolvedCommand(command: unknown): void {
|
|
24
|
+
if (isResolvedMongoWireCommand(command)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
throw runtimeError(
|
|
28
|
+
RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND,
|
|
29
|
+
'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.',
|
|
30
|
+
{ phase: 'beforeExecute' },
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
5
34
|
/**
|
|
6
35
|
* Computes a stable content hash for a lowered Mongo execution plan.
|
|
7
36
|
*
|
|
@@ -36,14 +65,14 @@ import type { MongoExecutionPlan } from './mongo-execution-plan';
|
|
|
36
65
|
* bounded, opaque digest. See `@prisma-next/utils/hash-content` for the
|
|
37
66
|
* rationale.
|
|
38
67
|
*
|
|
68
|
+
* @throws {RuntimeErrorEnvelope} {@link RUNTIME_CONTENT_HASH_REQUIRES_RESOLVED_COMMAND}
|
|
69
|
+
* when `exec.command` is still a pre-resolve draft (plain object), e.g. when
|
|
70
|
+
* `contentHash` is called from `beforeExecute`.
|
|
71
|
+
*
|
|
39
72
|
* @internal
|
|
40
73
|
*/
|
|
41
74
|
export function computeMongoContentHash(exec: MongoExecutionPlan): Promise<string> {
|
|
42
|
-
|
|
43
|
-
// rejects class instances by design (so `Map`/`Set`/class instances
|
|
44
|
-
// cannot collapse to `{}` and silently collide). All wire-command
|
|
45
|
-
// data lives on own enumerable properties, so this preserves the
|
|
46
|
-
// same canonical form and therefore the same hash.
|
|
75
|
+
assertContentHashOnResolvedCommand(exec.command);
|
|
47
76
|
return hashContent(
|
|
48
77
|
canonicalStringify({
|
|
49
78
|
storageHash: exec.meta.storageHash,
|
package/src/exports/index.ts
CHANGED
|
@@ -18,3 +18,14 @@ export {
|
|
|
18
18
|
export type { MongoMiddleware, MongoMiddlewareContext } from '../mongo-middleware';
|
|
19
19
|
export type { MongoRuntime, MongoRuntimeOptions } from '../mongo-runtime';
|
|
20
20
|
export { createMongoRuntime } from '../mongo-runtime';
|
|
21
|
+
export type {
|
|
22
|
+
MongoParamRefEntry,
|
|
23
|
+
MongoParamRefEntryUnion,
|
|
24
|
+
MongoParamRefHandle,
|
|
25
|
+
MongoParamRefMutator,
|
|
26
|
+
MongoParamRefMutatorInternal,
|
|
27
|
+
} from '../param-ref-mutator';
|
|
28
|
+
export {
|
|
29
|
+
createMongoParamRefMutator,
|
|
30
|
+
flattenMongoParamRefs,
|
|
31
|
+
} from '../param-ref-mutator';
|
|
@@ -7,8 +7,8 @@ import type { AnyMongoWireCommand } from '@prisma-next/mongo-wire';
|
|
|
7
7
|
* that a Mongo driver can run.
|
|
8
8
|
*
|
|
9
9
|
* The plan carries:
|
|
10
|
-
* - `command` —
|
|
11
|
-
* `
|
|
10
|
+
* - `command` — dual lifecycle (see field JSDoc): unresolved draft during
|
|
11
|
+
* `beforeExecute`, frozen wire command afterward
|
|
12
12
|
* - `meta` — family-agnostic plan metadata (target, lane, hashes, ...)
|
|
13
13
|
* - `_row` — phantom row type, propagated from the originating
|
|
14
14
|
* `MongoQueryPlan`
|
|
@@ -23,6 +23,14 @@ import type { AnyMongoWireCommand } from '@prisma-next/mongo-wire';
|
|
|
23
23
|
* cannot depend on.
|
|
24
24
|
*/
|
|
25
25
|
export interface MongoExecutionPlan<Row = unknown> extends ExecutionPlan<Row> {
|
|
26
|
+
/**
|
|
27
|
+
* Lowered command payload. **Lifecycle:** during `beforeExecute` this slot
|
|
28
|
+
* holds the unresolved `MongoLoweredDraft` (plain object, `MongoParamRef`
|
|
29
|
+
* leaves intact). After `resolveParams` and in later middleware hooks
|
|
30
|
+
* (`afterExecute`, `onRow`, intercept-after-resolve) it is the frozen wire
|
|
31
|
+
* command (`InsertOneWireCommand`, `AggregateWireCommand`, …). Do not read
|
|
32
|
+
* `command` structurally in `beforeExecute` — use the `params` mutator.
|
|
33
|
+
*/
|
|
26
34
|
readonly command: AnyMongoWireCommand;
|
|
27
35
|
readonly resultShape?: MongoResultShape;
|
|
28
36
|
}
|
package/src/mongo-middleware.ts
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AfterExecuteResult,
|
|
3
|
-
ParamRefMutator,
|
|
4
3
|
RuntimeMiddleware,
|
|
5
4
|
RuntimeMiddlewareContext,
|
|
6
5
|
} from '@prisma-next/framework-components/runtime';
|
|
7
6
|
import type { MongoExecutionPlan } from './mongo-execution-plan';
|
|
7
|
+
import type { MongoParamRefMutator } from './param-ref-mutator';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Per-execute middleware context for Mongo. See {@link MongoMiddleware} for
|
|
11
|
+
* plan/command lifecycle during `beforeExecute` vs later hooks.
|
|
12
|
+
*/
|
|
13
|
+
export interface MongoMiddlewareContext extends RuntimeMiddlewareContext {
|
|
14
|
+
/**
|
|
15
|
+
* Stable digest of `meta.storageHash` plus the **resolved** wire command.
|
|
16
|
+
* Valid only on post-resolution plans (typically `afterExecute` or intercept
|
|
17
|
+
* after `resolveParams`). Calling this from `beforeExecute` throws
|
|
18
|
+
* `RUNTIME.CONTENT_HASH_REQUIRES_RESOLVED_COMMAND` because `plan.command`
|
|
19
|
+
* is still an unresolved draft at that point.
|
|
20
|
+
*/
|
|
21
|
+
contentHash(exec: MongoExecutionPlan): Promise<string>;
|
|
22
|
+
}
|
|
10
23
|
|
|
11
24
|
/**
|
|
12
25
|
* Mongo-domain middleware. Extends the framework `RuntimeMiddleware`
|
|
@@ -18,13 +31,24 @@ export interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
|
|
|
18
31
|
* telemetry) — which carry no `familyId` — remain assignable. When
|
|
19
32
|
* present, it must be `'mongo'`; the runtime rejects mismatches at
|
|
20
33
|
* construction time via `checkMiddlewareCompatibility`.
|
|
34
|
+
*
|
|
35
|
+
* **Pre-resolve `beforeExecute` contract:** `plan.command` holds the
|
|
36
|
+
* unresolved `MongoLoweredDraft`, not a wire command. Observe and mutate
|
|
37
|
+
* parameters via `params.entries()` / `replaceValue` / `replaceValues` only.
|
|
38
|
+
* Do not inspect `plan.command` structurally or call `ctx.contentHash` in
|
|
39
|
+
* this hook. After the chain, `resolveParams` produces the frozen wire
|
|
40
|
+
* command used in `afterExecute` and for `contentHash`.
|
|
21
41
|
*/
|
|
22
42
|
export interface MongoMiddleware extends RuntimeMiddleware<MongoExecutionPlan> {
|
|
23
43
|
readonly familyId?: 'mongo';
|
|
44
|
+
/**
|
|
45
|
+
* Runs after structural lower, before `resolveParams`. `plan.command` is the
|
|
46
|
+
* unresolved draft; use `params` for param-ref access, not `plan.command`.
|
|
47
|
+
*/
|
|
24
48
|
beforeExecute?(
|
|
25
49
|
plan: MongoExecutionPlan,
|
|
26
50
|
ctx: MongoMiddlewareContext,
|
|
27
|
-
params?:
|
|
51
|
+
params?: MongoParamRefMutator,
|
|
28
52
|
): void | Promise<void>;
|
|
29
53
|
onRow?(
|
|
30
54
|
row: Record<string, unknown>,
|
package/src/mongo-runtime.ts
CHANGED
|
@@ -5,17 +5,24 @@ import {
|
|
|
5
5
|
checkMiddlewareCompatibility,
|
|
6
6
|
RuntimeCore,
|
|
7
7
|
type RuntimeExecuteOptions,
|
|
8
|
+
type RuntimeMiddlewareContext,
|
|
8
9
|
runBeforeExecuteChain,
|
|
9
10
|
runWithMiddleware,
|
|
10
11
|
} from '@prisma-next/framework-components/runtime';
|
|
11
12
|
import type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';
|
|
12
13
|
import type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
|
|
14
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
13
15
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
14
16
|
import { decodeMongoRow } from './codecs/decoding';
|
|
15
17
|
import { computeMongoContentHash } from './content-hash';
|
|
16
18
|
import type { MongoExecutionPlan } from './mongo-execution-plan';
|
|
17
19
|
import type { MongoCodecLookup, MongoExecutionContext } from './mongo-execution-stack';
|
|
18
20
|
import type { MongoMiddleware, MongoMiddlewareContext } from './mongo-middleware';
|
|
21
|
+
import {
|
|
22
|
+
createMongoParamRefMutator,
|
|
23
|
+
type MongoParamRefMutator,
|
|
24
|
+
type MongoParamRefMutatorInternal,
|
|
25
|
+
} from './param-ref-mutator';
|
|
19
26
|
|
|
20
27
|
function noop() {}
|
|
21
28
|
|
|
@@ -88,11 +95,21 @@ class MongoRuntimeImpl
|
|
|
88
95
|
log: { info: noop, warn: noop, error: noop },
|
|
89
96
|
// ctx is only invoked by runWithMiddleware with execs this runtime lowered;
|
|
90
97
|
// the framework parameter type is the cross-family base.
|
|
91
|
-
contentHash: (exec) =>
|
|
98
|
+
contentHash: (exec) =>
|
|
99
|
+
computeMongoContentHash(
|
|
100
|
+
blindCast<MongoExecutionPlan, 'runWithMiddleware passes execs this runtime lowered'>(
|
|
101
|
+
exec,
|
|
102
|
+
),
|
|
103
|
+
),
|
|
92
104
|
// When MongoRuntimeImpl grows connection()/transaction() surfaces,
|
|
93
105
|
// derive a scope-narrowed ctx per call (mirror
|
|
94
106
|
// SqlRuntimeImpl#executeAgainstQueryable in `sql-runtime.ts`).
|
|
95
107
|
scope: 'runtime',
|
|
108
|
+
// Placeholder satisfying the required field on the cross-family base. The
|
|
109
|
+
// stored ctx is a runtime-level template; the per-execute ctx constructed
|
|
110
|
+
// in `execute()` spreads this template and overrides `planExecutionId`
|
|
111
|
+
// with a fresh UUID. ADR 220.
|
|
112
|
+
planExecutionId: '',
|
|
96
113
|
};
|
|
97
114
|
|
|
98
115
|
super({ middleware, ctx });
|
|
@@ -104,6 +121,7 @@ class MongoRuntimeImpl
|
|
|
104
121
|
this.#codecs = options.context.codecs;
|
|
105
122
|
}
|
|
106
123
|
|
|
124
|
+
/* v8 ignore start -- one-phase lower satisfies RuntimeCore; execute uses structuralLower + resolveParams */
|
|
107
125
|
protected override async lower(
|
|
108
126
|
plan: MongoQueryPlan,
|
|
109
127
|
ctx: CodecCallContext,
|
|
@@ -114,6 +132,7 @@ class MongoRuntimeImpl
|
|
|
114
132
|
...ifDefined('resultShape', plan.resultShape),
|
|
115
133
|
};
|
|
116
134
|
}
|
|
135
|
+
/* v8 ignore stop */
|
|
117
136
|
|
|
118
137
|
protected override runDriver(exec: MongoExecutionPlan): AsyncIterable<Record<string, unknown>> {
|
|
119
138
|
return this.#driver.execute<Record<string, unknown>>(exec.command);
|
|
@@ -126,26 +145,81 @@ class MongoRuntimeImpl
|
|
|
126
145
|
const self = this;
|
|
127
146
|
const signal = options?.signal;
|
|
128
147
|
const codecCtx: CodecCallContext = signal === undefined ? {} : { signal };
|
|
148
|
+
|
|
149
|
+
// Per-execute middleware context. Spread the stored runtime-level
|
|
150
|
+
// template and mint a fresh `planExecutionId` so every hook in this
|
|
151
|
+
// call observes the same value, and two executions of the same plan
|
|
152
|
+
// observe distinct values. ADR 220. The plan itself flows through
|
|
153
|
+
// unchanged.
|
|
154
|
+
const execCtx: RuntimeMiddlewareContext = {
|
|
155
|
+
...self.ctx,
|
|
156
|
+
planExecutionId: crypto.randomUUID(),
|
|
157
|
+
};
|
|
158
|
+
|
|
129
159
|
const generator = async function* (): AsyncGenerator<Row, void, unknown> {
|
|
130
160
|
checkAborted(codecCtx, 'stream');
|
|
131
161
|
const compiled = await self.runBeforeCompile(plan);
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
|
|
163
|
+
// Phase 1: structural lower — transforms the AST but leaves MongoParamRef
|
|
164
|
+
// nodes in place so middleware can inspect and rewrite them before
|
|
165
|
+
// codec resolution.
|
|
166
|
+
const draft = self.#adapter.structuralLower(compiled);
|
|
167
|
+
const mutator: MongoParamRefMutatorInternal = createMongoParamRefMutator(draft);
|
|
168
|
+
|
|
169
|
+
// Build the plan view for the beforeExecute chain. Middleware accesses
|
|
170
|
+
// plan.meta and the mutator's entries(); plan.command carries the
|
|
171
|
+
// unresolved draft at this stage.
|
|
172
|
+
// The cast is necessary because MongoExecutionPlan.command is typed as
|
|
173
|
+
// AnyMongoWireCommand (the post-resolution shape). No beforeExecute
|
|
174
|
+
// middleware reads plan.command structurally — params are observed via
|
|
175
|
+
// the mutator's entries(). The cast is narrowed to the command slot
|
|
176
|
+
// only so no whole-object information is lost.
|
|
177
|
+
const draftExec: MongoExecutionPlan = {
|
|
178
|
+
meta: compiled.meta,
|
|
179
|
+
...ifDefined('resultShape', compiled.resultShape),
|
|
180
|
+
command: blindCast<
|
|
181
|
+
MongoExecutionPlan['command'],
|
|
182
|
+
'MongoLoweredDraft held in command slot for the beforeExecute view; resolveParams runs after the chain'
|
|
183
|
+
>(draft),
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
await runBeforeExecuteChain<MongoExecutionPlan, MongoParamRefMutator>(
|
|
187
|
+
draftExec,
|
|
188
|
+
self.middleware,
|
|
189
|
+
execCtx,
|
|
190
|
+
mutator,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Phase 2: resolve params — converts the (possibly mutated) draft into
|
|
194
|
+
// a frozen wire command. currentDraft() returns the original draft by
|
|
195
|
+
// reference when no middleware called replaceValue/replaceValues (fast path).
|
|
196
|
+
const resolvedCommand = await self.#adapter.resolveParams(mutator.currentDraft(), codecCtx);
|
|
197
|
+
const exec: MongoExecutionPlan = {
|
|
198
|
+
meta: compiled.meta,
|
|
199
|
+
...ifDefined('resultShape', compiled.resultShape),
|
|
200
|
+
command: resolvedCommand,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// Phase 3: driver pipeline — runWithMiddleware and decodeMongoRow both
|
|
204
|
+
// receive the fully resolved exec. computeMongoContentHash (called via
|
|
205
|
+
// ctx.contentHash during intercept/afterExecute) therefore hashes the
|
|
206
|
+
// resolved command; no MongoParamRef instance reaches canonicalStringify.
|
|
134
207
|
const stream = runWithMiddleware<MongoExecutionPlan, Record<string, unknown>>(
|
|
135
208
|
exec,
|
|
136
209
|
self.middleware,
|
|
137
|
-
|
|
210
|
+
execCtx,
|
|
138
211
|
() => self.runDriver(exec),
|
|
139
212
|
);
|
|
140
213
|
for await (const rawRow of stream) {
|
|
141
214
|
if (exec.resultShape === undefined) {
|
|
142
|
-
yield
|
|
215
|
+
yield blindCast<Row, 'driver row matches plan _row phantom when resultShape is absent'>(
|
|
216
|
+
rawRow,
|
|
217
|
+
);
|
|
143
218
|
} else {
|
|
144
219
|
// Source the collection from the lowered exec rather than the
|
|
145
|
-
// pre-lowering plan: a
|
|
146
|
-
// rewrite collection names during compilation, and the wire
|
|
147
|
-
//
|
|
148
|
-
// ran.
|
|
220
|
+
// pre-lowering plan: a runBeforeCompile middleware is allowed to
|
|
221
|
+
// rewrite collection names during compilation, and the wire command
|
|
222
|
+
// carried by exec is always authoritative for what just ran.
|
|
149
223
|
const decoded = await decodeMongoRow(
|
|
150
224
|
rawRow,
|
|
151
225
|
exec.resultShape,
|
|
@@ -153,7 +227,7 @@ class MongoRuntimeImpl
|
|
|
153
227
|
exec.command.collection,
|
|
154
228
|
codecCtx,
|
|
155
229
|
);
|
|
156
|
-
yield
|
|
230
|
+
yield blindCast<Row, 'decodeMongoRow output matches plan _row phantom'>(decoded);
|
|
157
231
|
}
|
|
158
232
|
}
|
|
159
233
|
};
|