@prisma-next/mongo-orm 0.3.0-dev.134 → 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/dist/index.mjs CHANGED
@@ -1,77 +1,608 @@
1
- import { AggregateCommand, FindCommand } from "@prisma-next/mongo-core";
1
+ import { AsyncIterableResult } from "@prisma-next/framework-components/runtime";
2
+ import { AggregateCommand, DeleteManyCommand, FindOneAndDeleteCommand, FindOneAndUpdateCommand, InsertManyCommand, InsertOneCommand, MongoAndExpr, MongoFieldFilter, MongoLimitStage, MongoLookupStage, MongoMatchStage, MongoProjectStage, MongoSkipStage, MongoSortStage, MongoUnwindStage, RawAggregateCommand, RawDeleteManyCommand, RawDeleteOneCommand, RawFindOneAndDeleteCommand, RawFindOneAndUpdateCommand, RawInsertManyCommand, RawInsertOneCommand, RawUpdateManyCommand, RawUpdateOneCommand, UpdateManyCommand, isMongoFilterExpr } from "@prisma-next/mongo-query-ast/execution";
3
+ import { MongoParamRef } from "@prisma-next/mongo-value";
2
4
 
3
- //#region src/mongo-orm.ts
4
- const stubMeta = {
5
- target: "mongo",
6
- storageHash: "orm",
7
- lane: "mongo-orm",
8
- paramDescriptors: []
9
- };
10
- function resolveCollection(model, modelName) {
11
- return model.storage.collection ?? modelName;
5
+ //#region src/collection-state.ts
6
+ function emptyCollectionState() {
7
+ return {
8
+ filters: [],
9
+ includes: [],
10
+ orderBy: void 0,
11
+ selectedFields: void 0,
12
+ limit: void 0,
13
+ offset: void 0
14
+ };
12
15
  }
13
- function buildLookupStages(contract, model, include) {
16
+
17
+ //#endregion
18
+ //#region src/compile.ts
19
+ function compileIncludes(includes) {
14
20
  const stages = [];
15
- for (const [relName, shouldInclude] of Object.entries(include)) {
16
- if (!shouldInclude) continue;
17
- const relation = model.relations?.[relName];
18
- if (!relation) continue;
19
- const targetModel = contract.models[relation.to];
20
- if (!targetModel || targetModel.owner) continue;
21
- const ref = relation;
22
- if (ref.on.localFields.length !== 1 || ref.on.targetFields.length !== 1) throw new Error(`Compound references are not yet supported: relation "${relName}" has ${ref.on.localFields.length} local field(s) and ${ref.on.targetFields.length} target field(s)`);
23
- const targetCollection = resolveCollection(targetModel, ref.to);
24
- stages.push({ $lookup: {
25
- from: targetCollection,
26
- localField: ref.on.localFields[0],
27
- foreignField: ref.on.targetFields[0],
28
- as: relName
29
- } });
30
- if (ref.cardinality === "N:1" || ref.cardinality === "1:1") stages.push({ $unwind: {
31
- path: `$${relName}`,
32
- preserveNullAndEmptyArrays: true
33
- } });
21
+ for (const inc of includes) {
22
+ stages.push(new MongoLookupStage({
23
+ from: inc.from,
24
+ localField: inc.localField,
25
+ foreignField: inc.foreignField,
26
+ as: inc.relationName
27
+ }));
28
+ if (inc.cardinality === "N:1" || inc.cardinality === "1:1") stages.push(new MongoUnwindStage(`$${inc.relationName}`, true));
34
29
  }
35
30
  return stages;
36
31
  }
37
- var MongoCollectionImpl = class {
32
+ function compileMongoQuery(collection, state, storageHash) {
33
+ const stages = [];
34
+ const singleFilter = state.filters.length === 1 ? state.filters[0] : void 0;
35
+ if (singleFilter) stages.push(new MongoMatchStage(singleFilter));
36
+ else if (state.filters.length > 1) stages.push(new MongoMatchStage(MongoAndExpr.of([...state.filters])));
37
+ if (state.includes.length > 0) stages.push(...compileIncludes(state.includes));
38
+ if (state.orderBy) stages.push(new MongoSortStage(state.orderBy));
39
+ if (state.offset !== void 0) stages.push(new MongoSkipStage(state.offset));
40
+ if (state.limit !== void 0) stages.push(new MongoLimitStage(state.limit));
41
+ if (state.selectedFields && state.selectedFields.length > 0) {
42
+ const projection = {};
43
+ for (const field of state.selectedFields) projection[field] = 1;
44
+ if (!Object.hasOwn(projection, "_id")) projection["_id"] = 0;
45
+ stages.push(new MongoProjectStage(projection));
46
+ }
47
+ const meta = {
48
+ target: "mongo",
49
+ storageHash,
50
+ lane: "mongo-orm",
51
+ paramDescriptors: []
52
+ };
53
+ return {
54
+ collection,
55
+ command: new AggregateCommand(collection, stages),
56
+ meta
57
+ };
58
+ }
59
+
60
+ //#endregion
61
+ //#region src/field-accessor.ts
62
+ function createFieldExpression(fieldPath) {
63
+ return {
64
+ set(value) {
65
+ return {
66
+ operator: "$set",
67
+ field: fieldPath,
68
+ value: new MongoParamRef(value)
69
+ };
70
+ },
71
+ unset() {
72
+ return {
73
+ operator: "$unset",
74
+ field: fieldPath,
75
+ value: new MongoParamRef("")
76
+ };
77
+ },
78
+ inc(value) {
79
+ return {
80
+ operator: "$inc",
81
+ field: fieldPath,
82
+ value: new MongoParamRef(value)
83
+ };
84
+ },
85
+ mul(value) {
86
+ return {
87
+ operator: "$mul",
88
+ field: fieldPath,
89
+ value: new MongoParamRef(value)
90
+ };
91
+ },
92
+ push(value) {
93
+ return {
94
+ operator: "$push",
95
+ field: fieldPath,
96
+ value: new MongoParamRef(value)
97
+ };
98
+ },
99
+ pull(match) {
100
+ return {
101
+ operator: "$pull",
102
+ field: fieldPath,
103
+ value: new MongoParamRef(match)
104
+ };
105
+ },
106
+ addToSet(value) {
107
+ return {
108
+ operator: "$addToSet",
109
+ field: fieldPath,
110
+ value: new MongoParamRef(value)
111
+ };
112
+ },
113
+ pop(end) {
114
+ return {
115
+ operator: "$pop",
116
+ field: fieldPath,
117
+ value: new MongoParamRef(end)
118
+ };
119
+ }
120
+ };
121
+ }
122
+ function createFieldAccessor() {
123
+ return new Proxy((() => {}), {
124
+ get(_target, prop) {
125
+ return createFieldExpression(prop);
126
+ },
127
+ apply(_target, _thisArg, args) {
128
+ return createFieldExpression(args[0]);
129
+ }
130
+ });
131
+ }
132
+ function compileFieldOperations(ops, wrapValue) {
133
+ const grouped = {};
134
+ for (const op of ops) {
135
+ let group = grouped[op.operator];
136
+ if (!group) {
137
+ group = {};
138
+ grouped[op.operator] = group;
139
+ }
140
+ group[op.field] = wrapValue(op.field, op.value, op.operator);
141
+ }
142
+ return grouped;
143
+ }
144
+
145
+ //#endregion
146
+ //#region src/collection.ts
147
+ function resolveCollectionName(model, modelName) {
148
+ return model.storage.collection ?? modelName;
149
+ }
150
+ var MongoCollectionImpl = class MongoCollectionImpl {
38
151
  #contract;
39
152
  #modelName;
40
153
  #executor;
154
+ #collectionName;
155
+ #state;
156
+ #variantName;
41
157
  constructor(contract, modelName, executor) {
42
158
  this.#contract = contract;
43
159
  this.#modelName = modelName;
44
160
  this.#executor = executor;
161
+ const model = contract.models[modelName];
162
+ this.#collectionName = resolveCollectionName(model, modelName);
163
+ this.#state = emptyCollectionState();
45
164
  }
46
- findMany(options) {
165
+ variant(variantName) {
47
166
  const model = this.#contract.models[this.#modelName];
48
- const collection = resolveCollection(model, this.#modelName);
49
- const filter = options?.where ? options.where : void 0;
50
- const include = options?.include;
51
- const hasIncludes = include && Object.keys(include).length > 0;
52
- let plan;
53
- if (hasIncludes) {
54
- const pipeline = [];
55
- if (filter && Object.keys(filter).length > 0) pipeline.push({ $match: filter });
56
- pipeline.push(...buildLookupStages(this.#contract, model, include));
57
- plan = {
58
- command: new AggregateCommand(collection, pipeline),
59
- meta: stubMeta
60
- };
61
- } else plan = {
62
- command: new FindCommand(collection, filter),
63
- meta: stubMeta
167
+ if (!model?.discriminator || !model.variants) return this;
168
+ const variantEntry = model.variants[variantName];
169
+ if (!variantEntry) return this;
170
+ const filter = MongoFieldFilter.eq(model.discriminator.field, new MongoParamRef(variantEntry.value));
171
+ return this.#cloneWithVariant({ filters: [...this.#state.filters, filter] }, variantName);
172
+ }
173
+ where(filter) {
174
+ if (isMongoFilterExpr(filter)) return this.#clone({ filters: [...this.#state.filters, filter] });
175
+ const compiled = this.#compileWhereObject(filter);
176
+ return this.#clone({ filters: [...this.#state.filters, ...compiled] });
177
+ }
178
+ select(...fields) {
179
+ return this.#clone({ selectedFields: [...this.#state.selectedFields ?? [], ...fields] });
180
+ }
181
+ include(relationName) {
182
+ const relation = this.#contract.models[this.#modelName].relations?.[relationName];
183
+ if (!relation) throw new Error(`Unknown relation "${relationName}" on model "${this.#modelName}"`);
184
+ if (!("on" in relation)) throw new Error(`Relation "${relationName}" is an embed relation — only reference relations can be included`);
185
+ const ref = relation;
186
+ const localField = ref.on.localFields[0];
187
+ const foreignField = ref.on.targetFields[0];
188
+ if (!localField || !foreignField || ref.on.localFields.length !== 1 || ref.on.targetFields.length !== 1) throw new Error(`Compound references are not yet supported: relation "${relationName}"`);
189
+ const targetModel = this.#contract.models[ref.to];
190
+ if (!targetModel) throw new Error(`Target model "${ref.to}" not found for relation "${relationName}"`);
191
+ const includeExpr = {
192
+ relationName,
193
+ from: resolveCollectionName(targetModel, ref.to),
194
+ localField,
195
+ foreignField,
196
+ cardinality: ref.cardinality
64
197
  };
198
+ return this.#clone({ includes: [...this.#state.includes, includeExpr] });
199
+ }
200
+ orderBy(spec) {
201
+ const merged = {
202
+ ...this.#state.orderBy,
203
+ ...spec
204
+ };
205
+ return this.#clone({ orderBy: merged });
206
+ }
207
+ take(n) {
208
+ return this.#clone({ limit: n });
209
+ }
210
+ skip(n) {
211
+ return this.#clone({ offset: n });
212
+ }
213
+ all() {
214
+ return this.#execute();
215
+ }
216
+ async first() {
217
+ const result = this.#clone({ limit: 1 }).#execute();
218
+ for await (const row of result) return row;
219
+ return null;
220
+ }
221
+ async create(data) {
222
+ this.#rejectIncludes("create");
223
+ const normalized = this.#injectDiscriminator(this.#stripUndefined(data));
224
+ const document = this.#toDocument(normalized);
225
+ const command = new InsertOneCommand(this.#collectionName, document);
226
+ return {
227
+ _id: (await this.#drainPlan(command))[0].insertedId,
228
+ ...normalized
229
+ };
230
+ }
231
+ createAll(data) {
232
+ this.#rejectIncludes("createAll");
233
+ const self = this;
234
+ async function* gen() {
235
+ const normalizedRows = data.map((d) => self.#injectDiscriminator(self.#stripUndefined(d)));
236
+ const documents = normalizedRows.map((d) => self.#toDocument(d));
237
+ const command = new InsertManyCommand(self.#collectionName, documents);
238
+ const insertedIds = (await self.#drainPlan(command))[0].insertedIds;
239
+ for (let i = 0; i < normalizedRows.length; i++) yield {
240
+ _id: insertedIds[i],
241
+ ...normalizedRows[i]
242
+ };
243
+ }
244
+ return new AsyncIterableResult(gen());
245
+ }
246
+ async createCount(data) {
247
+ this.#rejectIncludes("createCount");
248
+ const documents = data.map((d) => this.#toDocument(this.#injectDiscriminator(d)));
249
+ const command = new InsertManyCommand(this.#collectionName, documents);
250
+ return (await this.#drainPlan(command))[0].insertedCount;
251
+ }
252
+ async update(dataOrCallback) {
253
+ this.#requireFilters("update");
254
+ this.#rejectWindowing("update");
255
+ this.#rejectIncludes("update");
256
+ const filter = this.#mergeFilters();
257
+ const updateDoc = this.#resolveUpdateDoc(dataOrCallback);
258
+ const command = new FindOneAndUpdateCommand(this.#collectionName, filter, updateDoc, false);
259
+ return (await this.#drainPlan(command))[0] ?? null;
260
+ }
261
+ updateAll(dataOrCallback) {
262
+ this.#requireFilters("updateAll");
263
+ this.#rejectWindowing("updateAll");
264
+ const self = this;
265
+ async function* gen() {
266
+ const ids = await self.#readMatchingIds();
267
+ if (ids.length === 0) return;
268
+ const filter = self.#mergeFilters();
269
+ const updateDoc = self.#resolveUpdateDoc(dataOrCallback);
270
+ const command = new UpdateManyCommand(self.#collectionName, filter, updateDoc);
271
+ await self.#drainPlan(command);
272
+ const idFilter = MongoFieldFilter.in("_id", ids.map((id) => new MongoParamRef(id)));
273
+ yield* self.#clone({ filters: [idFilter] }).#execute();
274
+ }
275
+ return new AsyncIterableResult(gen());
276
+ }
277
+ async updateCount(dataOrCallback) {
278
+ this.#requireFilters("updateCount");
279
+ this.#rejectWindowing("updateCount");
280
+ this.#rejectIncludes("updateCount");
281
+ const filter = this.#mergeFilters();
282
+ const updateDoc = this.#resolveUpdateDoc(dataOrCallback);
283
+ const command = new UpdateManyCommand(this.#collectionName, filter, updateDoc);
284
+ return (await this.#drainPlan(command))[0].modifiedCount;
285
+ }
286
+ async delete() {
287
+ this.#requireFilters("delete");
288
+ this.#rejectWindowing("delete");
289
+ this.#rejectIncludes("delete");
290
+ const filter = this.#mergeFilters();
291
+ const command = new FindOneAndDeleteCommand(this.#collectionName, filter);
292
+ return (await this.#drainPlan(command))[0] ?? null;
293
+ }
294
+ deleteAll() {
295
+ this.#requireFilters("deleteAll");
296
+ this.#rejectWindowing("deleteAll");
297
+ const self = this;
298
+ async function* gen() {
299
+ const docs = [];
300
+ for await (const row of self.#execute()) docs.push(row);
301
+ const filter = self.#mergeFilters();
302
+ const command = new DeleteManyCommand(self.#collectionName, filter);
303
+ await self.#drainPlan(command);
304
+ yield* docs;
305
+ }
306
+ return new AsyncIterableResult(gen());
307
+ }
308
+ async deleteCount() {
309
+ this.#requireFilters("deleteCount");
310
+ this.#rejectWindowing("deleteCount");
311
+ this.#rejectIncludes("deleteCount");
312
+ const filter = this.#mergeFilters();
313
+ const command = new DeleteManyCommand(this.#collectionName, filter);
314
+ return (await this.#drainPlan(command))[0].deletedCount;
315
+ }
316
+ async upsert(input) {
317
+ this.#requireFilters("upsert");
318
+ this.#rejectWindowing("upsert");
319
+ this.#rejectIncludes("upsert");
320
+ const filter = this.#mergeFilters();
321
+ const allCreateFields = this.#toDocument(this.#injectDiscriminator(input.create));
322
+ let updateDoc;
323
+ if (typeof input.update === "function") {
324
+ const accessor = createFieldAccessor();
325
+ const ops = input.update(accessor);
326
+ if (ops.find((op) => op.field === "_id")) throw new Error("Mutation payloads cannot modify `_id`");
327
+ const dotPathOp = ops.find((op) => op.field.includes("."));
328
+ if (dotPathOp) throw new Error(`upsert() does not support dot-path field operations (found "${dotPathOp.field}"). Dot-path updates conflict with \$setOnInsert on the insert path, producing incomplete documents. Use top-level field operations instead.`);
329
+ updateDoc = compileFieldOperations(ops, (field, value, operator) => this.#wrapFieldOpValue(field, value, operator));
330
+ } else {
331
+ const setFields = this.#toSetFields(input.update);
332
+ updateDoc = {};
333
+ if (Object.keys(setFields).length > 0) updateDoc["$set"] = setFields;
334
+ }
335
+ const updatedFields = /* @__PURE__ */ new Set();
336
+ for (const operatorGroup of Object.values(updateDoc)) for (const fieldPath of Object.keys(operatorGroup)) updatedFields.add(fieldPath.split(".")[0] ?? fieldPath);
337
+ const insertOnlyFields = {};
338
+ for (const [key, value] of Object.entries(allCreateFields)) if (!updatedFields.has(key)) insertOnlyFields[key] = value;
339
+ if (Object.keys(insertOnlyFields).length > 0) updateDoc["$setOnInsert"] = insertOnlyFields;
340
+ const command = new FindOneAndUpdateCommand(this.#collectionName, filter, updateDoc, true);
341
+ return (await this.#drainPlan(command))[0];
342
+ }
343
+ async #readMatchingIds() {
344
+ const idQuery = this.#clone({
345
+ includes: [],
346
+ selectedFields: ["_id"],
347
+ orderBy: void 0,
348
+ limit: void 0,
349
+ offset: void 0
350
+ });
351
+ const ids = [];
352
+ for await (const row of idQuery.#execute()) ids.push(row["_id"]);
353
+ return ids;
354
+ }
355
+ #execute() {
356
+ const plan = this.#compile();
65
357
  return this.#executor.execute(plan);
66
358
  }
359
+ #compile() {
360
+ return compileMongoQuery(this.#collectionName, this.#state, this.#contract.storage.storageHash);
361
+ }
362
+ #wrapCommand(command) {
363
+ return {
364
+ collection: this.#collectionName,
365
+ command,
366
+ meta: this.#planMeta()
367
+ };
368
+ }
369
+ async #drainPlan(command) {
370
+ const plan = this.#wrapCommand(command);
371
+ const result = this.#executor.execute(plan);
372
+ const rows = [];
373
+ for await (const row of result) rows.push(row);
374
+ return rows;
375
+ }
376
+ #modelFields() {
377
+ return this.#contract.models[this.#modelName]?.fields ?? {};
378
+ }
379
+ #compileWhereObject(data) {
380
+ const fields = this.#modelFields();
381
+ const filters = [];
382
+ for (const [key, value] of Object.entries(data)) {
383
+ if (value === void 0) continue;
384
+ const wrapped = this.#wrapFieldValue(value, fields[key]);
385
+ filters.push(MongoFieldFilter.eq(key, wrapped));
386
+ }
387
+ return filters;
388
+ }
389
+ #wrapFieldValue(value, field) {
390
+ if (field === void 0) return new MongoParamRef(value);
391
+ if (field.type.kind === "scalar") return new MongoParamRef(value, { codecId: field.type.codecId });
392
+ if (field.type.kind === "valueObject") {
393
+ const voName = field.type.name;
394
+ const voDef = this.#contract.valueObjects?.[voName];
395
+ if (!voDef || value === null) return new MongoParamRef(value);
396
+ if (field.many && Array.isArray(value)) return value.map((item) => this.#wrapValueObject(item, voDef));
397
+ return this.#wrapValueObject(value, voDef);
398
+ }
399
+ return new MongoParamRef(value);
400
+ }
401
+ #wrapValueObject(data, voDef) {
402
+ const doc = {};
403
+ for (const [key, value] of Object.entries(data)) {
404
+ if (value === void 0) continue;
405
+ const fieldDef = voDef.fields[key];
406
+ doc[key] = this.#wrapFieldValue(value, fieldDef);
407
+ }
408
+ return doc;
409
+ }
410
+ #toDocument(data) {
411
+ const fields = this.#modelFields();
412
+ const doc = {};
413
+ for (const [key, value] of Object.entries(data)) if (value !== void 0) doc[key] = this.#wrapFieldValue(value, fields[key]);
414
+ return doc;
415
+ }
416
+ #toSetFields(data) {
417
+ const fields = this.#modelFields();
418
+ const result = {};
419
+ for (const [key, value] of Object.entries(data)) {
420
+ if (key === "_id" && value !== void 0) throw new Error("Mutation payloads cannot modify `_id`");
421
+ if (value !== void 0) result[key] = this.#wrapFieldValue(value, fields[key]);
422
+ }
423
+ return result;
424
+ }
425
+ #stripUndefined(data) {
426
+ const result = {};
427
+ for (const [key, value] of Object.entries(data)) if (value !== void 0) result[key] = value;
428
+ return result;
429
+ }
430
+ #toUpdateDocument(data) {
431
+ return { $set: this.#toSetFields(data) };
432
+ }
433
+ #resolveUpdateDoc(dataOrCallback) {
434
+ if (typeof dataOrCallback === "function") {
435
+ const ops = dataOrCallback(createFieldAccessor());
436
+ if (ops.find((op) => op.field === "_id")) throw new Error("Mutation payloads cannot modify `_id`");
437
+ if (ops.length === 0) return { $set: {} };
438
+ return compileFieldOperations(ops, (field, value, operator) => this.#wrapFieldOpValue(field, value, operator));
439
+ }
440
+ return this.#toUpdateDocument(dataOrCallback);
441
+ }
442
+ #wrapFieldOpValue(field, value, operator) {
443
+ if (operator === "$unset") return value;
444
+ const topLevelField = field.split(".")[0] ?? field;
445
+ const contractField = this.#modelFields()[topLevelField];
446
+ if (!contractField) return value;
447
+ if (field.includes(".")) return this.#wrapDotPathValue(field, value);
448
+ if (value instanceof MongoParamRef && contractField.type.kind === "scalar") return new MongoParamRef(value.value, { codecId: contractField.type.codecId });
449
+ if (contractField.type.kind === "valueObject" && value instanceof MongoParamRef) {
450
+ const raw = value.value;
451
+ if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
452
+ const voName = contractField.type.name;
453
+ const voDef = this.#contract.valueObjects?.[voName];
454
+ if (voDef) return this.#wrapValueObject(raw, voDef);
455
+ }
456
+ }
457
+ return value;
458
+ }
459
+ #wrapDotPathValue(dotPath, value) {
460
+ const parts = dotPath.split(".");
461
+ const fields = this.#modelFields();
462
+ let currentField = parts[0] ? fields[parts[0]] : void 0;
463
+ for (let i = 1; i < parts.length; i++) {
464
+ if (!currentField || currentField.type.kind !== "valueObject") return value;
465
+ const voName = currentField.type.name;
466
+ const voDef = this.#contract.valueObjects?.[voName];
467
+ if (!voDef) return value;
468
+ const partKey = parts[i];
469
+ currentField = partKey ? voDef.fields[partKey] : void 0;
470
+ }
471
+ if (currentField?.type.kind === "scalar" && value instanceof MongoParamRef) return new MongoParamRef(value.value, { codecId: currentField.type.codecId });
472
+ if (currentField?.type.kind === "valueObject" && value instanceof MongoParamRef) {
473
+ const raw = value.value;
474
+ if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
475
+ const voName = currentField.type.name;
476
+ const voDef = this.#contract.valueObjects?.[voName];
477
+ if (voDef) return this.#wrapValueObject(raw, voDef);
478
+ }
479
+ }
480
+ return value;
481
+ }
482
+ #mergeFilters() {
483
+ const [single] = this.#state.filters;
484
+ if (this.#state.filters.length === 1 && single) return single;
485
+ return MongoAndExpr.of([...this.#state.filters]);
486
+ }
487
+ #requireFilters(methodName) {
488
+ if (this.#state.filters.length === 0) throw new Error(`${methodName}() requires a .where() filter. Call .where() before .${methodName}()`);
489
+ }
490
+ #rejectWindowing(methodName) {
491
+ if (this.#state.orderBy !== void 0 || this.#state.limit !== void 0 || this.#state.offset !== void 0) throw new Error(`${methodName}() does not support orderBy/skip/take. Remove windowing before calling .${methodName}()`);
492
+ }
493
+ #rejectIncludes(methodName) {
494
+ if (this.#state.includes.length > 0) throw new Error(`${methodName}() does not support .include(). Remove includes before calling .${methodName}()`);
495
+ }
496
+ #planMeta() {
497
+ return {
498
+ target: "mongo",
499
+ storageHash: this.#contract.storage.storageHash,
500
+ lane: "mongo-orm",
501
+ paramDescriptors: []
502
+ };
503
+ }
504
+ #injectDiscriminator(data) {
505
+ if (!this.#variantName) return data;
506
+ const model = this.#contract.models[this.#modelName];
507
+ if (!model?.discriminator || !model.variants) return data;
508
+ const variantEntry = model.variants[this.#variantName];
509
+ if (!variantEntry) return data;
510
+ return {
511
+ ...data,
512
+ [model.discriminator.field]: variantEntry.value
513
+ };
514
+ }
515
+ #clone(overrides) {
516
+ const instance = new MongoCollectionImpl(this.#contract, this.#modelName, this.#executor);
517
+ instance.#state = {
518
+ ...this.#state,
519
+ ...overrides
520
+ };
521
+ instance.#collectionName = this.#collectionName;
522
+ instance.#variantName = this.#variantName;
523
+ return instance;
524
+ }
525
+ #cloneWithVariant(overrides, variantName) {
526
+ const instance = new MongoCollectionImpl(this.#contract, this.#modelName, this.#executor);
527
+ instance.#state = {
528
+ ...this.#state,
529
+ ...overrides
530
+ };
531
+ instance.#collectionName = this.#collectionName;
532
+ instance.#variantName = variantName;
533
+ return instance;
534
+ }
67
535
  };
536
+ function createMongoCollection(contract, modelName, executor) {
537
+ return new MongoCollectionImpl(contract, modelName, executor);
538
+ }
539
+
540
+ //#endregion
541
+ //#region src/mongo-orm.ts
68
542
  function mongoOrm(options) {
69
543
  const { contract, executor } = options;
70
544
  const client = {};
71
- for (const [rootName, modelName] of Object.entries(contract.roots)) client[rootName] = new MongoCollectionImpl(contract, modelName, executor);
545
+ for (const [rootName, modelName] of Object.entries(contract.roots)) client[rootName] = createMongoCollection(contract, modelName, executor);
72
546
  return client;
73
547
  }
74
548
 
75
549
  //#endregion
76
- export { mongoOrm };
550
+ //#region src/raw-collection.ts
551
+ function createRawMongoCollection(collectionName, meta) {
552
+ function buildable(command) {
553
+ return { build: () => ({
554
+ collection: collectionName,
555
+ command,
556
+ meta
557
+ }) };
558
+ }
559
+ return {
560
+ aggregate(pipeline) {
561
+ return buildable(new RawAggregateCommand(collectionName, pipeline));
562
+ },
563
+ insertOne(document) {
564
+ return buildable(new RawInsertOneCommand(collectionName, document));
565
+ },
566
+ insertMany(documents) {
567
+ return buildable(new RawInsertManyCommand(collectionName, documents));
568
+ },
569
+ updateOne(filter, update) {
570
+ return buildable(new RawUpdateOneCommand(collectionName, filter, update));
571
+ },
572
+ updateMany(filter, update) {
573
+ return buildable(new RawUpdateManyCommand(collectionName, filter, update));
574
+ },
575
+ deleteOne(filter) {
576
+ return buildable(new RawDeleteOneCommand(collectionName, filter));
577
+ },
578
+ deleteMany(filter) {
579
+ return buildable(new RawDeleteManyCommand(collectionName, filter));
580
+ },
581
+ findOneAndUpdate(filter, update, options) {
582
+ return buildable(new RawFindOneAndUpdateCommand(collectionName, filter, update, options?.upsert ?? false));
583
+ },
584
+ findOneAndDelete(filter) {
585
+ return buildable(new RawFindOneAndDeleteCommand(collectionName, filter));
586
+ }
587
+ };
588
+ }
589
+
590
+ //#endregion
591
+ //#region src/mongo-raw.ts
592
+ function mongoRaw(options) {
593
+ const { contract } = options;
594
+ return { collection(rootName) {
595
+ const modelName = contract.roots[rootName];
596
+ if (!Object.hasOwn(contract.models, modelName)) throw new Error(`Unknown model "${modelName}" for root "${rootName}"`);
597
+ return createRawMongoCollection(contract.models[modelName].storage.collection ?? modelName, {
598
+ target: "mongo",
599
+ storageHash: contract.storage.storageHash,
600
+ lane: "mongo-raw",
601
+ paramDescriptors: []
602
+ });
603
+ } };
604
+ }
605
+
606
+ //#endregion
607
+ export { compileMongoQuery, createFieldAccessor, createMongoCollection, mongoOrm, mongoRaw };
77
608
  //# sourceMappingURL=index.mjs.map