@prisma-next/mongo-runtime 0.3.0-dev.127 → 0.3.0-dev.162
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 +5 -4
- package/dist/index.d.mts +17 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +64 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -9
- package/src/exports/index.ts +1 -0
- package/src/mongo-middleware.ts +23 -0
- package/src/mongo-runtime.ts +85 -15
package/README.md
CHANGED
|
@@ -4,15 +4,16 @@ MongoDB runtime executor for Prisma Next.
|
|
|
4
4
|
|
|
5
5
|
## Responsibilities
|
|
6
6
|
|
|
7
|
-
- **Runtime executor**: `createMongoRuntime()` composes adapter and driver into a `MongoRuntime`
|
|
8
|
-
- **
|
|
9
|
-
-
|
|
7
|
+
- **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
|
+
- **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
10
|
- **Lifecycle management**: Connection lifecycle via `close()`
|
|
11
11
|
|
|
12
12
|
## Dependencies
|
|
13
13
|
|
|
14
14
|
- **Depends on**:
|
|
15
|
-
- `@prisma-next/mongo-
|
|
15
|
+
- `@prisma-next/mongo-lowering` (`MongoAdapter`, `MongoDriver` interfaces)
|
|
16
|
+
- `@prisma-next/mongo-query-ast` (`MongoQueryPlan`, `AnyMongoCommand` — the typed plan shape)
|
|
16
17
|
- `@prisma-next/runtime-executor` (`AsyncIterableResult` return type)
|
|
17
18
|
- **Depended on by**:
|
|
18
19
|
- Integration tests (`test/integration/test/mongo/`)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import { AsyncIterableResult } from "@prisma-next/runtime
|
|
2
|
-
import {
|
|
1
|
+
import { AfterExecuteResult, AsyncIterableResult, RuntimeMiddleware, RuntimeMiddlewareContext } from "@prisma-next/framework-components/runtime";
|
|
2
|
+
import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
|
|
3
|
+
import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
|
|
3
4
|
|
|
5
|
+
//#region src/mongo-middleware.d.ts
|
|
6
|
+
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>;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
4
14
|
//#region src/mongo-runtime.d.ts
|
|
5
15
|
interface MongoRuntimeOptions {
|
|
6
16
|
readonly adapter: MongoAdapter;
|
|
7
17
|
readonly driver: MongoDriver;
|
|
8
|
-
readonly
|
|
18
|
+
readonly contract: unknown;
|
|
19
|
+
readonly targetId: string;
|
|
20
|
+
readonly middleware?: readonly RuntimeMiddleware[];
|
|
21
|
+
readonly mode?: 'strict' | 'permissive';
|
|
9
22
|
}
|
|
10
23
|
interface MongoRuntime {
|
|
11
24
|
execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row>;
|
|
@@ -13,5 +26,5 @@ interface MongoRuntime {
|
|
|
13
26
|
}
|
|
14
27
|
declare function createMongoRuntime(options: MongoRuntimeOptions): MongoRuntime;
|
|
15
28
|
//#endregion
|
|
16
|
-
export { type MongoRuntime, type MongoRuntimeOptions, createMongoRuntime };
|
|
29
|
+
export { type MongoMiddleware, type MongoMiddlewareContext, type MongoRuntime, type MongoRuntimeOptions, createMongoRuntime };
|
|
17
30
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/mongo-runtime.ts"],"sourcesContent":[],"mappings":";;;;
|
|
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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,22 +1,77 @@
|
|
|
1
|
-
import { AsyncIterableResult } from "@prisma-next/runtime
|
|
1
|
+
import { AsyncIterableResult, checkMiddlewareCompatibility } from "@prisma-next/framework-components/runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/mongo-runtime.ts
|
|
4
|
+
function noop() {}
|
|
5
|
+
function now() {
|
|
6
|
+
return Date.now();
|
|
7
|
+
}
|
|
4
8
|
var MongoRuntimeImpl = class {
|
|
5
9
|
#adapter;
|
|
6
10
|
#driver;
|
|
7
|
-
#
|
|
11
|
+
#middleware;
|
|
12
|
+
#middlewareContext;
|
|
8
13
|
constructor(options) {
|
|
9
14
|
this.#adapter = options.adapter;
|
|
10
15
|
this.#driver = options.driver;
|
|
11
|
-
|
|
16
|
+
const middleware = options.middleware ? [...options.middleware] : [];
|
|
17
|
+
for (const mw of middleware) checkMiddlewareCompatibility(mw, "mongo", options.targetId);
|
|
18
|
+
this.#middleware = middleware;
|
|
19
|
+
this.#middlewareContext = {
|
|
20
|
+
contract: options.contract,
|
|
21
|
+
mode: options.mode ?? "strict",
|
|
22
|
+
now,
|
|
23
|
+
log: {
|
|
24
|
+
info: noop,
|
|
25
|
+
warn: noop,
|
|
26
|
+
error: noop
|
|
27
|
+
}
|
|
28
|
+
};
|
|
12
29
|
}
|
|
13
30
|
execute(plan) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 = 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
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return new AsyncIterableResult(iterator());
|
|
20
75
|
}
|
|
21
76
|
async close() {
|
|
22
77
|
await this.#driver.close();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["#adapter","#driver","#
|
|
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 = 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,QAAQ,MAAM,KAAK;AAEvC,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"}
|
package/package.json
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/mongo-runtime",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.162",
|
|
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.3.0-dev.
|
|
9
|
-
"@prisma-next/mongo-
|
|
10
|
-
"@prisma-next/
|
|
8
|
+
"@prisma-next/contract": "0.3.0-dev.162",
|
|
9
|
+
"@prisma-next/mongo-lowering": "0.3.0-dev.162",
|
|
10
|
+
"@prisma-next/mongo-query-ast": "0.3.0-dev.162",
|
|
11
|
+
"@prisma-next/framework-components": "0.3.0-dev.162"
|
|
11
12
|
},
|
|
12
13
|
"devDependencies": {
|
|
13
14
|
"mongodb": "^6.16.0",
|
|
14
|
-
"mongodb-memory-server": "
|
|
15
|
+
"mongodb-memory-server": "10.4.3",
|
|
15
16
|
"tsdown": "0.18.4",
|
|
16
17
|
"typescript": "5.9.3",
|
|
17
18
|
"vitest": "4.0.17",
|
|
18
|
-
"@prisma-next/adapter-mongo": "0.3.0-dev.
|
|
19
|
-
"@prisma-next/
|
|
19
|
+
"@prisma-next/adapter-mongo": "0.3.0-dev.162",
|
|
20
|
+
"@prisma-next/middleware-telemetry": "0.3.0-dev.162",
|
|
21
|
+
"@prisma-next/runtime-executor": "0.3.0-dev.162",
|
|
22
|
+
"@prisma-next/mongo-contract-ts": "0.3.0-dev.162",
|
|
23
|
+
"@prisma-next/mongo-pipeline-builder": "0.3.0-dev.162",
|
|
24
|
+
"@prisma-next/mongo-value": "0.3.0-dev.162",
|
|
25
|
+
"@prisma-next/family-mongo": "0.3.0-dev.162",
|
|
26
|
+
"@prisma-next/driver-mongo": "0.3.0-dev.162",
|
|
27
|
+
"@prisma-next/mongo-contract": "0.3.0-dev.162",
|
|
20
28
|
"@prisma-next/test-utils": "0.0.1",
|
|
21
29
|
"@prisma-next/tsdown": "0.0.0",
|
|
22
|
-
"@prisma-next/
|
|
30
|
+
"@prisma-next/tsconfig": "0.0.0",
|
|
31
|
+
"@prisma-next/target-mongo": "0.3.0-dev.162"
|
|
23
32
|
},
|
|
24
33
|
"files": [
|
|
25
34
|
"dist",
|
|
@@ -35,7 +44,7 @@
|
|
|
35
44
|
"repository": {
|
|
36
45
|
"type": "git",
|
|
37
46
|
"url": "https://github.com/prisma/prisma-next.git",
|
|
38
|
-
"directory": "packages/2-mongo-family/
|
|
47
|
+
"directory": "packages/2-mongo-family/7-runtime"
|
|
39
48
|
},
|
|
40
49
|
"scripts": {
|
|
41
50
|
"build": "tsdown",
|
package/src/exports/index.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AfterExecuteResult,
|
|
3
|
+
RuntimeMiddleware,
|
|
4
|
+
RuntimeMiddlewareContext,
|
|
5
|
+
} from '@prisma-next/framework-components/runtime';
|
|
6
|
+
import type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
|
|
7
|
+
|
|
8
|
+
export interface MongoMiddlewareContext extends RuntimeMiddlewareContext {}
|
|
9
|
+
|
|
10
|
+
export interface MongoMiddleware extends RuntimeMiddleware {
|
|
11
|
+
readonly familyId: 'mongo';
|
|
12
|
+
beforeExecute?(plan: MongoQueryPlan, ctx: MongoMiddlewareContext): Promise<void>;
|
|
13
|
+
onRow?(
|
|
14
|
+
row: Record<string, unknown>,
|
|
15
|
+
plan: MongoQueryPlan,
|
|
16
|
+
ctx: MongoMiddlewareContext,
|
|
17
|
+
): Promise<void>;
|
|
18
|
+
afterExecute?(
|
|
19
|
+
plan: MongoQueryPlan,
|
|
20
|
+
result: AfterExecuteResult,
|
|
21
|
+
ctx: MongoMiddlewareContext,
|
|
22
|
+
): Promise<void>;
|
|
23
|
+
}
|
package/src/mongo-runtime.ts
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
RuntimeMiddleware,
|
|
3
|
+
RuntimeMiddlewareContext,
|
|
4
|
+
} from '@prisma-next/framework-components/runtime';
|
|
5
|
+
import {
|
|
6
|
+
AsyncIterableResult,
|
|
7
|
+
checkMiddlewareCompatibility,
|
|
8
|
+
} from '@prisma-next/framework-components/runtime';
|
|
9
|
+
import type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';
|
|
10
|
+
import type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
|
|
11
|
+
|
|
12
|
+
function noop() {}
|
|
13
|
+
function now() {
|
|
14
|
+
return Date.now();
|
|
15
|
+
}
|
|
8
16
|
|
|
9
17
|
export interface MongoRuntimeOptions {
|
|
10
18
|
readonly adapter: MongoAdapter;
|
|
11
19
|
readonly driver: MongoDriver;
|
|
12
|
-
readonly
|
|
20
|
+
readonly contract: unknown;
|
|
21
|
+
readonly targetId: string;
|
|
22
|
+
readonly middleware?: readonly RuntimeMiddleware[];
|
|
23
|
+
readonly mode?: 'strict' | 'permissive';
|
|
13
24
|
}
|
|
14
25
|
|
|
15
26
|
export interface MongoRuntime {
|
|
@@ -20,23 +31,82 @@ export interface MongoRuntime {
|
|
|
20
31
|
class MongoRuntimeImpl implements MongoRuntime {
|
|
21
32
|
readonly #adapter: MongoAdapter;
|
|
22
33
|
readonly #driver: MongoDriver;
|
|
23
|
-
readonly #
|
|
34
|
+
readonly #middleware: readonly RuntimeMiddleware[];
|
|
35
|
+
readonly #middlewareContext: RuntimeMiddlewareContext;
|
|
24
36
|
|
|
25
37
|
constructor(options: MongoRuntimeOptions) {
|
|
26
38
|
this.#adapter = options.adapter;
|
|
27
39
|
this.#driver = options.driver;
|
|
28
|
-
|
|
40
|
+
|
|
41
|
+
const middleware = options.middleware ? [...options.middleware] : [];
|
|
42
|
+
for (const mw of middleware) {
|
|
43
|
+
checkMiddlewareCompatibility(mw, 'mongo', options.targetId);
|
|
44
|
+
}
|
|
45
|
+
this.#middleware = middleware;
|
|
46
|
+
|
|
47
|
+
this.#middlewareContext = {
|
|
48
|
+
contract: options.contract,
|
|
49
|
+
mode: options.mode ?? 'strict',
|
|
50
|
+
now,
|
|
51
|
+
log: { info: noop, warn: noop, error: noop },
|
|
52
|
+
};
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row> {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
56
|
+
const adapter = this.#adapter;
|
|
57
|
+
const driver = this.#driver;
|
|
58
|
+
const middleware = this.#middleware;
|
|
59
|
+
const ctx = this.#middlewareContext;
|
|
34
60
|
|
|
35
|
-
async function*
|
|
36
|
-
|
|
37
|
-
|
|
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
|
+
|
|
67
|
+
try {
|
|
68
|
+
for (const mw of middleware) {
|
|
69
|
+
if (mw.beforeExecute) {
|
|
70
|
+
await mw.beforeExecute(plan, ctx);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const wireCommand = 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
|
+
}
|
|
103
|
+
|
|
104
|
+
await mw.afterExecute(plan, { rowCount, latencyMs, completed }, ctx);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
38
108
|
|
|
39
|
-
return new AsyncIterableResult(
|
|
109
|
+
return new AsyncIterableResult(iterator());
|
|
40
110
|
}
|
|
41
111
|
|
|
42
112
|
async close(): Promise<void> {
|