@prisma-next/adapter-mongo 0.5.0-dev.7 → 0.5.0-dev.71
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 +4 -2
- package/dist/codec-types.d.mts.map +1 -1
- package/dist/codec-types.mjs +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +11 -18
- package/dist/control.mjs.map +1 -1
- package/dist/index.d.mts +16 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -11
- package/dist/index.mjs.map +1 -1
- package/dist/{mongo-adapter-aVo8aZrf.mjs → mongo-adapter-DfCmEYHR.mjs} +234 -105
- package/dist/mongo-adapter-DfCmEYHR.mjs.map +1 -0
- package/dist/runtime.d.mts +16 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +23 -0
- package/dist/runtime.mjs.map +1 -0
- package/package.json +21 -17
- package/src/core/codecs.ts +116 -23
- package/src/core/introspect-schema.ts +6 -1
- package/src/core/operations.ts +3 -3
- package/src/exports/control.ts +2 -18
- package/src/exports/runtime.ts +48 -0
- package/src/lowering.ts +46 -17
- package/src/mongo-adapter.ts +78 -58
- package/src/resolve-value.ts +97 -6
- package/dist/mongo-adapter-aVo8aZrf.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.mjs","names":[],"sources":["../src/exports/runtime.ts"],"sourcesContent":["import type {\n ExecutionStack,\n RuntimeAdapterDescriptor,\n RuntimeAdapterInstance,\n} from '@prisma-next/framework-components/execution';\nimport type { MongoCodecRegistry } from '@prisma-next/mongo-codec';\nimport type { MongoAdapter } from '@prisma-next/mongo-lowering';\nimport { buildStandardCodecRegistry, mongoCodecDescriptors } from '../core/codecs';\nimport { createMongoAdapter } from '../mongo-adapter';\n\n/**\n * adapter-mongo deliberately does NOT import the `MongoRuntimeAdapterDescriptor` type alias from `@prisma-next/mongo-runtime`. The adapter package is downstream of the Mongo runtime package only conceptually; introducing a hard import would create a workspace dependency cycle (`mongo-runtime` consumes the runtime descriptor's `create(stack)` factory; `adapter-mongo` would then need `mongo-runtime` to type the\n * descriptor). The descriptor is shaped to satisfy the framework's `RuntimeAdapterDescriptor` plus the structural `MongoStaticContributions` (`codecs()`) that `@prisma-next/mongo-runtime` narrows to at composition time. This mirrors the `target-postgres` ↔ `sql-runtime` decoupling pattern.\n */\n\ninterface MongoRuntimeAdapterInstance\n extends RuntimeAdapterInstance<'mongo', 'mongo'>,\n MongoAdapter {}\n\nconst mongoRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<\n 'mongo',\n 'mongo',\n MongoRuntimeAdapterInstance\n> & {\n readonly codecs: () => MongoCodecRegistry;\n} = {\n kind: 'adapter',\n id: 'mongo',\n familyId: 'mongo',\n targetId: 'mongo',\n version: '0.0.1',\n types: {\n codecTypes: {\n codecDescriptors: mongoCodecDescriptors,\n },\n },\n codecs: buildStandardCodecRegistry,\n create(_stack: ExecutionStack<'mongo', 'mongo'>): MongoRuntimeAdapterInstance {\n const adapter = createMongoAdapter();\n return {\n familyId: 'mongo' as const,\n targetId: 'mongo' as const,\n lower: adapter.lower.bind(adapter),\n };\n },\n};\n\nexport default mongoRuntimeAdapterDescriptor;\n"],"mappings":";;AAmBA,MAAM,gCAMF;CACF,MAAM;CACN,IAAI;CACJ,UAAU;CACV,UAAU;CACV,SAAS;CACT,OAAO,EACL,YAAY,EACV,kBAAkB,uBACnB,EACF;CACD,QAAQ;CACR,OAAO,QAAuE;EAC5E,MAAM,UAAU,oBAAoB;EACpC,OAAO;GACL,UAAU;GACV,UAAU;GACV,OAAO,QAAQ,MAAM,KAAK,QAAQ;GACnC;;CAEJ"}
|
package/package.json
CHANGED
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/adapter-mongo",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.71",
|
|
4
|
+
"license": "Apache-2.0",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"sideEffects": false,
|
|
6
7
|
"description": "MongoDB adapter for Prisma Next (lowers commands to wire format)",
|
|
7
8
|
"dependencies": {
|
|
8
9
|
"arktype": "^2.1.29",
|
|
9
10
|
"mongodb": "^6.16.0",
|
|
10
|
-
"@prisma-next/config": "0.5.0-dev.
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
13
|
-
"@prisma-next/mongo
|
|
14
|
-
"@prisma-next/
|
|
15
|
-
"@prisma-next/mongo-
|
|
16
|
-
"@prisma-next/mongo-lowering": "0.5.0-dev.
|
|
17
|
-
"@prisma-next/mongo-
|
|
18
|
-
"@prisma-next/mongo-value": "0.5.0-dev.
|
|
19
|
-
"@prisma-next/mongo-
|
|
20
|
-
"@prisma-next/
|
|
21
|
-
"@prisma-next/
|
|
22
|
-
"@prisma-next/
|
|
11
|
+
"@prisma-next/config": "0.5.0-dev.71",
|
|
12
|
+
"@prisma-next/contract": "0.5.0-dev.71",
|
|
13
|
+
"@prisma-next/framework-components": "0.5.0-dev.71",
|
|
14
|
+
"@prisma-next/target-mongo": "0.5.0-dev.71",
|
|
15
|
+
"@prisma-next/mongo-contract": "0.5.0-dev.71",
|
|
16
|
+
"@prisma-next/mongo-query-ast": "0.5.0-dev.71",
|
|
17
|
+
"@prisma-next/mongo-lowering": "0.5.0-dev.71",
|
|
18
|
+
"@prisma-next/mongo-schema-ir": "0.5.0-dev.71",
|
|
19
|
+
"@prisma-next/mongo-value": "0.5.0-dev.71",
|
|
20
|
+
"@prisma-next/mongo-codec": "0.5.0-dev.71",
|
|
21
|
+
"@prisma-next/utils": "0.5.0-dev.71",
|
|
22
|
+
"@prisma-next/operations": "0.5.0-dev.71",
|
|
23
|
+
"@prisma-next/mongo-wire": "0.5.0-dev.71"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"mongodb-memory-server": "10.4.3",
|
|
26
|
-
"tsdown": "0.
|
|
27
|
+
"tsdown": "0.22.0",
|
|
27
28
|
"typescript": "5.9.3",
|
|
28
|
-
"vitest": "4.
|
|
29
|
-
"@prisma-next/driver-mongo": "0.5.0-dev.
|
|
29
|
+
"vitest": "4.1.5",
|
|
30
|
+
"@prisma-next/driver-mongo": "0.5.0-dev.71",
|
|
31
|
+
"@prisma-next/mongo-contract-psl": "0.5.0-dev.71",
|
|
32
|
+
"@prisma-next/psl-parser": "0.5.0-dev.71",
|
|
30
33
|
"@prisma-next/test-utils": "0.0.1",
|
|
31
34
|
"@prisma-next/tsconfig": "0.0.0",
|
|
32
35
|
"@prisma-next/tsdown": "0.0.0"
|
|
@@ -39,6 +42,7 @@
|
|
|
39
42
|
".": "./dist/index.mjs",
|
|
40
43
|
"./codec-types": "./dist/codec-types.mjs",
|
|
41
44
|
"./control": "./dist/control.mjs",
|
|
45
|
+
"./runtime": "./dist/runtime.mjs",
|
|
42
46
|
"./package.json": "./package.json"
|
|
43
47
|
},
|
|
44
48
|
"main": "./dist/index.mjs",
|
package/src/core/codecs.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CodecDescriptor, CodecTrait } from '@prisma-next/framework-components/codec';
|
|
2
|
+
import { voidParamsSchema } from '@prisma-next/framework-components/codec';
|
|
3
|
+
import {
|
|
4
|
+
type MongoCodec,
|
|
5
|
+
type MongoCodecRegistry,
|
|
6
|
+
mongoCodec,
|
|
7
|
+
newMongoCodecRegistry,
|
|
8
|
+
} from '@prisma-next/mongo-codec';
|
|
2
9
|
import { ObjectId } from 'mongodb';
|
|
3
10
|
import {
|
|
4
11
|
MONGO_BOOLEAN_CODEC_ID,
|
|
@@ -12,64 +19,150 @@ import {
|
|
|
12
19
|
|
|
13
20
|
export const mongoObjectIdCodec = mongoCodec({
|
|
14
21
|
typeId: MONGO_OBJECTID_CODEC_ID,
|
|
15
|
-
targetTypes: ['objectId'],
|
|
16
|
-
traits: ['equality'],
|
|
17
22
|
decode: (wire: ObjectId) => wire.toHexString(),
|
|
18
23
|
encode: (value: string) => new ObjectId(value),
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
export const mongoStringCodec = mongoCodec({
|
|
22
27
|
typeId: MONGO_STRING_CODEC_ID,
|
|
23
|
-
targetTypes: ['string'],
|
|
24
|
-
traits: ['equality', 'order', 'textual'],
|
|
25
28
|
decode: (wire: string) => wire,
|
|
26
29
|
encode: (value: string) => value,
|
|
27
30
|
});
|
|
28
31
|
|
|
29
32
|
export const mongoDoubleCodec = mongoCodec({
|
|
30
33
|
typeId: MONGO_DOUBLE_CODEC_ID,
|
|
31
|
-
targetTypes: ['double'],
|
|
32
|
-
traits: ['equality', 'order', 'numeric'],
|
|
33
34
|
decode: (wire: number) => wire,
|
|
34
35
|
encode: (value: number) => value,
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
export const mongoInt32Codec = mongoCodec({
|
|
38
39
|
typeId: MONGO_INT32_CODEC_ID,
|
|
39
|
-
targetTypes: ['int'],
|
|
40
|
-
traits: ['equality', 'order', 'numeric'],
|
|
41
40
|
decode: (wire: number) => wire,
|
|
42
41
|
encode: (value: number) => value,
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
export const mongoBooleanCodec = mongoCodec({
|
|
46
45
|
typeId: MONGO_BOOLEAN_CODEC_ID,
|
|
47
|
-
targetTypes: ['bool'],
|
|
48
|
-
traits: ['equality', 'boolean'],
|
|
49
46
|
decode: (wire: boolean) => wire,
|
|
50
47
|
encode: (value: boolean) => value,
|
|
51
48
|
});
|
|
52
49
|
|
|
53
50
|
export const mongoDateCodec = mongoCodec({
|
|
54
51
|
typeId: MONGO_DATE_CODEC_ID,
|
|
55
|
-
targetTypes: ['date'],
|
|
56
|
-
traits: ['equality', 'order'],
|
|
57
52
|
decode: (wire: Date) => wire,
|
|
58
53
|
encode: (value: Date) => value,
|
|
54
|
+
encodeJson: (value: Date) => value.toISOString(),
|
|
55
|
+
decodeJson: (json) => {
|
|
56
|
+
if (typeof json !== 'string') throw new Error('expected ISO date string');
|
|
57
|
+
return new Date(json);
|
|
58
|
+
},
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
export const mongoVectorCodec = mongoCodec({
|
|
62
62
|
typeId: MONGO_VECTOR_CODEC_ID,
|
|
63
|
-
targetTypes: ['vector'],
|
|
64
|
-
traits: ['equality'],
|
|
65
63
|
decode: (wire: readonly number[]) => wire,
|
|
66
64
|
encode: (value: readonly number[]) => value,
|
|
67
|
-
renderOutputType: (typeParams) => {
|
|
68
|
-
const length = typeParams['length'];
|
|
69
|
-
if (length === undefined) return undefined;
|
|
70
|
-
if (typeof length !== 'number' || !Number.isFinite(length) || !Number.isInteger(length)) {
|
|
71
|
-
throw new Error('renderOutputType: expected positive integer "length" for Vector');
|
|
72
|
-
}
|
|
73
|
-
return `Vector<${length}>`;
|
|
74
|
-
},
|
|
75
65
|
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The canonical set of Mongo wire-type codecs.
|
|
69
|
+
*
|
|
70
|
+
* Single source of truth for both control- and runtime-plane adapter descriptors. Don't duplicate this list — import it.
|
|
71
|
+
*/
|
|
72
|
+
export const mongoStandardCodecs = [
|
|
73
|
+
mongoObjectIdCodec,
|
|
74
|
+
mongoStringCodec,
|
|
75
|
+
mongoDoubleCodec,
|
|
76
|
+
mongoInt32Codec,
|
|
77
|
+
mongoBooleanCodec,
|
|
78
|
+
mongoDateCodec,
|
|
79
|
+
mongoVectorCodec,
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Build a {@link CodecDescriptor} for a Mongo wire-type codec.
|
|
84
|
+
*
|
|
85
|
+
* Wraps an existing {@link MongoCodec} instance into a descriptor whose factory hands out the same shared codec. Mongo's full migration to descriptor-first authoring is tracked under TML-2324; for now the descriptor view is composed from the existing `mongoCodec()` outputs.
|
|
86
|
+
*/
|
|
87
|
+
function descriptorFor<Id extends string>(
|
|
88
|
+
codec: MongoCodec<Id, readonly CodecTrait[]>,
|
|
89
|
+
metadata: {
|
|
90
|
+
readonly traits: readonly CodecTrait[];
|
|
91
|
+
readonly targetTypes: readonly string[];
|
|
92
|
+
readonly renderOutputType?: (typeParams: Record<string, unknown>) => string | undefined;
|
|
93
|
+
},
|
|
94
|
+
): CodecDescriptor {
|
|
95
|
+
// The descriptor's `P` is structurally `Record<string, unknown>` for codecs that take params (Mongo `vector`); non-parameterized codecs ignore the slot. Cast through `unknown` to fit the `CodecDescriptor` slot's `(params: P) => …` typing without leaking a per-codec `P` into the heterogeneous descriptor list.
|
|
96
|
+
const renderOutputType = metadata.renderOutputType as
|
|
97
|
+
| CodecDescriptor['renderOutputType']
|
|
98
|
+
| undefined;
|
|
99
|
+
return {
|
|
100
|
+
codecId: codec.id,
|
|
101
|
+
traits: metadata.traits,
|
|
102
|
+
targetTypes: metadata.targetTypes,
|
|
103
|
+
paramsSchema: voidParamsSchema as CodecDescriptor['paramsSchema'],
|
|
104
|
+
isParameterized: false,
|
|
105
|
+
factory: (() => () => codec) as CodecDescriptor['factory'],
|
|
106
|
+
...(renderOutputType !== undefined ? { renderOutputType } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const renderVectorOutputType = (typeParams: Record<string, unknown>): string | undefined => {
|
|
111
|
+
const length = typeParams['length'];
|
|
112
|
+
if (length === undefined) return undefined;
|
|
113
|
+
if (
|
|
114
|
+
typeof length !== 'number' ||
|
|
115
|
+
!Number.isFinite(length) ||
|
|
116
|
+
!Number.isInteger(length) ||
|
|
117
|
+
length <= 0
|
|
118
|
+
) {
|
|
119
|
+
throw new Error('renderOutputType: expected positive integer "length" for Vector');
|
|
120
|
+
}
|
|
121
|
+
return `Vector<${length}>`;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Mongo wire-type codec descriptors. Static metadata for `traits`, `targetTypes`, and `renderOutputType` lives here (the descriptor shape) — `MongoCodec` itself is narrow and only carries the four conversion methods (TML-2357).
|
|
126
|
+
*/
|
|
127
|
+
export const mongoCodecDescriptors: ReadonlyArray<CodecDescriptor> = [
|
|
128
|
+
descriptorFor(mongoObjectIdCodec, { traits: ['equality'], targetTypes: ['objectId'] }),
|
|
129
|
+
descriptorFor(mongoStringCodec, {
|
|
130
|
+
traits: ['equality', 'order', 'textual'],
|
|
131
|
+
targetTypes: ['string'],
|
|
132
|
+
}),
|
|
133
|
+
descriptorFor(mongoDoubleCodec, {
|
|
134
|
+
traits: ['equality', 'order', 'numeric'],
|
|
135
|
+
targetTypes: ['double'],
|
|
136
|
+
}),
|
|
137
|
+
descriptorFor(mongoInt32Codec, {
|
|
138
|
+
traits: ['equality', 'order', 'numeric'],
|
|
139
|
+
targetTypes: ['int'],
|
|
140
|
+
}),
|
|
141
|
+
descriptorFor(mongoBooleanCodec, { traits: ['equality', 'boolean'], targetTypes: ['bool'] }),
|
|
142
|
+
descriptorFor(mongoDateCodec, { traits: ['equality', 'order'], targetTypes: ['date'] }),
|
|
143
|
+
descriptorFor(mongoVectorCodec, {
|
|
144
|
+
traits: ['equality'],
|
|
145
|
+
targetTypes: ['vector'],
|
|
146
|
+
renderOutputType: renderVectorOutputType,
|
|
147
|
+
}),
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Lookup descriptor metadata by codec id — used by tests and for descriptor-side reads of static metadata.
|
|
152
|
+
*/
|
|
153
|
+
export function mongoDescriptorById(codecId: string): CodecDescriptor | undefined {
|
|
154
|
+
return mongoCodecDescriptors.find((d) => d.codecId === codecId);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Build a {@link MongoCodecRegistry} preloaded with the standard Mongo wire-type codecs.
|
|
159
|
+
*
|
|
160
|
+
* Single point of truth for adapter-side codec construction: used by the legacy synchronous `createMongoAdapter()` factory and by the runtime adapter descriptor's `codecs()` getter. Userland code obtains a registry via the framework's execution-stack composition (see `createMongoExecutionContext`) instead of calling this directly.
|
|
161
|
+
*/
|
|
162
|
+
export function buildStandardCodecRegistry(): MongoCodecRegistry {
|
|
163
|
+
const registry = newMongoCodecRegistry();
|
|
164
|
+
for (const codec of mongoStandardCodecs) {
|
|
165
|
+
registry.register(codec);
|
|
166
|
+
}
|
|
167
|
+
return registry;
|
|
168
|
+
}
|
|
@@ -18,7 +18,12 @@ function parseIndexKeys(keySpec: Record<string, unknown>): MongoIndexKey[] {
|
|
|
18
18
|
return keys;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Exported for unit tests to exercise the defensive `!key` guard; not part of
|
|
23
|
+
* the public API. Callers in this package use it via the `introspectSchema`
|
|
24
|
+
* pipeline only.
|
|
25
|
+
*/
|
|
26
|
+
export function isDefaultIdIndex(doc: Document): boolean {
|
|
22
27
|
const key = doc['key'] as Record<string, unknown> | undefined;
|
|
23
28
|
if (!key) return false;
|
|
24
29
|
const entries = Object.entries(key);
|
package/src/core/operations.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { OperationDescriptor } from '@prisma-next/operations';
|
|
2
|
-
import {
|
|
2
|
+
import { MONGO_VECTOR_CODEC_ID } from './codec-ids';
|
|
3
3
|
|
|
4
4
|
export const mongoVectorNearOperation = Object.freeze({
|
|
5
5
|
method: 'near',
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
self: { codecId: MONGO_VECTOR_CODEC_ID },
|
|
7
|
+
impl: () => undefined as never,
|
|
8
8
|
}) satisfies OperationDescriptor;
|
|
9
9
|
|
|
10
10
|
export const mongoVectorOperationDescriptors: readonly OperationDescriptor[] = [
|
package/src/exports/control.ts
CHANGED
|
@@ -8,15 +8,7 @@ export {
|
|
|
8
8
|
} from '../core/mongo-control-driver';
|
|
9
9
|
export { createMongoRunnerDeps, extractDb } from '../core/runner-deps';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
mongoBooleanCodec,
|
|
13
|
-
mongoDateCodec,
|
|
14
|
-
mongoDoubleCodec,
|
|
15
|
-
mongoInt32Codec,
|
|
16
|
-
mongoObjectIdCodec,
|
|
17
|
-
mongoStringCodec,
|
|
18
|
-
mongoVectorCodec,
|
|
19
|
-
} from '../core/codecs';
|
|
11
|
+
import { mongoCodecDescriptors } from '../core/codecs';
|
|
20
12
|
|
|
21
13
|
const mongoAdapterDescriptor: ControlAdapterDescriptor<'mongo', 'mongo'> = {
|
|
22
14
|
kind: 'adapter',
|
|
@@ -34,15 +26,7 @@ const mongoAdapterDescriptor: ControlAdapterDescriptor<'mongo', 'mongo'> = {
|
|
|
34
26
|
]),
|
|
35
27
|
types: {
|
|
36
28
|
codecTypes: {
|
|
37
|
-
|
|
38
|
-
mongoObjectIdCodec,
|
|
39
|
-
mongoStringCodec,
|
|
40
|
-
mongoDoubleCodec,
|
|
41
|
-
mongoInt32Codec,
|
|
42
|
-
mongoBooleanCodec,
|
|
43
|
-
mongoDateCodec,
|
|
44
|
-
mongoVectorCodec,
|
|
45
|
-
],
|
|
29
|
+
codecDescriptors: mongoCodecDescriptors,
|
|
46
30
|
import: {
|
|
47
31
|
package: '@prisma-next/adapter-mongo/codec-types',
|
|
48
32
|
named: 'CodecTypes',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExecutionStack,
|
|
3
|
+
RuntimeAdapterDescriptor,
|
|
4
|
+
RuntimeAdapterInstance,
|
|
5
|
+
} from '@prisma-next/framework-components/execution';
|
|
6
|
+
import type { MongoCodecRegistry } from '@prisma-next/mongo-codec';
|
|
7
|
+
import type { MongoAdapter } from '@prisma-next/mongo-lowering';
|
|
8
|
+
import { buildStandardCodecRegistry, mongoCodecDescriptors } from '../core/codecs';
|
|
9
|
+
import { createMongoAdapter } from '../mongo-adapter';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* adapter-mongo deliberately does NOT import the `MongoRuntimeAdapterDescriptor` type alias from `@prisma-next/mongo-runtime`. The adapter package is downstream of the Mongo runtime package only conceptually; introducing a hard import would create a workspace dependency cycle (`mongo-runtime` consumes the runtime descriptor's `create(stack)` factory; `adapter-mongo` would then need `mongo-runtime` to type the
|
|
13
|
+
* descriptor). The descriptor is shaped to satisfy the framework's `RuntimeAdapterDescriptor` plus the structural `MongoStaticContributions` (`codecs()`) that `@prisma-next/mongo-runtime` narrows to at composition time. This mirrors the `target-postgres` ↔ `sql-runtime` decoupling pattern.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface MongoRuntimeAdapterInstance
|
|
17
|
+
extends RuntimeAdapterInstance<'mongo', 'mongo'>,
|
|
18
|
+
MongoAdapter {}
|
|
19
|
+
|
|
20
|
+
const mongoRuntimeAdapterDescriptor: RuntimeAdapterDescriptor<
|
|
21
|
+
'mongo',
|
|
22
|
+
'mongo',
|
|
23
|
+
MongoRuntimeAdapterInstance
|
|
24
|
+
> & {
|
|
25
|
+
readonly codecs: () => MongoCodecRegistry;
|
|
26
|
+
} = {
|
|
27
|
+
kind: 'adapter',
|
|
28
|
+
id: 'mongo',
|
|
29
|
+
familyId: 'mongo',
|
|
30
|
+
targetId: 'mongo',
|
|
31
|
+
version: '0.0.1',
|
|
32
|
+
types: {
|
|
33
|
+
codecTypes: {
|
|
34
|
+
codecDescriptors: mongoCodecDescriptors,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
codecs: buildStandardCodecRegistry,
|
|
38
|
+
create(_stack: ExecutionStack<'mongo', 'mongo'>): MongoRuntimeAdapterInstance {
|
|
39
|
+
const adapter = createMongoAdapter();
|
|
40
|
+
return {
|
|
41
|
+
familyId: 'mongo' as const,
|
|
42
|
+
targetId: 'mongo' as const,
|
|
43
|
+
lower: adapter.lower.bind(adapter),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default mongoRuntimeAdapterDescriptor;
|
package/src/lowering.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CodecCallContext } from '@prisma-next/framework-components/codec';
|
|
2
|
+
import type { MongoCodecRegistry } from '@prisma-next/mongo-codec';
|
|
1
3
|
import type {
|
|
2
4
|
MongoAggExpr,
|
|
3
5
|
MongoAggExprVisitor,
|
|
@@ -136,16 +138,20 @@ export function lowerAggExpr(expr: MongoAggExpr): unknown {
|
|
|
136
138
|
return expr.accept(aggExprLoweringVisitor);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
|
-
export function lowerFilter(
|
|
141
|
+
export async function lowerFilter(
|
|
142
|
+
filter: MongoFilterExpr,
|
|
143
|
+
codecs: MongoCodecRegistry,
|
|
144
|
+
ctx: CodecCallContext,
|
|
145
|
+
): Promise<Document> {
|
|
140
146
|
switch (filter.kind) {
|
|
141
147
|
case 'field':
|
|
142
|
-
return { [filter.field]: { [filter.op]: resolveValue(filter.value) } };
|
|
148
|
+
return { [filter.field]: { [filter.op]: await resolveValue(filter.value, codecs, ctx) } };
|
|
143
149
|
case 'and':
|
|
144
|
-
return { $and: filter.exprs.map((e) => lowerFilter(e)) };
|
|
150
|
+
return { $and: await Promise.all(filter.exprs.map((e) => lowerFilter(e, codecs, ctx))) };
|
|
145
151
|
case 'or':
|
|
146
|
-
return { $or: filter.exprs.map((e) => lowerFilter(e)) };
|
|
152
|
+
return { $or: await Promise.all(filter.exprs.map((e) => lowerFilter(e, codecs, ctx))) };
|
|
147
153
|
case 'not':
|
|
148
|
-
return { $nor: [lowerFilter(filter.expr)] };
|
|
154
|
+
return { $nor: [await lowerFilter(filter.expr, codecs, ctx)] };
|
|
149
155
|
case 'exists':
|
|
150
156
|
return { [filter.field]: { $exists: filter.exists } };
|
|
151
157
|
case 'expr':
|
|
@@ -198,10 +204,14 @@ function lowerWindowField(wf: MongoWindowField): Record<string, unknown> {
|
|
|
198
204
|
return result;
|
|
199
205
|
}
|
|
200
206
|
|
|
201
|
-
export function lowerStage(
|
|
207
|
+
export async function lowerStage(
|
|
208
|
+
stage: MongoPipelineStage,
|
|
209
|
+
codecs: MongoCodecRegistry,
|
|
210
|
+
ctx: CodecCallContext,
|
|
211
|
+
): Promise<Record<string, unknown>> {
|
|
202
212
|
switch (stage.kind) {
|
|
203
213
|
case 'match':
|
|
204
|
-
return { $match: lowerFilter(stage.filter) };
|
|
214
|
+
return { $match: await lowerFilter(stage.filter, codecs, ctx) };
|
|
205
215
|
case 'project': {
|
|
206
216
|
const projection: Record<string, unknown> = {};
|
|
207
217
|
for (const [key, val] of Object.entries(stage.projection)) {
|
|
@@ -223,7 +233,9 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
223
233
|
if (stage.localField !== undefined) lookup['localField'] = stage.localField;
|
|
224
234
|
if (stage.foreignField !== undefined) lookup['foreignField'] = stage.foreignField;
|
|
225
235
|
if (stage.pipeline) {
|
|
226
|
-
lookup['pipeline'] =
|
|
236
|
+
lookup['pipeline'] = await Promise.all(
|
|
237
|
+
stage.pipeline.map((s) => lowerStage(s, codecs, ctx)),
|
|
238
|
+
);
|
|
227
239
|
}
|
|
228
240
|
if (stage.let_) {
|
|
229
241
|
lookup['let'] = lowerExprRecord(stage.let_);
|
|
@@ -264,7 +276,9 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
264
276
|
case 'unionWith': {
|
|
265
277
|
const unionWith: Record<string, unknown> = { coll: stage.collection };
|
|
266
278
|
if (stage.pipeline) {
|
|
267
|
-
unionWith['pipeline'] =
|
|
279
|
+
unionWith['pipeline'] = await Promise.all(
|
|
280
|
+
stage.pipeline.map((s) => lowerStage(s, codecs, ctx)),
|
|
281
|
+
);
|
|
268
282
|
}
|
|
269
283
|
return { $unionWith: unionWith };
|
|
270
284
|
}
|
|
@@ -294,7 +308,7 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
294
308
|
if (stage.spherical !== undefined) geoNear['spherical'] = stage.spherical;
|
|
295
309
|
if (stage.maxDistance !== undefined) geoNear['maxDistance'] = stage.maxDistance;
|
|
296
310
|
if (stage.minDistance !== undefined) geoNear['minDistance'] = stage.minDistance;
|
|
297
|
-
if (stage.query) geoNear['query'] = lowerFilter(stage.query);
|
|
311
|
+
if (stage.query) geoNear['query'] = await lowerFilter(stage.query, codecs, ctx);
|
|
298
312
|
if (stage.key !== undefined) geoNear['key'] = stage.key;
|
|
299
313
|
if (stage.distanceMultiplier !== undefined)
|
|
300
314
|
geoNear['distanceMultiplier'] = stage.distanceMultiplier;
|
|
@@ -302,9 +316,18 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
302
316
|
return { $geoNear: geoNear };
|
|
303
317
|
}
|
|
304
318
|
case 'facet': {
|
|
319
|
+
const facetEntries = Object.entries(stage.facets);
|
|
320
|
+
const facetPipelines = await Promise.all(
|
|
321
|
+
facetEntries.map(([, pipeline]) =>
|
|
322
|
+
Promise.all(pipeline.map((s) => lowerStage(s, codecs, ctx))),
|
|
323
|
+
),
|
|
324
|
+
);
|
|
305
325
|
const facet: Record<string, unknown> = {};
|
|
306
|
-
for (
|
|
307
|
-
|
|
326
|
+
for (let i = 0; i < facetEntries.length; i++) {
|
|
327
|
+
const entry = facetEntries[i];
|
|
328
|
+
if (entry) {
|
|
329
|
+
facet[entry[0]] = facetPipelines[i];
|
|
330
|
+
}
|
|
308
331
|
}
|
|
309
332
|
return { $facet: facet };
|
|
310
333
|
}
|
|
@@ -319,7 +342,11 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
319
342
|
if (stage.maxDepth !== undefined) graphLookup['maxDepth'] = stage.maxDepth;
|
|
320
343
|
if (stage.depthField !== undefined) graphLookup['depthField'] = stage.depthField;
|
|
321
344
|
if (stage.restrictSearchWithMatch)
|
|
322
|
-
graphLookup['restrictSearchWithMatch'] = lowerFilter(
|
|
345
|
+
graphLookup['restrictSearchWithMatch'] = await lowerFilter(
|
|
346
|
+
stage.restrictSearchWithMatch,
|
|
347
|
+
codecs,
|
|
348
|
+
ctx,
|
|
349
|
+
);
|
|
323
350
|
return { $graphLookup: graphLookup };
|
|
324
351
|
}
|
|
325
352
|
case 'merge': {
|
|
@@ -327,7 +354,7 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
327
354
|
if (stage.on !== undefined) merge['on'] = stage.on;
|
|
328
355
|
if (stage.whenMatched !== undefined) {
|
|
329
356
|
merge['whenMatched'] = Array.isArray(stage.whenMatched)
|
|
330
|
-
? stage.whenMatched.map((s) => lowerStage(s))
|
|
357
|
+
? await Promise.all(stage.whenMatched.map((s) => lowerStage(s, codecs, ctx)))
|
|
331
358
|
: stage.whenMatched;
|
|
332
359
|
}
|
|
333
360
|
if (stage.whenNotMatched !== undefined) merge['whenNotMatched'] = stage.whenNotMatched;
|
|
@@ -395,8 +422,10 @@ export function lowerStage(stage: MongoPipelineStage): Record<string, unknown> {
|
|
|
395
422
|
}
|
|
396
423
|
}
|
|
397
424
|
|
|
398
|
-
export function lowerPipeline(
|
|
425
|
+
export async function lowerPipeline(
|
|
399
426
|
stages: ReadonlyArray<MongoPipelineStage>,
|
|
400
|
-
|
|
401
|
-
|
|
427
|
+
codecs: MongoCodecRegistry,
|
|
428
|
+
ctx: CodecCallContext,
|
|
429
|
+
): Promise<Array<Record<string, unknown>>> {
|
|
430
|
+
return Promise.all(stages.map((s) => lowerStage(s, codecs, ctx)));
|
|
402
431
|
}
|