@prisma-next/mongo-runtime 0.5.0-dev.8 → 0.5.0-dev.9

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/README.md CHANGED
@@ -2,18 +2,53 @@
2
2
 
3
3
  MongoDB runtime executor for Prisma Next.
4
4
 
5
+ ## Package Classification
6
+
7
+ - **Domain**: mongo
8
+ - **Layer**: runtime
9
+ - **Plane**: runtime
10
+
11
+ ## Overview
12
+
13
+ The Mongo runtime package implements the Mongo family runtime by extending the abstract `RuntimeCore` base class from `@prisma-next/framework-components/runtime` with Mongo-specific lowering and driver dispatch. It provides the public runtime API for MongoDB, layering Mongo concerns (adapter lowering and wire-command dispatch) on top of the shared middleware lifecycle.
14
+
5
15
  ## Responsibilities
6
16
 
7
17
  - **Runtime executor**: `createMongoRuntime()` composes adapter and driver into a `MongoRuntime` with a single `execute(plan)` entry point accepting `MongoQueryPlan<Row>` from `@prisma-next/mongo-query-ast`. Execution is one path for reads and writes: `adapter.lower(plan)` produces a wire command, then the driver runs it.
8
18
  - **Unified flow**: There is no separate `execute` vs `executeCommand`; all operations use `execute(plan)`.
9
- - **Lowering**: Happens in the adapter (`lower(plan)`), not inside the runtime.
10
- - **Lifecycle management**: Connection lifecycle via `close()`
19
+ - **Lowering**: Happens in the adapter (`lower(plan)`), wrapped by the runtime's `lower` override into a `MongoExecutionPlan`.
20
+ - **Middleware lifecycle inheritance**: `MongoRuntime` extends `RuntimeCore<MongoQueryPlan, MongoExecutionPlan, MongoMiddleware>` and inherits the `beforeExecute` / `onRow` / `afterExecute` lifecycle from the framework via `runWithMiddleware`. Mongo does **not** override `runBeforeCompile` (Mongo middleware has no `beforeCompile` hook today).
21
+ - **Lifecycle management**: Connection lifecycle via `close()`.
11
22
 
12
23
  ## Dependencies
13
24
 
14
25
  - **Depends on**:
15
26
  - `@prisma-next/mongo-lowering` (`MongoAdapter`, `MongoDriver` interfaces)
16
27
  - `@prisma-next/mongo-query-ast` (`MongoQueryPlan`, `AnyMongoCommand` — the typed plan shape)
17
- - `@prisma-next/runtime-executor` (`AsyncIterableResult` return type)
28
+ - `@prisma-next/framework-components` (`RuntimeCore` base class, `runWithMiddleware` helper, `RuntimeMiddleware` SPI, `AsyncIterableResult` return type)
18
29
  - **Depended on by**:
19
- - Integration tests (`test/integration/test/mongo/`)
30
+ - Integration tests (`test/integration/test/mongo/` and `test/integration/test/cross-package/cross-family-middleware.test.ts`)
31
+
32
+ ## Architecture
33
+
34
+ `MongoRuntimeImpl` extends `RuntimeCore<MongoQueryPlan, MongoExecutionPlan, MongoMiddleware>` and overrides:
35
+
36
+ - `lower(plan)` — calls the adapter's `lower(plan)` and wraps the resulting wire command into a `MongoExecutionPlan`.
37
+ - `runDriver(exec)` — dispatches the wire command to the Mongo driver via `driver.execute(exec.command)`.
38
+ - `close()` — closes the underlying driver.
39
+
40
+ The execution template (`execute(plan)` → `lower` → `runWithMiddleware` → `runDriver`) is inherited from `RuntimeCore`. The four inline middleware lifecycle loops (`beforeExecute`, `onRow`, `afterExecute`, plus the error-path `afterExecute`) that previously lived in `MongoRuntimeImpl.execute` are now delegated to the shared `runWithMiddleware` helper.
41
+
42
+ ```mermaid
43
+ flowchart LR
44
+ Plan[MongoQueryPlan] --> Runtime[MongoRuntime]
45
+ Runtime -.extends.-> Core[RuntimeCore]
46
+ Runtime --> Adapter[MongoAdapter.lower]
47
+ Adapter --> Exec[MongoExecutionPlan]
48
+ Runtime --> Driver[MongoDriver.execute]
49
+ ```
50
+
51
+ ## Related Subsystems
52
+
53
+ - **[Runtime & Middleware Framework](../../../../docs/architecture%20docs/subsystems/4.%20Runtime%20&%20Middleware%20Framework.md)** — Runtime execution pipeline
54
+ - **[Adapters & Targets](../../../../docs/architecture%20docs/subsystems/5.%20Adapters%20&%20Targets.md)** — Adapter and driver responsibilities
package/dist/index.d.mts CHANGED
@@ -1,14 +1,53 @@
1
- import { AfterExecuteResult, AsyncIterableResult, RuntimeMiddleware, RuntimeMiddlewareContext } from "@prisma-next/framework-components/runtime";
2
- import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
1
+ import { AfterExecuteResult, AsyncIterableResult, ExecutionPlan, RuntimeMiddleware, RuntimeMiddlewareContext } from "@prisma-next/framework-components/runtime";
2
+ import { AnyMongoWireCommand } from "@prisma-next/mongo-wire";
3
3
  import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
