@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
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
|
|
3
|
+
//#region src/codec-registry.ts
|
|
4
|
+
var MongoCodecRegistryImpl = class {
|
|
5
|
+
#byId = /* @__PURE__ */ new Map();
|
|
6
|
+
get(id) {
|
|
7
|
+
return this.#byId.get(id);
|
|
8
|
+
}
|
|
9
|
+
has(id) {
|
|
10
|
+
return this.#byId.has(id);
|
|
11
|
+
}
|
|
12
|
+
register(codec) {
|
|
13
|
+
if (this.#byId.has(codec.id)) throw new Error(`Codec with ID '${codec.id}' is already registered`);
|
|
14
|
+
this.#byId.set(codec.id, codec);
|
|
15
|
+
}
|
|
16
|
+
*[Symbol.iterator]() {
|
|
17
|
+
yield* this.#byId.values();
|
|
18
|
+
}
|
|
19
|
+
values() {
|
|
20
|
+
return this.#byId.values();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function createMongoCodecRegistry() {
|
|
24
|
+
return new MongoCodecRegistryImpl();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/codecs.ts
|
|
29
|
+
function mongoCodec(config) {
|
|
30
|
+
return {
|
|
31
|
+
id: config.typeId,
|
|
32
|
+
targetTypes: config.targetTypes,
|
|
33
|
+
decode: config.decode,
|
|
34
|
+
encode: config.encode
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/commands.ts
|
|
40
|
+
var MongoCommand = class {
|
|
41
|
+
collection;
|
|
42
|
+
constructor(collection) {
|
|
43
|
+
this.collection = collection;
|
|
44
|
+
}
|
|
45
|
+
freeze() {
|
|
46
|
+
Object.freeze(this);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var FindCommand = class extends MongoCommand {
|
|
50
|
+
kind = "find";
|
|
51
|
+
filter;
|
|
52
|
+
projection;
|
|
53
|
+
sort;
|
|
54
|
+
limit;
|
|
55
|
+
skip;
|
|
56
|
+
constructor(collection, filter, options) {
|
|
57
|
+
super(collection);
|
|
58
|
+
this.filter = filter;
|
|
59
|
+
this.projection = options?.projection;
|
|
60
|
+
this.sort = options?.sort;
|
|
61
|
+
this.limit = options?.limit;
|
|
62
|
+
this.skip = options?.skip;
|
|
63
|
+
this.freeze();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var InsertOneCommand = class extends MongoCommand {
|
|
67
|
+
kind = "insertOne";
|
|
68
|
+
document;
|
|
69
|
+
constructor(collection, document) {
|
|
70
|
+
super(collection);
|
|
71
|
+
this.document = document;
|
|
72
|
+
this.freeze();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var UpdateOneCommand = class extends MongoCommand {
|
|
76
|
+
kind = "updateOne";
|
|
77
|
+
filter;
|
|
78
|
+
update;
|
|
79
|
+
constructor(collection, filter, update) {
|
|
80
|
+
super(collection);
|
|
81
|
+
this.filter = filter;
|
|
82
|
+
this.update = update;
|
|
83
|
+
this.freeze();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var DeleteOneCommand = class extends MongoCommand {
|
|
87
|
+
kind = "deleteOne";
|
|
88
|
+
filter;
|
|
89
|
+
constructor(collection, filter) {
|
|
90
|
+
super(collection);
|
|
91
|
+
this.filter = filter;
|
|
92
|
+
this.freeze();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var AggregateCommand = class extends MongoCommand {
|
|
96
|
+
kind = "aggregate";
|
|
97
|
+
pipeline;
|
|
98
|
+
constructor(collection, pipeline) {
|
|
99
|
+
super(collection);
|
|
100
|
+
this.pipeline = pipeline;
|
|
101
|
+
this.freeze();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/param-ref.ts
|
|
107
|
+
var MongoParamRef = class MongoParamRef {
|
|
108
|
+
value;
|
|
109
|
+
name;
|
|
110
|
+
codecId;
|
|
111
|
+
constructor(value, options) {
|
|
112
|
+
this.value = value;
|
|
113
|
+
this.name = options?.name;
|
|
114
|
+
this.codecId = options?.codecId;
|
|
115
|
+
Object.freeze(this);
|
|
116
|
+
}
|
|
117
|
+
static of(value, options) {
|
|
118
|
+
return new MongoParamRef(value, options);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/validate-domain.ts
|
|
124
|
+
function validateContractDomain(contract) {
|
|
125
|
+
const errors = [];
|
|
126
|
+
const warnings = [];
|
|
127
|
+
const modelNames = new Set(Object.keys(contract.models));
|
|
128
|
+
validateRoots(contract, modelNames, errors);
|
|
129
|
+
validateVariantsAndBases(contract, modelNames, errors);
|
|
130
|
+
validateRelationTargets(contract, modelNames, errors);
|
|
131
|
+
validateDiscriminators(contract, errors);
|
|
132
|
+
detectOrphanedModels(contract, modelNames, warnings);
|
|
133
|
+
if (errors.length > 0) throw new Error(`Contract domain validation failed:\n- ${errors.join("\n- ")}`);
|
|
134
|
+
return { warnings };
|
|
135
|
+
}
|
|
136
|
+
function validateRoots(contract, modelNames, errors) {
|
|
137
|
+
const seenValues = /* @__PURE__ */ new Set();
|
|
138
|
+
for (const [rootKey, modelName] of Object.entries(contract.roots)) {
|
|
139
|
+
if (seenValues.has(modelName)) errors.push(`Duplicate root value: "${modelName}" is mapped by multiple root keys`);
|
|
140
|
+
seenValues.add(modelName);
|
|
141
|
+
if (!modelNames.has(modelName)) errors.push(`Root "${rootKey}" references model "${modelName}" which does not exist in models`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function validateVariantsAndBases(contract, modelNames, errors) {
|
|
145
|
+
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
146
|
+
if (model.variants) for (const variantName of Object.keys(model.variants)) {
|
|
147
|
+
if (!modelNames.has(variantName)) {
|
|
148
|
+
errors.push(`Model "${modelName}" lists variant "${variantName}" which does not exist in models`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const variantModel = contract.models[variantName];
|
|
152
|
+
if (!variantModel) continue;
|
|
153
|
+
if (variantModel.base !== modelName) errors.push(`Variant "${variantName}" has base "${variantModel.base ?? "(none)"}" but expected "${modelName}"`);
|
|
154
|
+
}
|
|
155
|
+
if (model.base) {
|
|
156
|
+
if (!modelNames.has(model.base)) {
|
|
157
|
+
errors.push(`Model "${modelName}" has base "${model.base}" which does not exist in models`);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const baseModel = contract.models[model.base];
|
|
161
|
+
if (!baseModel) continue;
|
|
162
|
+
if (!baseModel.variants || !(modelName in baseModel.variants)) errors.push(`Model "${modelName}" has base "${model.base}" which does not list it as a variant`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function validateRelationTargets(contract, modelNames, errors) {
|
|
167
|
+
for (const [modelName, model] of Object.entries(contract.models)) for (const [relName, relation] of Object.entries(model.relations)) if (!modelNames.has(relation.to)) errors.push(`Relation "${relName}" on model "${modelName}" targets "${relation.to}" which does not exist in models`);
|
|
168
|
+
}
|
|
169
|
+
function validateDiscriminators(contract, errors) {
|
|
170
|
+
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
171
|
+
if (model.discriminator) {
|
|
172
|
+
if (!model.variants || Object.keys(model.variants).length === 0) errors.push(`Model "${modelName}" has discriminator but no variants`);
|
|
173
|
+
if (!(model.discriminator.field in model.fields)) errors.push(`Discriminator field "${model.discriminator.field}" is not a field on model "${modelName}"`);
|
|
174
|
+
}
|
|
175
|
+
if (model.variants && Object.keys(model.variants).length > 0 && !model.discriminator) errors.push(`Model "${modelName}" has variants but no discriminator`);
|
|
176
|
+
if (model.base) {
|
|
177
|
+
if (model.discriminator) errors.push(`Model "${modelName}" has base and must not have discriminator`);
|
|
178
|
+
if (model.variants && Object.keys(model.variants).length > 0) errors.push(`Model "${modelName}" has base and must not have variants`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function detectOrphanedModels(contract, modelNames, warnings) {
|
|
183
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
184
|
+
for (const modelName of Object.values(contract.roots)) referenced.add(modelName);
|
|
185
|
+
for (const model of Object.values(contract.models)) {
|
|
186
|
+
for (const relation of Object.values(model.relations)) referenced.add(relation.to);
|
|
187
|
+
if (model.variants) for (const variantName of Object.keys(model.variants)) referenced.add(variantName);
|
|
188
|
+
if (model.base) referenced.add(model.base);
|
|
189
|
+
}
|
|
190
|
+
for (const modelName of modelNames) if (!referenced.has(modelName)) warnings.push(`Orphaned model: "${modelName}" is not referenced by any root, relation, or variant`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/contract-schema.ts
|
|
195
|
+
const MongoModelFieldSchema = type({
|
|
196
|
+
"+": "reject",
|
|
197
|
+
codecId: "string",
|
|
198
|
+
nullable: "boolean"
|
|
199
|
+
});
|
|
200
|
+
const MongoModelStorageSchema = type({
|
|
201
|
+
"+": "reject",
|
|
202
|
+
"collection?": "string"
|
|
203
|
+
});
|
|
204
|
+
const MongoDiscriminatorSchema = type({
|
|
205
|
+
"+": "reject",
|
|
206
|
+
field: "string"
|
|
207
|
+
});
|
|
208
|
+
const MongoVariantEntrySchema = type({
|
|
209
|
+
"+": "reject",
|
|
210
|
+
value: "string"
|
|
211
|
+
});
|
|
212
|
+
const MongoReferenceRelationOnSchema = type({
|
|
213
|
+
"+": "reject",
|
|
214
|
+
localFields: "string[]",
|
|
215
|
+
targetFields: "string[]"
|
|
216
|
+
});
|
|
217
|
+
const MongoReferenceRelationSchema = type({
|
|
218
|
+
"+": "reject",
|
|
219
|
+
to: "string",
|
|
220
|
+
cardinality: "'1:1' | '1:N' | 'N:1'",
|
|
221
|
+
strategy: "'reference'",
|
|
222
|
+
on: MongoReferenceRelationOnSchema
|
|
223
|
+
});
|
|
224
|
+
const MongoEmbedRelationSchema = type({
|
|
225
|
+
"+": "reject",
|
|
226
|
+
to: "string",
|
|
227
|
+
cardinality: "'1:1' | '1:N'",
|
|
228
|
+
strategy: "'embed'",
|
|
229
|
+
field: "string"
|
|
230
|
+
});
|
|
231
|
+
const MongoRelationSchema = MongoReferenceRelationSchema.or(MongoEmbedRelationSchema);
|
|
232
|
+
const MongoModelDefinitionSchema = type({
|
|
233
|
+
"+": "reject",
|
|
234
|
+
fields: type("Record<string, unknown>").pipe((fields) => {
|
|
235
|
+
const result = {};
|
|
236
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
237
|
+
const parsed = MongoModelFieldSchema(value);
|
|
238
|
+
if (parsed instanceof type.errors) throw new Error(`Invalid field "${key}": ${parsed.summary}`);
|
|
239
|
+
result[key] = parsed;
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}),
|
|
243
|
+
storage: MongoModelStorageSchema,
|
|
244
|
+
relations: type("Record<string, unknown>").pipe((relations) => {
|
|
245
|
+
const result = {};
|
|
246
|
+
for (const [key, value] of Object.entries(relations)) {
|
|
247
|
+
const parsed = MongoRelationSchema(value);
|
|
248
|
+
if (parsed instanceof type.errors) throw new Error(`Invalid relation "${key}": ${parsed.summary}`);
|
|
249
|
+
result[key] = parsed;
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
}),
|
|
253
|
+
"discriminator?": MongoDiscriminatorSchema,
|
|
254
|
+
"variants?": type("Record<string, unknown>").pipe((variants) => {
|
|
255
|
+
const result = {};
|
|
256
|
+
for (const [key, value] of Object.entries(variants)) {
|
|
257
|
+
const parsed = MongoVariantEntrySchema(value);
|
|
258
|
+
if (parsed instanceof type.errors) throw new Error(`Invalid variant "${key}": ${parsed.summary}`);
|
|
259
|
+
result[key] = parsed;
|
|
260
|
+
}
|
|
261
|
+
return result;
|
|
262
|
+
}),
|
|
263
|
+
"base?": "string"
|
|
264
|
+
});
|
|
265
|
+
const MongoStorageCollectionSchema = type({ "+": "reject" });
|
|
266
|
+
const MongoContractSchema = type({
|
|
267
|
+
"+": "reject",
|
|
268
|
+
targetFamily: "'mongo'",
|
|
269
|
+
roots: "Record<string, string>",
|
|
270
|
+
storage: type({
|
|
271
|
+
"+": "reject",
|
|
272
|
+
collections: type("Record<string, unknown>").pipe((collections) => {
|
|
273
|
+
const result = {};
|
|
274
|
+
for (const [key, value] of Object.entries(collections)) {
|
|
275
|
+
const parsed = MongoStorageCollectionSchema(value);
|
|
276
|
+
if (parsed instanceof type.errors) throw new Error(`Invalid collection "${key}": ${parsed.summary}`);
|
|
277
|
+
result[key] = parsed;
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
})
|
|
281
|
+
}),
|
|
282
|
+
models: type("Record<string, unknown>").pipe((models) => {
|
|
283
|
+
const result = {};
|
|
284
|
+
for (const [key, value] of Object.entries(models)) {
|
|
285
|
+
const parsed = MongoModelDefinitionSchema(value);
|
|
286
|
+
if (parsed instanceof type.errors) throw new Error(`Invalid model "${key}": ${parsed.summary}`);
|
|
287
|
+
result[key] = parsed;
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
})
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/validate-storage.ts
|
|
295
|
+
function validateMongoStorage(contract) {
|
|
296
|
+
const errors = [];
|
|
297
|
+
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
298
|
+
if (model.storage.collection && !(model.storage.collection in contract.storage.collections)) errors.push(`Model "${modelName}" references collection "${model.storage.collection}" which is not in storage.collections`);
|
|
299
|
+
if (model.base) {
|
|
300
|
+
const baseModel = contract.models[model.base];
|
|
301
|
+
if (baseModel) {
|
|
302
|
+
const variantCollection = model.storage.collection;
|
|
303
|
+
const baseCollection = baseModel.storage.collection;
|
|
304
|
+
if (variantCollection !== baseCollection) errors.push(`Mongo does not support multi-table inheritance; variant "${modelName}" must share its base's collection ("${baseCollection ?? "(none)"}"), but has "${variantCollection ?? "(none)"}"`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const [relName, relation] of Object.entries(model.relations)) {
|
|
308
|
+
if (relation.strategy === "embed") {
|
|
309
|
+
if (contract.models[relation.to]?.storage.collection) errors.push(`Embed relation "${relName}" targets "${relation.to}" which must not have a collection`);
|
|
310
|
+
}
|
|
311
|
+
if (relation.strategy === "reference") {
|
|
312
|
+
for (const localField of relation.on.localFields) if (!(localField in model.fields)) errors.push(`Reference relation "${relName}": localField "${localField}" is not a field on model "${modelName}"`);
|
|
313
|
+
const targetModel = contract.models[relation.to];
|
|
314
|
+
if (targetModel) {
|
|
315
|
+
for (const targetField of relation.on.targetFields) if (!(targetField in targetModel.fields)) errors.push(`Reference relation "${relName}": targetField "${targetField}" is not a field on model "${relation.to}"`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (errors.length > 0) throw new Error(`Contract storage validation failed:\n- ${errors.join("\n- ")}`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region src/validate-mongo-contract.ts
|
|
325
|
+
function validateMongoContract(value) {
|
|
326
|
+
const parsed = MongoContractSchema(value);
|
|
327
|
+
if (parsed instanceof type.errors) throw new Error(`Contract structural validation failed: ${parsed.summary}`);
|
|
328
|
+
const contract = parsed;
|
|
329
|
+
const { warnings } = validateContractDomain(contract);
|
|
330
|
+
validateMongoStorage(contract);
|
|
331
|
+
return {
|
|
332
|
+
contract,
|
|
333
|
+
indices: buildIndices(contract),
|
|
334
|
+
warnings
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function buildIndices(contract) {
|
|
338
|
+
const variantToBase = {};
|
|
339
|
+
const modelToVariants = {};
|
|
340
|
+
for (const [modelName, model] of Object.entries(contract.models)) {
|
|
341
|
+
if (model.base) variantToBase[modelName] = model.base;
|
|
342
|
+
if (model.variants) modelToVariants[modelName] = Object.keys(model.variants);
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
variantToBase,
|
|
346
|
+
modelToVariants
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/wire-commands.ts
|
|
352
|
+
var MongoWireCommand = class {
|
|
353
|
+
collection;
|
|
354
|
+
constructor(collection) {
|
|
355
|
+
this.collection = collection;
|
|
356
|
+
}
|
|
357
|
+
freeze() {
|
|
358
|
+
Object.freeze(this);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
var FindWireCommand = class extends MongoWireCommand {
|
|
362
|
+
kind = "find";
|
|
363
|
+
filter;
|
|
364
|
+
projection;
|
|
365
|
+
sort;
|
|
366
|
+
limit;
|
|
367
|
+
skip;
|
|
368
|
+
constructor(collection, filter, options) {
|
|
369
|
+
super(collection);
|
|
370
|
+
this.filter = filter;
|
|
371
|
+
this.projection = options?.projection;
|
|
372
|
+
this.sort = options?.sort;
|
|
373
|
+
this.limit = options?.limit;
|
|
374
|
+
this.skip = options?.skip;
|
|
375
|
+
this.freeze();
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
var InsertOneWireCommand = class extends MongoWireCommand {
|
|
379
|
+
kind = "insertOne";
|
|
380
|
+
document;
|
|
381
|
+
constructor(collection, document) {
|
|
382
|
+
super(collection);
|
|
383
|
+
this.document = document;
|
|
384
|
+
this.freeze();
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
var UpdateOneWireCommand = class extends MongoWireCommand {
|
|
388
|
+
kind = "updateOne";
|
|
389
|
+
filter;
|
|
390
|
+
update;
|
|
391
|
+
constructor(collection, filter, update) {
|
|
392
|
+
super(collection);
|
|
393
|
+
this.filter = filter;
|
|
394
|
+
this.update = update;
|
|
395
|
+
this.freeze();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
var DeleteOneWireCommand = class extends MongoWireCommand {
|
|
399
|
+
kind = "deleteOne";
|
|
400
|
+
filter;
|
|
401
|
+
constructor(collection, filter) {
|
|
402
|
+
super(collection);
|
|
403
|
+
this.filter = filter;
|
|
404
|
+
this.freeze();
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
var AggregateWireCommand = class extends MongoWireCommand {
|
|
408
|
+
kind = "aggregate";
|
|
409
|
+
pipeline;
|
|
410
|
+
constructor(collection, pipeline) {
|
|
411
|
+
super(collection);
|
|
412
|
+
this.pipeline = pipeline;
|
|
413
|
+
this.freeze();
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
//#endregion
|
|
418
|
+
export { AggregateCommand, AggregateWireCommand, DeleteOneCommand, DeleteOneWireCommand, FindCommand, FindWireCommand, InsertOneCommand, InsertOneWireCommand, MongoParamRef, UpdateOneCommand, UpdateOneWireCommand, createMongoCodecRegistry, mongoCodec, validateContractDomain, validateMongoContract, validateMongoStorage };
|
|
419
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["#byId","errors: string[]","warnings: string[]","result: Record<string, unknown>","errors: string[]","arktypeType","variantToBase: Record<string, string>","modelToVariants: Record<string, string[]>"],"sources":["../src/codec-registry.ts","../src/codecs.ts","../src/commands.ts","../src/param-ref.ts","../src/validate-domain.ts","../src/contract-schema.ts","../src/validate-storage.ts","../src/validate-mongo-contract.ts","../src/wire-commands.ts"],"sourcesContent":["import type { MongoCodec } from './codecs';\n\nexport interface MongoCodecRegistry {\n get(id: string): MongoCodec<string> | undefined;\n has(id: string): boolean;\n register(codec: MongoCodec<string>): void;\n [Symbol.iterator](): Iterator<MongoCodec<string>>;\n values(): IterableIterator<MongoCodec<string>>;\n}\n\nclass MongoCodecRegistryImpl implements MongoCodecRegistry {\n readonly #byId = new Map<string, MongoCodec<string>>();\n\n get(id: string): MongoCodec<string> | undefined {\n return this.#byId.get(id);\n }\n\n has(id: string): boolean {\n return this.#byId.has(id);\n }\n\n register(codec: MongoCodec<string>): void {\n if (this.#byId.has(codec.id)) {\n throw new Error(`Codec with ID '${codec.id}' is already registered`);\n }\n this.#byId.set(codec.id, codec);\n }\n\n *[Symbol.iterator](): Iterator<MongoCodec<string>> {\n yield* this.#byId.values();\n }\n\n values(): IterableIterator<MongoCodec<string>> {\n return this.#byId.values();\n }\n}\n\nexport function createMongoCodecRegistry(): MongoCodecRegistry {\n return new MongoCodecRegistryImpl();\n}\n","export interface MongoCodec<Id extends string = string, TWire = unknown, TJs = unknown> {\n readonly id: Id;\n readonly targetTypes: readonly string[];\n decode(wire: TWire): TJs;\n encode?(value: TJs): TWire;\n}\n\nexport function mongoCodec<Id extends string, TWire, TJs>(config: {\n typeId: Id;\n targetTypes: readonly string[];\n encode: (value: TJs) => TWire;\n decode: (wire: TWire) => TJs;\n}): MongoCodec<Id, TWire, TJs> {\n return {\n id: config.typeId,\n targetTypes: config.targetTypes,\n decode: config.decode,\n encode: config.encode,\n };\n}\n\nexport type MongoCodecJsType<T> = T extends MongoCodec<string, unknown, infer TJs> ? TJs : never;\n","import type { MongoExpr, MongoUpdateDocument, MongoValue, RawPipeline } from './values';\n\nabstract class MongoCommand {\n abstract readonly kind: string;\n readonly collection: string;\n\n protected constructor(collection: string) {\n this.collection = collection;\n }\n\n protected freeze(): void {\n Object.freeze(this);\n }\n}\n\nexport interface FindOptions {\n readonly projection?: Record<string, 1 | 0>;\n readonly sort?: Record<string, 1 | -1>;\n readonly limit?: number;\n readonly skip?: number;\n}\n\nexport class FindCommand extends MongoCommand {\n readonly kind = 'find' as const;\n readonly filter: MongoExpr | undefined;\n readonly projection: Record<string, 1 | 0> | undefined;\n readonly sort: Record<string, 1 | -1> | undefined;\n readonly limit: number | undefined;\n readonly skip: number | undefined;\n\n constructor(collection: string, filter?: MongoExpr, options?: FindOptions) {\n super(collection);\n this.filter = filter;\n this.projection = options?.projection;\n this.sort = options?.sort;\n this.limit = options?.limit;\n this.skip = options?.skip;\n this.freeze();\n }\n}\n\nexport class InsertOneCommand extends MongoCommand {\n readonly kind = 'insertOne' as const;\n readonly document: Record<string, MongoValue>;\n\n constructor(collection: string, document: Record<string, MongoValue>) {\n super(collection);\n this.document = document;\n this.freeze();\n }\n}\n\nexport class UpdateOneCommand extends MongoCommand {\n readonly kind = 'updateOne' as const;\n readonly filter: MongoExpr;\n readonly update: MongoUpdateDocument;\n\n constructor(collection: string, filter: MongoExpr, update: MongoUpdateDocument) {\n super(collection);\n this.filter = filter;\n this.update = update;\n this.freeze();\n }\n}\n\nexport class DeleteOneCommand extends MongoCommand {\n readonly kind = 'deleteOne' as const;\n readonly filter: MongoExpr;\n\n constructor(collection: string, filter: MongoExpr) {\n super(collection);\n this.filter = filter;\n this.freeze();\n }\n}\n\nexport class AggregateCommand extends MongoCommand {\n readonly kind = 'aggregate' as const;\n readonly pipeline: RawPipeline;\n\n constructor(collection: string, pipeline: RawPipeline) {\n super(collection);\n this.pipeline = pipeline;\n this.freeze();\n }\n}\n\nexport type AnyMongoCommand =\n | FindCommand\n | InsertOneCommand\n | UpdateOneCommand\n | DeleteOneCommand\n | AggregateCommand;\n","export class MongoParamRef {\n readonly value: unknown;\n readonly name: string | undefined;\n readonly codecId: string | undefined;\n\n constructor(value: unknown, options?: { name?: string; codecId?: string }) {\n this.value = value;\n this.name = options?.name;\n this.codecId = options?.codecId;\n Object.freeze(this);\n }\n\n static of(value: unknown, options?: { name?: string; codecId?: string }): MongoParamRef {\n return new MongoParamRef(value, options);\n }\n}\n","export interface DomainModelShape {\n readonly fields: Record<string, unknown>;\n readonly relations: Record<string, { readonly to: string }>;\n readonly discriminator?: { readonly field: string };\n readonly variants?: Record<string, unknown>;\n readonly base?: string;\n}\n\nexport interface DomainContractShape {\n readonly roots: Record<string, string>;\n readonly models: Record<string, DomainModelShape>;\n}\n\nexport interface DomainValidationResult {\n readonly warnings: string[];\n}\n\nexport function validateContractDomain(contract: DomainContractShape): DomainValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n const modelNames = new Set(Object.keys(contract.models));\n\n validateRoots(contract, modelNames, errors);\n validateVariantsAndBases(contract, modelNames, errors);\n validateRelationTargets(contract, modelNames, errors);\n validateDiscriminators(contract, errors);\n detectOrphanedModels(contract, modelNames, warnings);\n\n if (errors.length > 0) {\n throw new Error(`Contract domain validation failed:\\n- ${errors.join('\\n- ')}`);\n }\n\n return { warnings };\n}\n\nfunction validateRoots(\n contract: DomainContractShape,\n modelNames: Set<string>,\n errors: string[],\n): void {\n const seenValues = new Set<string>();\n for (const [rootKey, modelName] of Object.entries(contract.roots)) {\n if (seenValues.has(modelName)) {\n errors.push(`Duplicate root value: \"${modelName}\" is mapped by multiple root keys`);\n }\n seenValues.add(modelName);\n\n if (!modelNames.has(modelName)) {\n errors.push(\n `Root \"${rootKey}\" references model \"${modelName}\" which does not exist in models`,\n );\n }\n }\n}\n\nfunction validateVariantsAndBases(\n contract: DomainContractShape,\n modelNames: Set<string>,\n errors: string[],\n): void {\n for (const [modelName, model] of Object.entries(contract.models)) {\n if (model.variants) {\n for (const variantName of Object.keys(model.variants)) {\n if (!modelNames.has(variantName)) {\n errors.push(\n `Model \"${modelName}\" lists variant \"${variantName}\" which does not exist in models`,\n );\n continue;\n }\n const variantModel = contract.models[variantName];\n if (!variantModel) continue;\n if (variantModel.base !== modelName) {\n errors.push(\n `Variant \"${variantName}\" has base \"${variantModel.base ?? '(none)'}\" but expected \"${modelName}\"`,\n );\n }\n }\n }\n\n if (model.base) {\n if (!modelNames.has(model.base)) {\n errors.push(`Model \"${modelName}\" has base \"${model.base}\" which does not exist in models`);\n continue;\n }\n const baseModel = contract.models[model.base];\n if (!baseModel) continue;\n if (!baseModel.variants || !(modelName in baseModel.variants)) {\n errors.push(\n `Model \"${modelName}\" has base \"${model.base}\" which does not list it as a variant`,\n );\n }\n }\n }\n}\n\nfunction validateRelationTargets(\n contract: DomainContractShape,\n modelNames: Set<string>,\n errors: string[],\n): void {\n for (const [modelName, model] of Object.entries(contract.models)) {\n for (const [relName, relation] of Object.entries(model.relations)) {\n if (!modelNames.has(relation.to)) {\n errors.push(\n `Relation \"${relName}\" on model \"${modelName}\" targets \"${relation.to}\" which does not exist in models`,\n );\n }\n }\n }\n}\n\nfunction validateDiscriminators(contract: DomainContractShape, errors: string[]): void {\n for (const [modelName, model] of Object.entries(contract.models)) {\n if (model.discriminator) {\n if (!model.variants || Object.keys(model.variants).length === 0) {\n errors.push(`Model \"${modelName}\" has discriminator but no variants`);\n }\n if (!(model.discriminator.field in model.fields)) {\n errors.push(\n `Discriminator field \"${model.discriminator.field}\" is not a field on model \"${modelName}\"`,\n );\n }\n }\n\n if (model.variants && Object.keys(model.variants).length > 0 && !model.discriminator) {\n errors.push(`Model \"${modelName}\" has variants but no discriminator`);\n }\n\n // Single-level polymorphism only: a variant (model with `base`) cannot itself\n // declare discriminator/variants. Multi-level polymorphism is out of scope per ADR 2.\n if (model.base) {\n if (model.discriminator) {\n errors.push(`Model \"${modelName}\" has base and must not have discriminator`);\n }\n if (model.variants && Object.keys(model.variants).length > 0) {\n errors.push(`Model \"${modelName}\" has base and must not have variants`);\n }\n }\n }\n}\n\nfunction detectOrphanedModels(\n contract: DomainContractShape,\n modelNames: Set<string>,\n warnings: string[],\n): void {\n const referenced = new Set<string>();\n\n for (const modelName of Object.values(contract.roots)) {\n referenced.add(modelName);\n }\n\n for (const model of Object.values(contract.models)) {\n for (const relation of Object.values(model.relations)) {\n referenced.add(relation.to);\n }\n if (model.variants) {\n for (const variantName of Object.keys(model.variants)) {\n referenced.add(variantName);\n }\n }\n if (model.base) {\n referenced.add(model.base);\n }\n }\n\n for (const modelName of modelNames) {\n if (!referenced.has(modelName)) {\n warnings.push(\n `Orphaned model: \"${modelName}\" is not referenced by any root, relation, or variant`,\n );\n }\n }\n}\n","import { type } from 'arktype';\n\nconst MongoModelFieldSchema = type({\n '+': 'reject',\n codecId: 'string',\n nullable: 'boolean',\n});\n\nconst MongoModelStorageSchema = type({\n '+': 'reject',\n 'collection?': 'string',\n});\n\nconst MongoDiscriminatorSchema = type({\n '+': 'reject',\n field: 'string',\n});\n\nconst MongoVariantEntrySchema = type({\n '+': 'reject',\n value: 'string',\n});\n\nconst MongoReferenceRelationOnSchema = type({\n '+': 'reject',\n localFields: 'string[]',\n targetFields: 'string[]',\n});\n\nconst MongoReferenceRelationSchema = type({\n '+': 'reject',\n to: 'string',\n cardinality: \"'1:1' | '1:N' | 'N:1'\",\n strategy: \"'reference'\",\n on: MongoReferenceRelationOnSchema,\n});\n\nconst MongoEmbedRelationSchema = type({\n '+': 'reject',\n to: 'string',\n cardinality: \"'1:1' | '1:N'\",\n strategy: \"'embed'\",\n field: 'string',\n});\n\nconst MongoRelationSchema = MongoReferenceRelationSchema.or(MongoEmbedRelationSchema);\n\nconst MongoModelDefinitionSchema = type({\n '+': 'reject',\n fields: type('Record<string, unknown>').pipe((fields) => {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(fields)) {\n const parsed = MongoModelFieldSchema(value);\n if (parsed instanceof type.errors) {\n throw new Error(`Invalid field \"${key}\": ${parsed.summary}`);\n }\n result[key] = parsed;\n }\n return result;\n }),\n storage: MongoModelStorageSchema,\n relations: type('Record<string, unknown>').pipe((relations) => {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(relations)) {\n const parsed = MongoRelationSchema(value);\n if (parsed instanceof type.errors) {\n throw new Error(`Invalid relation \"${key}\": ${parsed.summary}`);\n }\n result[key] = parsed;\n }\n return result;\n }),\n 'discriminator?': MongoDiscriminatorSchema,\n 'variants?': type('Record<string, unknown>').pipe((variants) => {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(variants)) {\n const parsed = MongoVariantEntrySchema(value);\n if (parsed instanceof type.errors) {\n throw new Error(`Invalid variant \"${key}\": ${parsed.summary}`);\n }\n result[key] = parsed;\n }\n return result;\n }),\n 'base?': 'string',\n});\n\nconst MongoStorageCollectionSchema = type({ '+': 'reject' });\n\nexport const MongoContractSchema = type({\n '+': 'reject',\n targetFamily: \"'mongo'\",\n roots: 'Record<string, string>',\n storage: type({\n '+': 'reject',\n collections: type('Record<string, unknown>').pipe((collections) => {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(collections)) {\n const parsed = MongoStorageCollectionSchema(value);\n if (parsed instanceof type.errors) {\n throw new Error(`Invalid collection \"${key}\": ${parsed.summary}`);\n }\n result[key] = parsed;\n }\n return result;\n }),\n }),\n models: type('Record<string, unknown>').pipe((models) => {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(models)) {\n const parsed = MongoModelDefinitionSchema(value);\n if (parsed instanceof type.errors) {\n throw new Error(`Invalid model \"${key}\": ${parsed.summary}`);\n }\n result[key] = parsed;\n }\n return result;\n }),\n});\n","import type { MongoContract } from './contract-types';\n\nexport function validateMongoStorage(contract: MongoContract): void {\n const errors: string[] = [];\n\n for (const [modelName, model] of Object.entries(contract.models)) {\n if (model.storage.collection && !(model.storage.collection in contract.storage.collections)) {\n errors.push(\n `Model \"${modelName}\" references collection \"${model.storage.collection}\" which is not in storage.collections`,\n );\n }\n\n // Mongo does not support multi-table inheritance (ADR 2): all variants of a base\n // must share the same collection (single-table inheritance only).\n if (model.base) {\n const baseModel = contract.models[model.base];\n if (baseModel) {\n const variantCollection = model.storage.collection;\n const baseCollection = baseModel.storage.collection;\n if (variantCollection !== baseCollection) {\n errors.push(\n `Mongo does not support multi-table inheritance; variant \"${modelName}\" must share its base's collection (\"${baseCollection ?? '(none)'}\"), but has \"${variantCollection ?? '(none)'}\"`,\n );\n }\n }\n }\n\n for (const [relName, relation] of Object.entries(model.relations)) {\n if (relation.strategy === 'embed') {\n const target = contract.models[relation.to];\n if (target?.storage.collection) {\n errors.push(\n `Embed relation \"${relName}\" targets \"${relation.to}\" which must not have a collection`,\n );\n }\n }\n\n if (relation.strategy === 'reference') {\n for (const localField of relation.on.localFields) {\n if (!(localField in model.fields)) {\n errors.push(\n `Reference relation \"${relName}\": localField \"${localField}\" is not a field on model \"${modelName}\"`,\n );\n }\n }\n\n const targetModel = contract.models[relation.to];\n if (targetModel) {\n for (const targetField of relation.on.targetFields) {\n if (!(targetField in targetModel.fields)) {\n errors.push(\n `Reference relation \"${relName}\": targetField \"${targetField}\" is not a field on model \"${relation.to}\"`,\n );\n }\n }\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Contract storage validation failed:\\n- ${errors.join('\\n- ')}`);\n }\n}\n","import { type as arktypeType } from 'arktype';\nimport { MongoContractSchema } from './contract-schema';\nimport type { MongoContract } from './contract-types';\nimport { validateContractDomain } from './validate-domain';\nimport { validateMongoStorage } from './validate-storage';\n\nexport interface MongoContractIndices {\n readonly variantToBase: Record<string, string>;\n readonly modelToVariants: Record<string, string[]>;\n}\n\nexport interface ValidatedMongoContract<TContract extends MongoContract> {\n readonly contract: TContract;\n readonly indices: MongoContractIndices;\n readonly warnings: string[];\n}\n\nexport function validateMongoContract<TContract extends MongoContract>(\n value: unknown,\n): ValidatedMongoContract<TContract> {\n const parsed = MongoContractSchema(value);\n if (parsed instanceof arktypeType.errors) {\n throw new Error(`Contract structural validation failed: ${parsed.summary}`);\n }\n\n const contract = parsed as unknown as TContract;\n\n const { warnings } = validateContractDomain(contract);\n validateMongoStorage(contract);\n\n const indices = buildIndices(contract);\n\n return { contract, indices, warnings };\n}\n\nfunction buildIndices(contract: MongoContract): MongoContractIndices {\n const variantToBase: Record<string, string> = {};\n const modelToVariants: Record<string, string[]> = {};\n\n for (const [modelName, model] of Object.entries(contract.models)) {\n if (model.base) {\n variantToBase[modelName] = model.base;\n }\n if (model.variants) {\n modelToVariants[modelName] = Object.keys(model.variants);\n }\n }\n\n return { variantToBase, modelToVariants };\n}\n","import type { Document, RawPipeline } from './values';\n\nabstract class MongoWireCommand {\n abstract readonly kind: string;\n readonly collection: string;\n\n protected constructor(collection: string) {\n this.collection = collection;\n }\n\n protected freeze(): void {\n Object.freeze(this);\n }\n}\n\nexport class FindWireCommand extends MongoWireCommand {\n readonly kind = 'find' as const;\n readonly filter: Document | undefined;\n readonly projection: Document | undefined;\n readonly sort: Document | undefined;\n readonly limit: number | undefined;\n readonly skip: number | undefined;\n\n constructor(\n collection: string,\n filter?: Document,\n options?: {\n projection?: Document;\n sort?: Document;\n limit?: number;\n skip?: number;\n },\n ) {\n super(collection);\n this.filter = filter;\n this.projection = options?.projection;\n this.sort = options?.sort;\n this.limit = options?.limit;\n this.skip = options?.skip;\n this.freeze();\n }\n}\n\nexport class InsertOneWireCommand extends MongoWireCommand {\n readonly kind = 'insertOne' as const;\n readonly document: Document;\n\n constructor(collection: string, document: Document) {\n super(collection);\n this.document = document;\n this.freeze();\n }\n}\n\nexport class UpdateOneWireCommand extends MongoWireCommand {\n readonly kind = 'updateOne' as const;\n readonly filter: Document;\n readonly update: Document;\n\n constructor(collection: string, filter: Document, update: Document) {\n super(collection);\n this.filter = filter;\n this.update = update;\n this.freeze();\n }\n}\n\nexport class DeleteOneWireCommand extends MongoWireCommand {\n readonly kind = 'deleteOne' as const;\n readonly filter: Document;\n\n constructor(collection: string, filter: Document) {\n super(collection);\n this.filter = filter;\n this.freeze();\n }\n}\n\nexport class AggregateWireCommand extends MongoWireCommand {\n readonly kind = 'aggregate' as const;\n readonly pipeline: RawPipeline;\n\n constructor(collection: string, pipeline: RawPipeline) {\n super(collection);\n this.pipeline = pipeline;\n this.freeze();\n }\n}\n\nexport type AnyMongoWireCommand =\n | FindWireCommand\n | InsertOneWireCommand\n | UpdateOneWireCommand\n | DeleteOneWireCommand\n | AggregateWireCommand;\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-next/mongo-core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "Core types for Prisma Next MongoDB support",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"test": "vitest run --passWithNoTests",
|
|
10
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"lint": "biome check . --error-on-warnings",
|
|
13
|
+
"lint:fix": "biome check --write .",
|
|
14
|
+
"lint:fix:unsafe": "biome check --write --unsafe .",
|
|
15
|
+
"clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@prisma-next/contract": "workspace:*",
|
|
19
|
+
"arktype": "catalog:"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@prisma-next/test-utils": "workspace:*",
|
|
23
|
+
"@prisma-next/tsconfig": "workspace:*",
|
|
24
|
+
"@prisma-next/tsdown": "workspace:*",
|
|
25
|
+
"tsdown": "catalog:",
|
|
26
|
+
"typescript": "catalog:",
|
|
27
|
+
"vitest": "catalog:"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"src"
|
|
32
|
+
],
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./dist/index.mjs",
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"main": "./dist/index.mjs",
|
|
38
|
+
"module": "./dist/index.mjs",
|
|
39
|
+
"types": "./dist/index.d.mts",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/prisma/prisma-next.git",
|
|
43
|
+
"directory": "packages/2-mongo-family/1-core"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MongoContract } from './contract-types';
|
|
2
|
+
import type { MongoExecutionPlan, MongoQueryPlan } from './plan';
|
|
3
|
+
|
|
4
|
+
export interface MongoLoweringContext {
|
|
5
|
+
readonly contract: MongoContract;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface MongoAdapter {
|
|
9
|
+
lower<Row>(
|
|
10
|
+
queryPlan: MongoQueryPlan<Row>,
|
|
11
|
+
context: MongoLoweringContext,
|
|
12
|
+
): MongoExecutionPlan<Row>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { MongoCodec } from './codecs';
|
|
2
|
+
|
|
3
|
+
export interface MongoCodecRegistry {
|
|
4
|
+
get(id: string): MongoCodec<string> | undefined;
|
|
5
|
+
has(id: string): boolean;
|
|
6
|
+
register(codec: MongoCodec<string>): void;
|
|
7
|
+
[Symbol.iterator](): Iterator<MongoCodec<string>>;
|
|
8
|
+
values(): IterableIterator<MongoCodec<string>>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class MongoCodecRegistryImpl implements MongoCodecRegistry {
|
|
12
|
+
readonly #byId = new Map<string, MongoCodec<string>>();
|
|
13
|
+
|
|
14
|
+
get(id: string): MongoCodec<string> | undefined {
|
|
15
|
+
return this.#byId.get(id);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
has(id: string): boolean {
|
|
19
|
+
return this.#byId.has(id);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
register(codec: MongoCodec<string>): void {
|
|
23
|
+
if (this.#byId.has(codec.id)) {
|
|
24
|
+
throw new Error(`Codec with ID '${codec.id}' is already registered`);
|
|
25
|
+
}
|
|
26
|
+
this.#byId.set(codec.id, codec);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
*[Symbol.iterator](): Iterator<MongoCodec<string>> {
|
|
30
|
+
yield* this.#byId.values();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
values(): IterableIterator<MongoCodec<string>> {
|
|
34
|
+
return this.#byId.values();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createMongoCodecRegistry(): MongoCodecRegistry {
|
|
39
|
+
return new MongoCodecRegistryImpl();
|
|
40
|
+
}
|
package/src/codecs.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface MongoCodec<Id extends string = string, TWire = unknown, TJs = unknown> {
|
|
2
|
+
readonly id: Id;
|
|
3
|
+
readonly targetTypes: readonly string[];
|
|
4
|
+
decode(wire: TWire): TJs;
|
|
5
|
+
encode?(value: TJs): TWire;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function mongoCodec<Id extends string, TWire, TJs>(config: {
|
|
9
|
+
typeId: Id;
|
|
10
|
+
targetTypes: readonly string[];
|
|
11
|
+
encode: (value: TJs) => TWire;
|
|
12
|
+
decode: (wire: TWire) => TJs;
|
|
13
|
+
}): MongoCodec<Id, TWire, TJs> {
|
|
14
|
+
return {
|
|
15
|
+
id: config.typeId,
|
|
16
|
+
targetTypes: config.targetTypes,
|
|
17
|
+
decode: config.decode,
|
|
18
|
+
encode: config.encode,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type MongoCodecJsType<T> = T extends MongoCodec<string, unknown, infer TJs> ? TJs : never;
|