@prisma-next/mongo-runtime 0.11.0 → 0.12.0
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.d.mts +134 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +291 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -20
- package/src/content-hash.ts +34 -5
- package/src/exports/index.ts +11 -0
- package/src/mongo-execution-plan.ts +10 -2
- package/src/mongo-middleware.ts +27 -3
- package/src/mongo-runtime.ts +84 -10
- package/src/param-ref-mutator.ts +435 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import type { ParamRefMutator } from '@prisma-next/framework-components/runtime';
|
|
2
|
+
import type { MongoLoweredDraft } from '@prisma-next/mongo-lowering';
|
|
3
|
+
import { MongoParamRef } from '@prisma-next/mongo-value';
|
|
4
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Phantom brand on {@link MongoParamRefHandle} so handles produced by
|
|
8
|
+
* {@link MongoParamRefMutator.entries} are distinguishable at the type level
|
|
9
|
+
* from user-constructed `MongoParamRef` instances. There is no runtime token —
|
|
10
|
+
* the handle IS the underlying `MongoParamRef` instance, cast through the brand.
|
|
11
|
+
*/
|
|
12
|
+
declare const mongoParamRefHandleBrand: unique symbol;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Opaque token identifying a single `MongoParamRef` in the draft tree.
|
|
16
|
+
* Produced by {@link MongoParamRefMutator.entries}; consumed by
|
|
17
|
+
* `replaceValue` / `replaceValues`. The `TCodecId` phantom parameter
|
|
18
|
+
* records the codec id so typed overloads can route replacement values
|
|
19
|
+
* through a `TCodecMap`.
|
|
20
|
+
*/
|
|
21
|
+
export interface MongoParamRefHandle<TCodecId extends string | undefined = string | undefined> {
|
|
22
|
+
readonly [mongoParamRefHandleBrand]: TCodecId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* One outbound `MongoParamRef` slot in the draft exposed to middleware.
|
|
27
|
+
* `value` is the current effective value (post any prior mutations);
|
|
28
|
+
* `codecId` is the codec id declared on the underlying `MongoParamRef`.
|
|
29
|
+
*/
|
|
30
|
+
export interface MongoParamRefEntry<TCodecId extends string | undefined = string | undefined> {
|
|
31
|
+
readonly ref: MongoParamRefHandle<TCodecId>;
|
|
32
|
+
readonly value: unknown;
|
|
33
|
+
readonly codecId: TCodecId;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Discriminated entry union over a codec map. For each `K` in `TCodecMap`,
|
|
38
|
+
* `entries()` may yield a `MongoParamRefEntry<K>`; refs with no codec id (or
|
|
39
|
+
* an unrecognised codec id) yield `MongoParamRefEntry<undefined>`. Pattern-
|
|
40
|
+
* matching on `entry.codecId` narrows `entry.ref` to `MongoParamRefHandle<K>`.
|
|
41
|
+
*/
|
|
42
|
+
export type MongoParamRefEntryUnion<TCodecMap extends Record<string, unknown>> =
|
|
43
|
+
| { [K in keyof TCodecMap & string]: MongoParamRefEntry<K> }[keyof TCodecMap & string]
|
|
44
|
+
| MongoParamRefEntry<undefined>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Mongo-family mutator threaded into `MongoMiddleware.beforeExecute` as
|
|
48
|
+
* `params`. Scope is `MongoParamRef.value` slots only — middleware cannot
|
|
49
|
+
* insert or remove refs, rewrite the filter shape, or modify the pipeline
|
|
50
|
+
* structure. The phantom `MongoParamRefHandle` brand and the typed
|
|
51
|
+
* `replaceValue` overload enforce this at compile time.
|
|
52
|
+
*
|
|
53
|
+
* `entries()` performs a flat walk over the `MongoLoweredDraft` tree via
|
|
54
|
+
* {@link flattenMongoParamRefs}, yielding every `MongoParamRef` leaf in
|
|
55
|
+
* document fields, array elements, filter predicates, update operators, and
|
|
56
|
+
* pipeline stages. The walk matches `resolveDraftSlot` in the Mongo adapter
|
|
57
|
+
* (plain-object and array slots only; `Date` and other non-plain objects are
|
|
58
|
+
* leaves in both paths).
|
|
59
|
+
*
|
|
60
|
+
* Allocation discipline: the working-overrides map is only allocated on the
|
|
61
|
+
* first `replaceValue` / `replaceValues` call. If no middleware mutates,
|
|
62
|
+
* `currentDraft()` returns the original draft by reference identity without
|
|
63
|
+
* allocating a new tree (the AC-MUT5 fast path).
|
|
64
|
+
*/
|
|
65
|
+
export interface MongoParamRefMutator<
|
|
66
|
+
TCodecMap extends Record<string, unknown> = Record<string, unknown>,
|
|
67
|
+
> extends ParamRefMutator {
|
|
68
|
+
entries(): IterableIterator<MongoParamRefEntryUnion<TCodecMap>>;
|
|
69
|
+
|
|
70
|
+
replaceValue<TCodecId extends keyof TCodecMap & string>(
|
|
71
|
+
ref: MongoParamRefHandle<TCodecId>,
|
|
72
|
+
newValue: TCodecMap[TCodecId],
|
|
73
|
+
): void;
|
|
74
|
+
replaceValue(ref: MongoParamRefHandle<undefined>, newValue: unknown): void;
|
|
75
|
+
|
|
76
|
+
replaceValues(
|
|
77
|
+
updates: Iterable<{
|
|
78
|
+
readonly ref: MongoParamRefHandle<(keyof TCodecMap & string) | undefined>;
|
|
79
|
+
readonly newValue: unknown;
|
|
80
|
+
}>,
|
|
81
|
+
): void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Internal-only view that exposes `currentDraft()` to the Mongo runtime.
|
|
86
|
+
* The runtime calls this after the `beforeExecute` chain; the result is the
|
|
87
|
+
* original draft by reference if nothing was mutated, otherwise a new tree
|
|
88
|
+
* with the mutations applied. `MongoMiddleware` consumers never see this
|
|
89
|
+
* shape; they receive the public `MongoParamRefMutator` view.
|
|
90
|
+
*/
|
|
91
|
+
export interface MongoParamRefMutatorInternal<
|
|
92
|
+
TCodecMap extends Record<string, unknown> = Record<string, unknown>,
|
|
93
|
+
> extends MongoParamRefMutator<TCodecMap> {
|
|
94
|
+
currentDraft(): MongoLoweredDraft;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type AnyMongoHandle = MongoParamRefHandle<string | undefined>;
|
|
98
|
+
|
|
99
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
100
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ─── Internal tree-walk helpers ────────────────────────────────────────────
|
|
104
|
+
// Descent mirrors resolveDraftSlot in adapter-mongo/resolve-value.ts: recurse
|
|
105
|
+
// arrays and plain records; treat MongoParamRef, primitives, Date, and other
|
|
106
|
+
// non-plain objects as leaves.
|
|
107
|
+
|
|
108
|
+
function* flattenDraftSlot(value: unknown): Generator<MongoParamRef> {
|
|
109
|
+
if (value instanceof MongoParamRef) {
|
|
110
|
+
yield value;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
for (const item of value) {
|
|
115
|
+
yield* flattenDraftSlot(item);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (isPlainRecord(value)) {
|
|
120
|
+
for (const v of Object.values(value)) {
|
|
121
|
+
yield* flattenDraftSlot(v);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Flat walk over a `MongoLoweredDraft` yielding every `MongoParamRef` leaf
|
|
128
|
+
* regardless of nesting — object values, array elements, filter predicate
|
|
129
|
+
* values, update operator values, and pipeline stage values. Raw command
|
|
130
|
+
* variants carry no `MongoParamRef` nodes so they yield zero entries.
|
|
131
|
+
*
|
|
132
|
+
* **Walk parity:** slot traversal matches `resolveDraftSlot` / `resolveParams`
|
|
133
|
+
* — refs appear only in plain-object and array containers; `Date` and other
|
|
134
|
+
* non-plain objects are leaves (not descended into), so middleware sees every
|
|
135
|
+
* ref the resolve pass will encode.
|
|
136
|
+
*/
|
|
137
|
+
export function* flattenMongoParamRefs(draft: MongoLoweredDraft): Generator<MongoParamRef> {
|
|
138
|
+
switch (draft.kind) {
|
|
139
|
+
case 'insertOne':
|
|
140
|
+
case 'rawInsertOne':
|
|
141
|
+
yield* flattenDraftSlot(draft.document);
|
|
142
|
+
break;
|
|
143
|
+
case 'insertMany':
|
|
144
|
+
case 'rawInsertMany':
|
|
145
|
+
for (const doc of draft.documents) {
|
|
146
|
+
yield* flattenDraftSlot(doc);
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
case 'updateOne':
|
|
150
|
+
case 'updateMany':
|
|
151
|
+
case 'rawUpdateOne':
|
|
152
|
+
case 'rawUpdateMany':
|
|
153
|
+
yield* flattenDraftSlot(draft.filter);
|
|
154
|
+
yield* flattenDraftSlot(draft.update);
|
|
155
|
+
break;
|
|
156
|
+
case 'findOneAndUpdate':
|
|
157
|
+
case 'rawFindOneAndUpdate':
|
|
158
|
+
yield* flattenDraftSlot(draft.filter);
|
|
159
|
+
yield* flattenDraftSlot(draft.update);
|
|
160
|
+
break;
|
|
161
|
+
case 'deleteOne':
|
|
162
|
+
case 'deleteMany':
|
|
163
|
+
case 'rawDeleteOne':
|
|
164
|
+
case 'rawDeleteMany':
|
|
165
|
+
yield* flattenDraftSlot(draft.filter);
|
|
166
|
+
break;
|
|
167
|
+
case 'findOneAndDelete':
|
|
168
|
+
case 'rawFindOneAndDelete':
|
|
169
|
+
yield* flattenDraftSlot(draft.filter);
|
|
170
|
+
break;
|
|
171
|
+
case 'aggregate':
|
|
172
|
+
case 'rawAggregate':
|
|
173
|
+
for (const stage of draft.pipeline) {
|
|
174
|
+
yield* flattenDraftSlot(stage);
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ─── Draft reconstruction for the mutated path ─────────────────────────────
|
|
181
|
+
|
|
182
|
+
function substituteSlot(value: unknown, overrides: ReadonlyMap<MongoParamRef, unknown>): unknown {
|
|
183
|
+
if (value instanceof MongoParamRef) {
|
|
184
|
+
if (overrides.has(value)) {
|
|
185
|
+
const opts: { name?: string; codecId?: string } = {};
|
|
186
|
+
if (value.name !== undefined) opts.name = value.name;
|
|
187
|
+
if (value.codecId !== undefined) opts.codecId = value.codecId;
|
|
188
|
+
return new MongoParamRef(overrides.get(value), opts);
|
|
189
|
+
}
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
if (Array.isArray(value)) {
|
|
193
|
+
return value.map((item) => substituteSlot(item, overrides));
|
|
194
|
+
}
|
|
195
|
+
if (isPlainRecord(value)) {
|
|
196
|
+
const out: Record<string, unknown> = {};
|
|
197
|
+
for (const [k, v] of Object.entries(value)) {
|
|
198
|
+
out[k] = substituteSlot(v, overrides);
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function substituteDoc(
|
|
206
|
+
doc: Record<string, unknown>,
|
|
207
|
+
overrides: ReadonlyMap<MongoParamRef, unknown>,
|
|
208
|
+
): Record<string, unknown> {
|
|
209
|
+
return blindCast<
|
|
210
|
+
Record<string, unknown>,
|
|
211
|
+
'substituteSlot preserves plain-object shape for document inputs'
|
|
212
|
+
>(substituteSlot(doc, overrides));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function isUpdatePipeline(
|
|
216
|
+
update: Record<string, unknown> | ReadonlyArray<Record<string, unknown>>,
|
|
217
|
+
): update is ReadonlyArray<Record<string, unknown>> {
|
|
218
|
+
return Array.isArray(update);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function substituteUpdate(
|
|
222
|
+
update: Record<string, unknown> | ReadonlyArray<Record<string, unknown>>,
|
|
223
|
+
overrides: ReadonlyMap<MongoParamRef, unknown>,
|
|
224
|
+
): Record<string, unknown> | Array<Record<string, unknown>> {
|
|
225
|
+
if (isUpdatePipeline(update)) {
|
|
226
|
+
return update.map((stage) => substituteDoc(stage, overrides));
|
|
227
|
+
}
|
|
228
|
+
return substituteDoc(update, overrides);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function buildMutatedDraft(
|
|
232
|
+
draft: MongoLoweredDraft,
|
|
233
|
+
overrides: ReadonlyMap<MongoParamRef, unknown>,
|
|
234
|
+
): MongoLoweredDraft {
|
|
235
|
+
switch (draft.kind) {
|
|
236
|
+
case 'insertOne':
|
|
237
|
+
return {
|
|
238
|
+
kind: 'insertOne',
|
|
239
|
+
collection: draft.collection,
|
|
240
|
+
document: substituteDoc(draft.document, overrides),
|
|
241
|
+
};
|
|
242
|
+
case 'rawInsertOne':
|
|
243
|
+
return {
|
|
244
|
+
kind: 'rawInsertOne',
|
|
245
|
+
collection: draft.collection,
|
|
246
|
+
document: substituteDoc(draft.document, overrides),
|
|
247
|
+
};
|
|
248
|
+
case 'insertMany':
|
|
249
|
+
return {
|
|
250
|
+
kind: 'insertMany',
|
|
251
|
+
collection: draft.collection,
|
|
252
|
+
documents: draft.documents.map((d) => substituteDoc(d, overrides)),
|
|
253
|
+
};
|
|
254
|
+
case 'rawInsertMany':
|
|
255
|
+
return {
|
|
256
|
+
kind: 'rawInsertMany',
|
|
257
|
+
collection: draft.collection,
|
|
258
|
+
documents: draft.documents.map((d) => substituteDoc(d, overrides)),
|
|
259
|
+
};
|
|
260
|
+
case 'updateOne':
|
|
261
|
+
return {
|
|
262
|
+
kind: 'updateOne',
|
|
263
|
+
collection: draft.collection,
|
|
264
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
265
|
+
update: substituteUpdate(draft.update, overrides),
|
|
266
|
+
upsert: draft.upsert,
|
|
267
|
+
};
|
|
268
|
+
case 'updateMany':
|
|
269
|
+
return {
|
|
270
|
+
kind: 'updateMany',
|
|
271
|
+
collection: draft.collection,
|
|
272
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
273
|
+
update: substituteUpdate(draft.update, overrides),
|
|
274
|
+
upsert: draft.upsert,
|
|
275
|
+
};
|
|
276
|
+
case 'rawUpdateOne':
|
|
277
|
+
return {
|
|
278
|
+
kind: 'rawUpdateOne',
|
|
279
|
+
collection: draft.collection,
|
|
280
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
281
|
+
update: substituteUpdate(draft.update, overrides),
|
|
282
|
+
};
|
|
283
|
+
case 'rawUpdateMany':
|
|
284
|
+
return {
|
|
285
|
+
kind: 'rawUpdateMany',
|
|
286
|
+
collection: draft.collection,
|
|
287
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
288
|
+
update: substituteUpdate(draft.update, overrides),
|
|
289
|
+
};
|
|
290
|
+
case 'deleteOne':
|
|
291
|
+
return {
|
|
292
|
+
kind: 'deleteOne',
|
|
293
|
+
collection: draft.collection,
|
|
294
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
295
|
+
};
|
|
296
|
+
case 'deleteMany':
|
|
297
|
+
return {
|
|
298
|
+
kind: 'deleteMany',
|
|
299
|
+
collection: draft.collection,
|
|
300
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
301
|
+
};
|
|
302
|
+
case 'rawDeleteOne':
|
|
303
|
+
return {
|
|
304
|
+
kind: 'rawDeleteOne',
|
|
305
|
+
collection: draft.collection,
|
|
306
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
307
|
+
};
|
|
308
|
+
case 'rawDeleteMany':
|
|
309
|
+
return {
|
|
310
|
+
kind: 'rawDeleteMany',
|
|
311
|
+
collection: draft.collection,
|
|
312
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
313
|
+
};
|
|
314
|
+
case 'findOneAndUpdate':
|
|
315
|
+
return {
|
|
316
|
+
kind: 'findOneAndUpdate',
|
|
317
|
+
collection: draft.collection,
|
|
318
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
319
|
+
update: substituteUpdate(draft.update, overrides),
|
|
320
|
+
upsert: draft.upsert,
|
|
321
|
+
sort: draft.sort,
|
|
322
|
+
returnDocument: draft.returnDocument,
|
|
323
|
+
};
|
|
324
|
+
case 'rawFindOneAndUpdate':
|
|
325
|
+
return {
|
|
326
|
+
kind: 'rawFindOneAndUpdate',
|
|
327
|
+
collection: draft.collection,
|
|
328
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
329
|
+
update: substituteUpdate(draft.update, overrides),
|
|
330
|
+
upsert: draft.upsert,
|
|
331
|
+
sort: draft.sort,
|
|
332
|
+
returnDocument: draft.returnDocument,
|
|
333
|
+
};
|
|
334
|
+
case 'findOneAndDelete':
|
|
335
|
+
return {
|
|
336
|
+
kind: 'findOneAndDelete',
|
|
337
|
+
collection: draft.collection,
|
|
338
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
339
|
+
sort: draft.sort,
|
|
340
|
+
};
|
|
341
|
+
case 'rawFindOneAndDelete':
|
|
342
|
+
return {
|
|
343
|
+
kind: 'rawFindOneAndDelete',
|
|
344
|
+
collection: draft.collection,
|
|
345
|
+
filter: substituteDoc(draft.filter, overrides),
|
|
346
|
+
sort: draft.sort,
|
|
347
|
+
};
|
|
348
|
+
case 'aggregate':
|
|
349
|
+
return {
|
|
350
|
+
kind: 'aggregate',
|
|
351
|
+
collection: draft.collection,
|
|
352
|
+
pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides)),
|
|
353
|
+
};
|
|
354
|
+
case 'rawAggregate':
|
|
355
|
+
return {
|
|
356
|
+
kind: 'rawAggregate',
|
|
357
|
+
collection: draft.collection,
|
|
358
|
+
pipeline: draft.pipeline.map((s) => substituteDoc(s, overrides)),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ─── Factory ────────────────────────────────────────────────────────────────
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Build a {@link MongoParamRefMutatorInternal} for the given lowered draft.
|
|
367
|
+
*
|
|
368
|
+
* The mutator captures the draft by reference and uses `flattenMongoParamRefs`
|
|
369
|
+
* on demand to produce `entries()`. Replacements are stored in a lazily-
|
|
370
|
+
* allocated `Map`; the fast path (no replacements) preserves bit-for-bit
|
|
371
|
+
* reference identity to the original draft in `currentDraft()`.
|
|
372
|
+
*/
|
|
373
|
+
export function createMongoParamRefMutator<
|
|
374
|
+
TCodecMap extends Record<string, unknown> = Record<string, unknown>,
|
|
375
|
+
>(draft: MongoLoweredDraft): MongoParamRefMutatorInternal<TCodecMap> {
|
|
376
|
+
const originalDraft = draft;
|
|
377
|
+
let overrides: Map<MongoParamRef, unknown> | undefined;
|
|
378
|
+
|
|
379
|
+
const ensureOverrides = (): Map<MongoParamRef, unknown> => {
|
|
380
|
+
if (!overrides) {
|
|
381
|
+
overrides = new Map();
|
|
382
|
+
}
|
|
383
|
+
return overrides;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
function* entries(): IterableIterator<MongoParamRefEntryUnion<TCodecMap>> {
|
|
387
|
+
for (const ref of flattenMongoParamRefs(originalDraft)) {
|
|
388
|
+
const handle = blindCast<
|
|
389
|
+
MongoParamRefHandle<string | undefined>,
|
|
390
|
+
'MongoParamRef instance is the runtime handle token'
|
|
391
|
+
>(ref);
|
|
392
|
+
const value = overrides?.has(ref) ? overrides.get(ref) : ref.value;
|
|
393
|
+
const codecId: string | undefined = ref.codecId;
|
|
394
|
+
const entry: MongoParamRefEntry<string | undefined> = { ref: handle, value, codecId };
|
|
395
|
+
yield blindCast<
|
|
396
|
+
MongoParamRefEntryUnion<TCodecMap>,
|
|
397
|
+
'entry codecId widened to TCodecMap union'
|
|
398
|
+
>(entry);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function replaceValue(handle: AnyMongoHandle, newValue: unknown): void {
|
|
403
|
+
ensureOverrides().set(
|
|
404
|
+
blindCast<MongoParamRef, 'MongoParamRefHandle brand is the underlying ref instance'>(handle),
|
|
405
|
+
newValue,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function replaceValues(
|
|
410
|
+
updates: Iterable<{ readonly ref: AnyMongoHandle; readonly newValue: unknown }>,
|
|
411
|
+
): void {
|
|
412
|
+
const map = ensureOverrides();
|
|
413
|
+
for (const { ref, newValue } of updates) {
|
|
414
|
+
map.set(
|
|
415
|
+
blindCast<MongoParamRef, 'MongoParamRefHandle brand is the underlying ref instance'>(ref),
|
|
416
|
+
newValue,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
entries,
|
|
423
|
+
replaceValue: blindCast<
|
|
424
|
+
MongoParamRefMutator<TCodecMap>['replaceValue'],
|
|
425
|
+
'replaceValue overloads are enforced at the interface; implementation accepts AnyMongoHandle'
|
|
426
|
+
>(replaceValue),
|
|
427
|
+
replaceValues,
|
|
428
|
+
currentDraft(): MongoLoweredDraft {
|
|
429
|
+
if (!overrides || overrides.size === 0) {
|
|
430
|
+
return originalDraft;
|
|
431
|
+
}
|
|
432
|
+
return buildMutatedDraft(originalDraft, overrides);
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|