4
+ import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
5
+
6
+ //#region src/mongo-execution-plan.d.ts
4
7
 
8
+ /**
9
+ * Mongo-domain execution plan: a query lowered to the wire-command shape
10
+ * that a Mongo driver can run.
11
+ *
12
+ * The plan carries:
13
+ * - `command` — the wire command (e.g. `InsertOneWireCommand`,
14
+ * `AggregateWireCommand`) produced by `MongoAdapter.lower(plan)`
15
+ * - `meta` — family-agnostic plan metadata (target, lane, hashes, ...)
16
+ * - `_row` — phantom row type, propagated from the originating
17
+ * `MongoQueryPlan`
18
+ *
19
+ * Extends the framework-level `ExecutionPlan<Row>` marker so generic SPIs
20
+ * (`RuntimeExecutor<MongoExecutionPlan>`,
21
+ * `RuntimeMiddleware<MongoExecutionPlan>`) can be parameterized over it.
22
+ *
23
+ * Lives in the runtime layer (alongside `MongoRuntime`) because the wire
24
+ * command shape lives in the transport layer (`@prisma-next/mongo-wire`),
25
+ * which the lanes layer (`mongo-query-ast`, where `MongoQueryPlan` lives)
26
+ * cannot depend on. M1 establishes this type; `MongoRuntime.execute` does
27
+ * not yet accept it as input — that adoption lands in M4.
28
+ */
29
+ interface MongoExecutionPlan<Row = unknown> extends ExecutionPlan<Row> {
30
+ readonly command: AnyMongoWireCommand;
31
+ }
32
+ //#endregion
5
33
  //#region src/mongo-middleware.d.ts
6
34
  interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
