@prisma-next/mongo-core 0.0.1
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 +21 -0
- package/dist/index.d.mts +291 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +419 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
- package/src/adapter-types.ts +13 -0
- package/src/codec-registry.ts +40 -0
- package/src/codecs.ts +22 -0
- package/src/commands.ts +93 -0
- package/src/contract-schema.ts +119 -0
- package/src/contract-types.ts +120 -0
- package/src/driver-types.ts +6 -0
- package/src/exports/index.ts +64 -0
- package/src/param-ref.ts +16 -0
- package/src/plan.ts +16 -0
- package/src/results.ts +12 -0
- package/src/validate-domain.ts +174 -0
- package/src/validate-mongo-contract.ts +50 -0
- package/src/validate-storage.ts +64 -0
- package/src/values.ts +12 -0
- package/src/wire-commands.ts +95 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { MongoContract } from './contract-types';
|
|
2
|
+
|
|
3
|
+
export function validateMongoStorage(contract: MongoContract): void {
|
|
4
|
+
const errors: string[] = [];
|
|
5
|
+
|
|
6
|
+
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
7
|
+
if (model.storage.collection && !(model.storage.collection in contract.storage.collections)) {
|
|
8
|
+
errors.push(
|
|
9
|
+
`Model "${modelName}" references collection "${model.storage.collection}" which is not in storage.collections`,
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Mongo does not support multi-table inheritance (ADR 2): all variants of a base
|
|
14
|
+
// must share the same collection (single-table inheritance only).
|
|
15
|
+
if (model.base) {
|
|
16
|
+
const baseModel = contract.models[model.base];
|
|
17
|
+
if (baseModel) {
|
|
18
|
+
const variantCollection = model.storage.collection;
|
|
19
|
+
const baseCollection = baseModel.storage.collection;
|
|
20
|
+
if (variantCollection !== baseCollection) {
|
|
21
|
+
errors.push(
|
|
22
|
+
`Mongo does not support multi-table inheritance; variant "${modelName}" must share its base's collection ("${baseCollection ?? '(none)'}"), but has "${variantCollection ?? '(none)'}"`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (const [relName, relation] of Object.entries(model.relations)) {
|
|
29
|
+
if (relation.strategy === 'embed') {
|
|
30
|
+
const target = contract.models[relation.to];
|
|
31
|
+
if (target?.storage.collection) {
|
|
32
|
+
errors.push(
|
|
33
|
+
`Embed relation "${relName}" targets "${relation.to}" which must not have a collection`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (relation.strategy === 'reference') {
|
|
39
|
+
for (const localField of relation.on.localFields) {
|
|
40
|
+
if (!(localField in model.fields)) {
|
|
41
|
+
errors.push(
|
|
42
|
+
`Reference relation "${relName}": localField "${localField}" is not a field on model "${modelName}"`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const targetModel = contract.models[relation.to];
|
|
48
|
+
if (targetModel) {
|
|
49
|
+
for (const targetField of relation.on.targetFields) {
|
|
50
|
+
if (!(targetField in targetModel.fields)) {
|
|
51
|
+
errors.push(
|
|
52
|
+
`Reference relation "${relName}": targetField "${targetField}" is not a field on model "${relation.to}"`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (errors.length > 0) {
|
|
62
|
+
throw new Error(`Contract storage validation failed:\n- ${errors.join('\n- ')}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/values.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MongoParamRef } from './param-ref';
|
|
2
|
+
|
|
3
|
+
export type LiteralValue = string | number | boolean | null | Date;
|
|
4
|
+
export type MongoValue = MongoParamRef | LiteralValue | MongoDocument | MongoArray;
|
|
5
|
+
export interface MongoDocument {
|
|
6
|
+
readonly [key: string]: MongoValue;
|
|
7
|
+
}
|
|
8
|
+
export interface MongoArray extends ReadonlyArray<MongoValue> {}
|
|
9
|
+
export type MongoExpr = MongoDocument;
|
|
10
|
+
export type MongoUpdateDocument = Record<string, MongoValue>;
|
|
11
|
+
export type RawPipeline = ReadonlyArray<Record<string, unknown>>;
|
|
12
|
+
export type Document = Record<string, unknown>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Document, RawPipeline } from './values';
|
|
2
|
+
|
|
3
|
+
abstract class MongoWireCommand {
|
|
4
|
+
abstract readonly kind: string;
|
|
5
|
+
readonly collection: string;
|
|
6
|
+
|
|
7
|
+
protected constructor(collection: string) {
|
|
8
|
+
this.collection = collection;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected freeze(): void {
|
|
12
|
+
Object.freeze(this);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class FindWireCommand extends MongoWireCommand {
|
|
17
|
+
readonly kind = 'find' as const;
|
|
18
|
+
readonly filter: Document | undefined;
|
|
19
|
+
readonly projection: Document | undefined;
|
|
20
|
+
readonly sort: Document | undefined;
|
|
21
|
+
readonly limit: number | undefined;
|
|
22
|
+
readonly skip: number | undefined;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
collection: string,
|
|
26
|
+
filter?: Document,
|
|
27
|
+
options?: {
|
|
28
|
+
projection?: Document;
|
|
29
|
+
sort?: Document;
|
|
30
|
+
limit?: number;
|
|
31
|
+
skip?: number;
|
|
32
|
+
},
|
|
33
|
+
) {
|
|
34
|
+
super(collection);
|
|
35
|
+
this.filter = filter;
|
|
36
|
+
this.projection = options?.projection;
|
|
37
|
+
this.sort = options?.sort;
|
|
38
|
+
this.limit = options?.limit;
|
|
39
|
+
this.skip = options?.skip;
|
|
40
|
+
this.freeze();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class InsertOneWireCommand extends MongoWireCommand {
|
|
45
|
+
readonly kind = 'insertOne' as const;
|
|
46
|
+
readonly document: Document;
|
|
47
|
+
|
|
48
|
+
constructor(collection: string, document: Document) {
|
|
49
|
+
super(collection);
|
|
50
|
+
this.document = document;
|
|
51
|
+
this.freeze();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class UpdateOneWireCommand extends MongoWireCommand {
|
|
56
|
+
readonly kind = 'updateOne' as const;
|
|
57
|
+
readonly filter: Document;
|
|
58
|
+
readonly update: Document;
|
|
59
|
+
|
|
60
|
+
constructor(collection: string, filter: Document, update: Document) {
|
|
61
|
+
super(collection);
|
|
62
|
+
this.filter = filter;
|
|
63
|
+
this.update = update;
|
|
64
|
+
this.freeze();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class DeleteOneWireCommand extends MongoWireCommand {
|
|
69
|
+
readonly kind = 'deleteOne' as const;
|
|
70
|
+
readonly filter: Document;
|
|
71
|
+
|
|
72
|
+
constructor(collection: string, filter: Document) {
|
|
73
|
+
super(collection);
|
|
74
|
+
this.filter = filter;
|
|
75
|
+
this.freeze();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class AggregateWireCommand extends MongoWireCommand {
|
|
80
|
+
readonly kind = 'aggregate' as const;
|
|
81
|
+
readonly pipeline: RawPipeline;
|
|
82
|
+
|
|
83
|
+
constructor(collection: string, pipeline: RawPipeline) {
|
|
84
|
+
super(collection);
|
|
85
|
+
this.pipeline = pipeline;
|
|
86
|
+
this.freeze();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type AnyMongoWireCommand =
|
|
91
|
+
| FindWireCommand
|
|
92
|
+
| InsertOneWireCommand
|
|
93
|
+
| UpdateOneWireCommand
|
|
94
|
+
| DeleteOneWireCommand
|
|
95
|
+
| AggregateWireCommand;
|