7
- interface MongoMiddleware extends RuntimeMiddleware {
8
- readonly familyId: 'mongo';
9
- beforeExecute?(plan: MongoQueryPlan, ctx: MongoMiddlewareContext): Promise<void>;
10
- onRow?(row: Record<string, unknown>, plan: MongoQueryPlan, ctx: MongoMiddlewareContext): Promise<void>;
11
- afterExecute?(plan: MongoQueryPlan, result: AfterExecuteResult, ctx: MongoMiddlewareContext): Promise<void>;
35
+ /**
36
+ * Mongo-domain middleware. Extends the framework `RuntimeMiddleware`
37
+ * parameterized over `MongoExecutionPlan` because `runWithMiddleware`
38
+ * (driven by `RuntimeCore`) invokes the lifecycle hooks with the
39
+ * post-lowering plan.
40
+ *
41
+ * `familyId` is optional so generic cross-family middleware (e.g.
42
+ * telemetry) — which carry no `familyId` — remain assignable. When
43
+ * present, it must be `'mongo'`; the runtime rejects mismatches at
44
+ * construction time via `checkMiddlewareCompatibility`.
45
+ */
46
+ interface MongoMiddleware extends RuntimeMiddleware<MongoExecutionPlan> {
47
+ readonly familyId?: 'mongo';
48
+ beforeExecute?(plan: MongoExecutionPlan, ctx: MongoMiddlewareContext): Promise<void>;
49
+ onRow?(row: Record<string, unknown>, plan: MongoExecutionPlan, ctx: MongoMiddlewareContext): Promise<void>;
50
+ afterExecute?(plan: MongoExecutionPlan, result: AfterExecuteResult, ctx: MongoMiddlewareContext): Promise<void>;
12
51
  }
13
52
  //#endregion
14
53
  //#region src/mongo-runtime.d.ts
@@ -17,7 +56,7 @@ interface MongoRuntimeOptions {
17
56
  readonly driver: MongoDriver;
18
57
  readonly contract: unknown;
19
58
  readonly targetId: string;
20
- readonly middleware?: readonly RuntimeMiddleware[];
59
+ readonly middleware?: readonly MongoMiddleware[];
21
60
  readonly mode?: 'strict' | 'permissive';
22
61
  }
23
62
  interface MongoRuntime {
@@ -26,5 +65,5 @@ interface MongoRuntime {
26
65
  }
27
66
  declare function createMongoRuntime(options: MongoRuntimeOptions): MongoRuntime;
28
67
  //#endregion
29
- export { type MongoMiddleware, type MongoMiddlewareContext, type MongoRuntime, type MongoRuntimeOptions, createMongoRuntime };
68
+ export { type MongoExecutionPlan, type MongoMiddleware, type MongoMiddlewareContext, type MongoRuntime, type MongoRuntimeOptions, createMongoRuntime };
30
69
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/mongo-middleware.ts","../src/mongo-runtime.ts"],"sourcesContent":[],"mappings":";;;;;UAOiB,sBAAA,SAA+B;UAE/B,eAAA,SAAwB;EAFxB,SAAA,QAAA,EAAA,OAAuB;EAEvB,aAAA,EAAA,IAAgB,EAEV,cAFU,EAAA,GAAA,EAEW,sBAFX,CAAA,EAEoC,OAFpC,CAAA,IAAA,CAAA;EAEV,KAAA,EAAA,GAAA,EAEd,MAFc,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,IAAA,EAGb,cAHa,EAAA,GAAA,EAId,sBAJc,CAAA,EAKlB,OALkB,CAAA,IAAA,CAAA;EAAqB,YAAA,EAAA,IAAA,EAOlC,cAPkC,EAAA,MAAA,EAQhC,kBARgC,EAAA,GAAA,EASnC,sBATmC,CAAA,EAUvC,OAVuC,CAAA,IAAA,CAAA;;;;UCK3B,mBAAA;EDTA,SAAA,OAAA,ECUG,YDVoB;EAEvB,SAAA,MAAA,ECSE,WDTc;EAEV,SAAA,QAAA,EAAA,OAAA;EAAqB,SAAA,QAAA,EAAA,MAAA;EAAyB,SAAA,UAAA,CAAA,EAAA,SCUpC,iBDVoC,EAAA;EAE5D,SAAA,IAAA,CAAA,EAAA,QAAA,GAAA,YAAA;;AAEA,UCUQ,YAAA,CDVR;EACJ,OAAA,CAAA,GAAA,CAAA,CAAA,IAAA,ECUgB,cDVhB,CCU+B,GDV/B,CAAA,CAAA,ECUsC,mBDVtC,CCU0D,GDV1D,CAAA;EAEK,KAAA,EAAA,ECSC,ODTD,CAAA,IAAA,CAAA;;AAED,iBCgGO,kBAAA,CDhGP,OAAA,ECgGmC,mBDhGnC,CAAA,ECgGyD,YDhGzD"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/mongo-execution-plan.ts","../src/mongo-middleware.ts","../src/mongo-runtime.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAwBA;;;;;;;;ACjBA;AAaA;;;;;;;;AAOK,UDHY,kBCGZ,CAAA,MAAA,OAAA,CAAA,SDHsD,aCGtD,CDHoE,GCGpE,CAAA,CAAA;EAEK,SAAA,OAAA,EDJU,mBCIV;;;;UAtBO,sBAAA,SAA+B;;;ADiBhD;;;;;;;;ACjBA;AAaiB,UAAA,eAAA,SAAwB,iBAAR,CAA0B,kBAA1B,CAAA,CAAA;EAA0B,SAAA,QAAA,CAAA,EAAA,OAAA;EAEpC,aAAA,EAAA,IAAA,EAAA,kBAAA,EAAA,GAAA,EAAyB,sBAAzB,CAAA,EAAkD,OAAlD,CAAA,IAAA,CAAA;EAAyB,KAAA,EAAA,GAAA,EAEvC,MAFuC,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,IAAA,EAGtC,kBAHsC,EAAA,GAAA,EAIvC,sBAJuC,CAAA,EAK3C,OAL2C,CAAA,IAAA,CAAA;EAAyB,YAAA,EAAA,IAAA,EAO/D,kBAP+D,EAAA,MAAA,EAQ7D,kBAR6D,EAAA,GAAA,EAShE,sBATgE,CAAA,EAUpE,OAVoE,CAAA,IAAA,CAAA;;;;UCVxD,mBAAA;oBACG;EFWH,SAAA,MAAA,EEVE,WFUgB;EAAsC,SAAA,QAAA,EAAA,OAAA;EACrD,SAAA,QAAA,EAAA,MAAA;EADuC,SAAA,UAAA,CAAA,EAAA,SEP1B,eFO0B,EAAA;EAAa,SAAA,IAAA,CAAA,EAAA,QAAA,GAAA,YAAA;;UEHvD,YAAA;qBACI,eAAe,OAAO,oBAAoB;EDf9C,KAAA,EAAA,ECgBN,ODhBM,CAAA,IAAA,CAAA;AAajB;AAA2D,iBCgD3C,kBAAA,CDhD2C,OAAA,ECgDf,mBDhDe,CAAA,ECgDO,YDhDP"}
package/dist/index.mjs CHANGED
@@ -1,77 +1,38 @@
1
- import { AsyncIterableResult, checkMiddlewareCompatibility } from "@prisma-next/framework-components/runtime";
1
+ import { RuntimeCore, checkMiddlewareCompatibility } from "@prisma-next/framework-components/runtime";
2
2
 
3
3
  //#region src/mongo-runtime.ts
4
4
  function noop() {}
5
- function now() {
6
- return Date.now();
7
- }
8
- var MongoRuntimeImpl = class {
5
+ var MongoRuntimeImpl = class extends RuntimeCore {
9
6
  #adapter;
10
7
  #driver;
11
- #middleware;
12
- #middlewareContext;
13
8
  constructor(options) {
14
- this.#adapter = options.adapter;
15
- this.#driver = options.driver;
16
9
  const middleware = options.middleware ? [...options.middleware] : [];
17
10
  for (const mw of middleware) checkMiddlewareCompatibility(mw, "mongo", options.targetId);
18
- this.#middleware = middleware;
19
- this.#middlewareContext = {
11
+ const ctx = {
20
12
  contract: options.contract,
21
13
  mode: options.mode ?? "strict",
22
- now,
14
+ now: () => Date.now(),
23
15
  log: {
24
16
  info: noop,
25
17
  warn: noop,
26
18
  error: noop
27
19
  }
28
20
  };
21
+ super({
22
+ middleware,
23
+ ctx
24
+ });
25
+ this.#adapter = options.adapter;
26
+ this.#driver = options.driver;
29
27
  }
30
- execute(plan) {
31
- const adapter = this.#adapter;
32
- const driver = this.#driver;
33
- const middleware = this.#middleware;
34
- const ctx = this.#middlewareContext;
35
- const iterator = async function* () {
36
- const startedAt = ctx.now();
37
- let rowCount = 0;
38
- let completed = false;
39
- let failed = false;
40
- try {
41
- for (const mw of middleware) if (mw.beforeExecute) await mw.beforeExecute(plan, ctx);
42
- const wireCommand = await adapter.lower(plan);
43
- for await (const row of driver.execute(wireCommand)) {
44
- for (const mw of middleware) if (mw.onRow) await mw.onRow(row, plan, ctx);
45
- rowCount++;
46
- yield row;
47
- }
48
- completed = true;
49
- } catch (error) {
50
- failed = true;
51
- throw error;
52
- } finally {
53
- const latencyMs = ctx.now() - startedAt;
54
- for (const mw of middleware) {
55
- if (!mw.afterExecute) continue;
56
- if (failed) {
57
- try {
58
- await mw.afterExecute(plan, {
59
- rowCount,
60
- latencyMs,
61
- completed
62
- }, ctx);
63
- } catch {}
64
- continue;
65
- }
66
- await mw.afterExecute(plan, {
67
- rowCount,
68
- latencyMs,
69
- completed
70
- }, ctx);
71
- }
72
- }
28
+ async lower(plan) {
29
+ return {
30
+ command: await this.#adapter.lower(plan),
31
+ meta: plan.meta
73
32
  };
74
- return new AsyncIterableResult(iterator());
33
+ }
34
+ runDriver(exec) {
35
+ return this.#driver.execute(exec.command);
75
36
  }
76
37
  async close() {
77
38
  await this.#driver.close();
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["#adapter","#driver","#middleware","#middlewareContext"],"sources":["../src/mongo-runtime.ts"],"sourcesContent":["import type {\n RuntimeMiddleware,\n RuntimeMiddlewareContext,\n} from '@prisma-next/framework-components/runtime';\nimport {\n AsyncIterableResult,\n checkMiddlewareCompatibility,\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';\n\nfunction noop() {}\nfunction now() {\n return Date.now();\n}\n\nexport interface MongoRuntimeOptions {\n readonly adapter: MongoAdapter;\n readonly driver: MongoDriver;\n readonly contract: unknown;\n readonly targetId: string;\n readonly middleware?: readonly RuntimeMiddleware[];\n readonly mode?: 'strict' | 'permissive';\n}\n\nexport interface MongoRuntime {\n execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row>;\n close(): Promise<void>;\n}\n\nclass MongoRuntimeImpl implements MongoRuntime {\n readonly #adapter: MongoAdapter;\n readonly #driver: MongoDriver;\n readonly #middleware: readonly RuntimeMiddleware[];\n readonly #middlewareContext: RuntimeMiddlewareContext;\n\n constructor(options: MongoRuntimeOptions) {\n this.#adapter = options.adapter;\n this.#driver = options.driver;\n\n const middleware = options.middleware ? [...options.middleware] : [];\n for (const mw of middleware) {\n checkMiddlewareCompatibility(mw, 'mongo', options.targetId);\n }\n this.#middleware = middleware;\n\n this.#middlewareContext = {\n contract: options.contract,\n mode: options.mode ?? 'strict',\n now,\n log: { info: noop, warn: noop, error: noop },\n };\n }\n\n execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row> {\n const adapter = this.#adapter;\n const driver = this.#driver;\n const middleware = this.#middleware;\n const ctx = this.#middlewareContext;\n\n const iterator = async function* (): AsyncGenerator<Row, void, unknown> {\n const startedAt = ctx.now();\n let rowCount = 0;\n let completed = false;\n let failed = false;\n\n try {\n for (const mw of middleware) {\n if (mw.beforeExecute) {\n await mw.beforeExecute(plan, ctx);\n }\n }\n\n const wireCommand = await adapter.lower(plan);\n\n for await (const row of driver.execute<Row>(wireCommand)) {\n for (const mw of middleware) {\n if (mw.onRow) {\n await mw.onRow(row as Record<string, unknown>, plan, ctx);\n }\n }\n rowCount++;\n yield row;\n }\n\n completed = true;\n } catch (error) {\n failed = true;\n throw error;\n } finally {\n const latencyMs = ctx.now() - startedAt;\n for (const mw of middleware) {\n if (!mw.afterExecute) continue;\n\n if (failed) {\n try {\n await mw.afterExecute(plan, { rowCount, latencyMs, completed }, ctx);\n } catch {\n // Ignore errors from afterExecute during error handling\n }\n continue;\n }\n\n await mw.afterExecute(plan, { rowCount, latencyMs, completed }, ctx);\n }\n }\n };\n\n return new AsyncIterableResult(iterator());\n }\n\n 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":";;;AAWA,SAAS,OAAO;AAChB,SAAS,MAAM;AACb,QAAO,KAAK,KAAK;;AAiBnB,IAAM,mBAAN,MAA+C;CAC7C,CAASA;CACT,CAASC;CACT,CAASC;CACT,CAASC;CAET,YAAY,SAA8B;AACxC,QAAKH,UAAW,QAAQ;AACxB,QAAKC,SAAU,QAAQ;EAEvB,MAAM,aAAa,QAAQ,aAAa,CAAC,GAAG,QAAQ,WAAW,GAAG,EAAE;AACpE,OAAK,MAAM,MAAM,WACf,8BAA6B,IAAI,SAAS,QAAQ,SAAS;AAE7D,QAAKC,aAAc;AAEnB,QAAKC,oBAAqB;GACxB,UAAU,QAAQ;GAClB,MAAM,QAAQ,QAAQ;GACtB;GACA,KAAK;IAAE,MAAM;IAAM,MAAM;IAAM,OAAO;IAAM;GAC7C;;CAGH,QAAa,MAAqD;EAChE,MAAM,UAAU,MAAKH;EACrB,MAAM,SAAS,MAAKC;EACpB,MAAM,aAAa,MAAKC;EACxB,MAAM,MAAM,MAAKC;EAEjB,MAAM,WAAW,mBAAuD;GACtE,MAAM,YAAY,IAAI,KAAK;GAC3B,IAAI,WAAW;GACf,IAAI,YAAY;GAChB,IAAI,SAAS;AAEb,OAAI;AACF,SAAK,MAAM,MAAM,WACf,KAAI,GAAG,cACL,OAAM,GAAG,cAAc,MAAM,IAAI;IAIrC,MAAM,cAAc,MAAM,QAAQ,MAAM,KAAK;AAE7C,eAAW,MAAM,OAAO,OAAO,QAAa,YAAY,EAAE;AACxD,UAAK,MAAM,MAAM,WACf,KAAI,GAAG,MACL,OAAM,GAAG,MAAM,KAAgC,MAAM,IAAI;AAG7D;AACA,WAAM;;AAGR,gBAAY;YACL,OAAO;AACd,aAAS;AACT,UAAM;aACE;IACR,MAAM,YAAY,IAAI,KAAK,GAAG;AAC9B,SAAK,MAAM,MAAM,YAAY;AAC3B,SAAI,CAAC,GAAG,aAAc;AAEtB,SAAI,QAAQ;AACV,UAAI;AACF,aAAM,GAAG,aAAa,MAAM;QAAE;QAAU;QAAW;QAAW,EAAE,IAAI;cAC9D;AAGR;;AAGF,WAAM,GAAG,aAAa,MAAM;MAAE;MAAU;MAAW;MAAW,EAAE,IAAI;;;;AAK1E,SAAO,IAAI,oBAAoB,UAAU,CAAC;;CAG5C,MAAM,QAAuB;AAC3B,QAAM,MAAKF,OAAQ,OAAO;;;AAI9B,SAAgB,mBAAmB,SAA4C;AAC7E,QAAO,IAAI,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"index.mjs","names":["#adapter","#driver","ctx: MongoMiddlewareContext"],"sources":["../src/mongo-runtime.ts"],"sourcesContent":["import type { AsyncIterableResult } from '@prisma-next/framework-components/runtime';\nimport {\n checkMiddlewareCompatibility,\n RuntimeCore,\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 type { MongoExecutionPlan } from './mongo-execution-plan';\nimport type { MongoMiddleware, MongoMiddlewareContext } from './mongo-middleware';\n\nfunction noop() {}\n\nexport interface MongoRuntimeOptions {\n readonly adapter: MongoAdapter;\n readonly driver: MongoDriver;\n readonly contract: unknown;\n readonly targetId: string;\n readonly middleware?: readonly MongoMiddleware[];\n readonly mode?: 'strict' | 'permissive';\n}\n\nexport interface MongoRuntime {\n execute<Row>(plan: MongoQueryPlan<Row>): 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\n constructor(options: MongoRuntimeOptions) {\n const middleware = options.middleware ? [...options.middleware] : [];\n for (const mw of middleware) {\n checkMiddlewareCompatibility(mw, 'mongo', options.targetId);\n }\n\n const ctx: MongoMiddlewareContext = {\n contract: options.contract,\n mode: options.mode ?? 'strict',\n now: () => Date.now(),\n log: { info: noop, warn: noop, error: noop },\n };\n\n super({ middleware, ctx });\n\n this.#adapter = options.adapter;\n this.#driver = options.driver;\n }\n\n protected override async lower(plan: MongoQueryPlan): Promise<MongoExecutionPlan> {\n return {\n command: await this.#adapter.lower(plan),\n meta: plan.meta,\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 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":";;;AAUA,SAAS,OAAO;AAgBhB,IAAM,mBAAN,cACU,YAEV;CACE,CAASA;CACT,CAASC;CAET,YAAY,SAA8B;EACxC,MAAM,aAAa,QAAQ,aAAa,CAAC,GAAG,QAAQ,WAAW,GAAG,EAAE;AACpE,OAAK,MAAM,MAAM,WACf,8BAA6B,IAAI,SAAS,QAAQ,SAAS;EAG7D,MAAMC,MAA8B;GAClC,UAAU,QAAQ;GAClB,MAAM,QAAQ,QAAQ;GACtB,WAAW,KAAK,KAAK;GACrB,KAAK;IAAE,MAAM;IAAM,MAAM;IAAM,OAAO;IAAM;GAC7C;AAED,QAAM;GAAE;GAAY;GAAK,CAAC;AAE1B,QAAKF,UAAW,QAAQ;AACxB,QAAKC,SAAU,QAAQ;;CAGzB,MAAyB,MAAM,MAAmD;AAChF,SAAO;GACL,SAAS,MAAM,MAAKD,QAAS,MAAM,KAAK;GACxC,MAAM,KAAK;GACZ;;CAGH,AAAmB,UAAU,MAAkE;AAC7F,SAAO,MAAKC,OAAQ,QAAiC,KAAK,QAAQ;;CAGpE,MAAe,QAAuB;AACpC,QAAM,MAAKA,OAAQ,OAAO;;;AAI9B,SAAgB,mBAAmB,SAA4C;AAC7E,QAAO,IAAI,iBAAiB,QAAQ"}
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo-runtime",
3
- "version": "0.5.0-dev.8",
3
+ "version": "0.5.0-dev.9",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "MongoDB runtime implementation for Prisma Next",
7
7
  "dependencies": {
8
- "@prisma-next/contract": "0.5.0-dev.8",
9
- "@prisma-next/framework-components": "0.5.0-dev.8",
10
- "@prisma-next/mongo-lowering": "0.5.0-dev.8",
11
- "@prisma-next/mongo-query-ast": "0.5.0-dev.8"
8
+ "@prisma-next/mongo-lowering": "0.5.0-dev.9",
9
+ "@prisma-next/contract": "0.5.0-dev.9",
10
+ "@prisma-next/framework-components": "0.5.0-dev.9",
11
+ "@prisma-next/mongo-query-ast": "0.5.0-dev.9",
12
+ "@prisma-next/mongo-wire": "0.5.0-dev.9"
12
13
  },
13
14
  "devDependencies": {
14
15
  "mongodb": "^6.16.0",
@@ -16,19 +17,18 @@
16
17
  "tsdown": "0.18.4",
17
18
  "typescript": "5.9.3",
18
19
  "vitest": "4.0.17",
19
- "@prisma-next/adapter-mongo": "0.5.0-dev.8",
20
- "@prisma-next/middleware-telemetry": "0.5.0-dev.8",
21
- "@prisma-next/mongo-contract-ts": "0.5.0-dev.8",
22
- "@prisma-next/family-mongo": "0.5.0-dev.8",
23
- "@prisma-next/runtime-executor": "0.5.0-dev.8",
24
- "@prisma-next/mongo-value": "0.5.0-dev.8",
25
- "@prisma-next/driver-mongo": "0.5.0-dev.8",
26
- "@prisma-next/mongo-query-builder": "0.5.0-dev.8",
27
- "@prisma-next/target-mongo": "0.5.0-dev.8",
28
- "@prisma-next/mongo-contract": "0.5.0-dev.8",
29
- "@prisma-next/test-utils": "0.0.1",
20
+ "@prisma-next/middleware-telemetry": "0.5.0-dev.9",
21
+ "@prisma-next/adapter-mongo": "0.5.0-dev.9",
22
+ "@prisma-next/family-mongo": "0.5.0-dev.9",
23
+ "@prisma-next/mongo-contract-ts": "0.5.0-dev.9",
24
+ "@prisma-next/mongo-query-builder": "0.5.0-dev.9",
25
+ "@prisma-next/mongo-value": "0.5.0-dev.9",
26
+ "@prisma-next/driver-mongo": "0.5.0-dev.9",
27
+ "@prisma-next/mongo-contract": "0.5.0-dev.9",
28
+ "@prisma-next/target-mongo": "0.5.0-dev.9",
29
+ "@prisma-next/tsconfig": "0.0.0",
30
30
  "@prisma-next/tsdown": "0.0.0",
31
- "@prisma-next/tsconfig": "0.0.0"
31
+ "@prisma-next/test-utils": "0.0.1"
32
32
  },
33
33
  "files": [
34
34
  "dist",
@@ -1,3 +1,4 @@
1
+ export type { MongoExecutionPlan } from '../mongo-execution-plan';
1
2
  export type { MongoMiddleware, MongoMiddlewareContext } from '../mongo-middleware';
2
3
  export type { MongoRuntime, MongoRuntimeOptions } from '../mongo-runtime';
3
4
  export { createMongoRuntime } from '../mongo-runtime';
@@ -0,0 +1,27 @@
1
+ import type { ExecutionPlan } from '@prisma-next/framework-components/runtime';
2
+ import type { AnyMongoWireCommand } from '@prisma-next/mongo-wire';
3
+
4
+ /**
5
+ * Mongo-domain execution plan: a query lowered to the wire-command shape
6
+ * that a Mongo driver can run.
7
+ *
8
+ * The plan carries:
9
+ * - `command` — the wire command (e.g. `InsertOneWireCommand`,
10
+ * `AggregateWireCommand`) produced by `MongoAdapter.lower(plan)`
11
+ * - `meta` — family-agnostic plan metadata (target, lane, hashes, ...)
12
+ * - `_row` — phantom row type, propagated from the originating
13
+ * `MongoQueryPlan`
14
+ *
15
+ * Extends the framework-level `ExecutionPlan<Row>` marker so generic SPIs
16
+ * (`RuntimeExecutor<MongoExecutionPlan>`,
17
+ * `RuntimeMiddleware<MongoExecutionPlan>`) can be parameterized over it.
18
+ *
19
+ * Lives in the runtime layer (alongside `MongoRuntime`) because the wire
20
+ * command shape lives in the transport layer (`@prisma-next/mongo-wire`),
21
+ * which the lanes layer (`mongo-query-ast`, where `MongoQueryPlan` lives)
22
+ * cannot depend on. M1 establishes this type; `MongoRuntime.execute` does
23
+ * not yet accept it as input — that adoption lands in M4.
24
+ */
25
+ export interface MongoExecutionPlan<Row = unknown> extends ExecutionPlan<Row> {
26
+ readonly command: AnyMongoWireCommand;
27
+ }
@@ -3,20 +3,31 @@ import type {
3
3
  RuntimeMiddleware,
4
4
  RuntimeMiddlewareContext,
5
5
  } from '@prisma-next/framework-components/runtime';
6
- import type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
6
+ import type { MongoExecutionPlan } from './mongo-execution-plan';
7
7
 
8
8
  export interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
9
9
 
10
- export interface MongoMiddleware extends RuntimeMiddleware {
11
- readonly familyId: 'mongo';
12
- beforeExecute?(plan: MongoQueryPlan, ctx: MongoMiddlewareContext): Promise<void>;
10
+ /**
11
+ * Mongo-domain middleware. Extends the framework `RuntimeMiddleware`
12
+ * parameterized over `MongoExecutionPlan` because `runWithMiddleware`
13
+ * (driven by `RuntimeCore`) invokes the lifecycle hooks with the
14
+ * post-lowering plan.
15
+ *
16
+ * `familyId` is optional so generic cross-family middleware (e.g.
17
+ * telemetry) — which carry no `familyId` — remain assignable. When
18
+ * present, it must be `'mongo'`; the runtime rejects mismatches at
19
+ * construction time via `checkMiddlewareCompatibility`.
20
+ */
21
+ export interface MongoMiddleware extends RuntimeMiddleware<MongoExecutionPlan> {
22
+ readonly familyId?: 'mongo';
23
+ beforeExecute?(plan: MongoExecutionPlan, ctx: MongoMiddlewareContext): Promise<void>;
13
24
  onRow?(
14
25
  row: Record<string, unknown>,
15
- plan: MongoQueryPlan,
26
+ plan: MongoExecutionPlan,
16
27
  ctx: MongoMiddlewareContext,
17
28
  ): Promise<void>;
18
29
  afterExecute?(
19
- plan: MongoQueryPlan,
30
+ plan: MongoExecutionPlan,
20
31
  result: AfterExecuteResult,
21
32
  ctx: MongoMiddlewareContext,
22
33
  ): Promise<void>;
@@ -1,25 +1,21 @@
1
- import type {
2
- RuntimeMiddleware,
3
- RuntimeMiddlewareContext,
4
- } from '@prisma-next/framework-components/runtime';
1
+ import type { AsyncIterableResult } from '@prisma-next/framework-components/runtime';
5
2
  import {
6
- AsyncIterableResult,
7
3
  checkMiddlewareCompatibility,
4
+ RuntimeCore,
8
5
  } from '@prisma-next/framework-components/runtime';
9
6
  import type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';
10
7
  import type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
8
+ import type { MongoExecutionPlan } from './mongo-execution-plan';
9
+ import type { MongoMiddleware, MongoMiddlewareContext } from './mongo-middleware';
11
10
 
12
11
  function noop() {}
13
- function now() {
14
- return Date.now();
15
- }
16
12
 
17
13
  export interface MongoRuntimeOptions {
18
14
  readonly adapter: MongoAdapter;
19
15
  readonly driver: MongoDriver;
20
16
  readonly contract: unknown;
21
17
  readonly targetId: string;
22
- readonly middleware?: readonly RuntimeMiddleware[];
18
+ readonly middleware?: readonly MongoMiddleware[];
23
19
  readonly mode?: 'strict' | 'permissive';
24
20
  }
25
21
 
@@ -28,88 +24,44 @@ export interface MongoRuntime {
28
24
  close(): Promise<void>;
29
25
  }
30
26
 
31
- class MongoRuntimeImpl implements MongoRuntime {
27
+ class MongoRuntimeImpl
28
+ extends RuntimeCore<MongoQueryPlan, MongoExecutionPlan, MongoMiddleware>
29
+ implements MongoRuntime
30
+ {
32
31
  readonly #adapter: MongoAdapter;
33
32
  readonly #driver: MongoDriver;
34
- readonly #middleware: readonly RuntimeMiddleware[];
35
- readonly #middlewareContext: RuntimeMiddlewareContext;
36
33
 
37
34
  constructor(options: MongoRuntimeOptions) {
38
- this.#adapter = options.adapter;
39
- this.#driver = options.driver;
40
-
41
35
  const middleware = options.middleware ? [...options.middleware] : [];
42
36
  for (const mw of middleware) {
43
37
  checkMiddlewareCompatibility(mw, 'mongo', options.targetId);
44
38
  }
45
- this.#middleware = middleware;
46
39
 
47
- this.#middlewareContext = {
40
+ const ctx: MongoMiddlewareContext = {
48
41
  contract: options.contract,
49
42
  mode: options.mode ?? 'strict',
50
- now,
43
+ now: () => Date.now(),
51
44
  log: { info: noop, warn: noop, error: noop },
52
45
  };
53
- }
54
-
55
- execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row> {
56
- const adapter = this.#adapter;
57
- const driver = this.#driver;
58
- const middleware = this.#middleware;
59
- const ctx = this.#middlewareContext;
60
-
61
- const iterator = async function* (): AsyncGenerator<Row, void, unknown> {
62
- const startedAt = ctx.now();
63
- let rowCount = 0;
64
- let completed = false;
65
- let failed = false;
66
46
 
67
- try {
68
- for (const mw of middleware) {
69
- if (mw.beforeExecute) {
70
- await mw.beforeExecute(plan, ctx);
71
- }
72
- }
47
+ super({ middleware, ctx });
73
48
 
74
- const wireCommand = await adapter.lower(plan);
75
-
76
- for await (const row of driver.execute<Row>(wireCommand)) {
77
- for (const mw of middleware) {
78
- if (mw.onRow) {
79
- await mw.onRow(row as Record<string, unknown>, plan, ctx);
80
- }
81
- }
82
- rowCount++;
83
- yield row;
84
- }
85
-
86
- completed = true;
87
- } catch (error) {
88
- failed = true;
89
- throw error;
90
- } finally {
91
- const latencyMs = ctx.now() - startedAt;
92
- for (const mw of middleware) {
93
- if (!mw.afterExecute) continue;
94
-
95
- if (failed) {
96
- try {
97
- await mw.afterExecute(plan, { rowCount, latencyMs, completed }, ctx);
98
- } catch {
99
- // Ignore errors from afterExecute during error handling
100
- }
101
- continue;
102
- }
49
+ this.#adapter = options.adapter;
50
+ this.#driver = options.driver;
51
+ }
103
52
 
104
- await mw.afterExecute(plan, { rowCount, latencyMs, completed }, ctx);
105
- }
106
- }
53
+ protected override async lower(plan: MongoQueryPlan): Promise<MongoExecutionPlan> {
54
+ return {
55
+ command: await this.#adapter.lower(plan),
56
+ meta: plan.meta,
107
57
  };
58
+ }
108
59
 
109
- return new AsyncIterableResult(iterator());
60
+ protected override runDriver(exec: MongoExecutionPlan): AsyncIterable<Record<string, unknown>> {
61
+ return this.#driver.execute<Record<string, unknown>>(exec.command);
110
62
  }
111
63
 
112
- async close(): Promise<void> {
64
+ override async close(): Promise<void> {
113
65
  await this.#driver.close();
114
66
  }
115
67
  }