@prisma-next/mongo-query-builder 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.
@@ -0,0 +1,1198 @@
1
+ import { AggregateCommand, AnyMongoCommand, DeleteManyCommand, DeleteOneCommand, DeleteResult, DeleteResult as DeleteResult$1, FindOneAndDeleteCommand, FindOneAndUpdateCommand, InsertManyCommand, InsertManyResult, InsertManyResult as InsertManyResult$1, InsertOneCommand, InsertOneResult, InsertOneResult as InsertOneResult$1, MongoAggAccumulator, MongoAggExpr, MongoDensifyRange, MongoFillOutput, MongoFilterExpr, MongoPipelineStage, MongoQueryPlan, MongoUpdatePipelineStage, MongoWindowField, UpdateManyCommand, UpdateOneCommand, UpdateResult, UpdateResult as UpdateResult$1 } from "@prisma-next/mongo-query-ast/execution";
2
+ import { ExtractMongoCodecTypes, MongoContract, MongoContractWithTypeMaps, MongoTypeMaps } from "@prisma-next/mongo-contract";
3
+ import { MongoValue } from "@prisma-next/mongo-value";
4
+
5
+ //#region src/types.d.ts
6
+ interface DocField {
7
+ readonly codecId: string;
8
+ readonly nullable: boolean;
9
+ }
10
+ type NumericField = {
11
+ readonly codecId: 'mongo/double@1';
12
+ readonly nullable: false;
13
+ };
14
+ type NullableNumericField = {
15
+ readonly codecId: 'mongo/double@1';
16
+ readonly nullable: true;
17
+ };
18
+ type StringField = {
19
+ readonly codecId: 'mongo/string@1';
20
+ readonly nullable: false;
21
+ };
22
+ type ArrayField = {
23
+ readonly codecId: 'mongo/array@1';
24
+ readonly nullable: false;
25
+ };
26
+ type BooleanField = {
27
+ readonly codecId: 'mongo/bool@1';
28
+ readonly nullable: false;
29
+ };
30
+ type DateField = {
31
+ readonly codecId: 'mongo/date@1';
32
+ readonly nullable: false;
33
+ };
34
+ type NullableDocField = {
35
+ readonly codecId: string;
36
+ readonly nullable: true;
37
+ };
38
+ type LiteralValue<F extends DocField> = F extends StringField ? string : F extends NumericField ? number : F extends BooleanField ? boolean : F extends DateField ? Date : unknown;
39
+ type DocShape = Record<string, DocField>;
40
+ type ExtractCodecId<F> = F extends {
41
+ type: {
42
+ kind: 'scalar';
43
+ codecId: infer C;
44
+ };
45
+ } ? C : F extends {
46
+ codecId: infer C extends string;
47
+ } ? C : string;
48
+ type ModelToDocShape<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { [K in keyof TContract['models'][ModelName]['fields'] & string]: {
49
+ readonly codecId: ExtractCodecId<TContract['models'][ModelName]['fields'][K]>;
50
+ readonly nullable: TContract['models'][ModelName]['fields'][K]['nullable'];
51
+ } };
52
+ type ResolveRow<Shape extends DocShape, CodecTypes extends Record<string, {
53
+ readonly output: unknown;
54
+ }>> = { -readonly [K in keyof Shape & string]: Shape[K]['codecId'] extends keyof CodecTypes ? Shape[K]['nullable'] extends true ? CodecTypes[Shape[K]['codecId']]['output'] | null : CodecTypes[Shape[K]['codecId']]['output'] : unknown };
55
+ interface TypedAggExpr<F extends DocField> {
56
+ readonly _field: F;
57
+ readonly node: MongoAggExpr;
58
+ }
59
+ interface TypedAccumulatorExpr<F extends DocField> {
60
+ readonly _field: F;
61
+ readonly node: MongoAggAccumulator;
62
+ }
63
+ type ExtractDocShape<T extends Record<string, TypedAggExpr<DocField>>> = { [K in keyof T & string]: T[K]['_field'] };
64
+ type SortSpec<S extends DocShape> = Partial<Record<keyof S & string, 1 | -1>>;
65
+ type ProjectedShape<Shape extends DocShape, Spec extends Record<string, 1 | TypedAggExpr<DocField>>> = { [K in keyof Spec & string]: Spec[K] extends 1 ? K extends keyof Shape ? Shape[K] : DocField : Spec[K] extends TypedAggExpr<infer F> ? F : DocField } & ('_id' extends keyof Shape ? '_id' extends keyof Spec ? Record<keyof never, never> : Pick<Shape, '_id'> : Record<keyof never, never>);
66
+ type GroupSpec = {
67
+ _id: TypedAggExpr<DocField> | null;
68
+ [key: string]: TypedAggExpr<DocField> | TypedAccumulatorExpr<DocField> | null;
69
+ };
70
+ type GroupedDocShape<Spec extends GroupSpec> = { [K in keyof Spec & string]: Spec[K] extends TypedAggExpr<infer F> ? F : Spec[K] extends TypedAccumulatorExpr<infer F> ? F : Spec[K] extends null ? {
71
+ readonly codecId: 'mongo/null@1';
72
+ readonly nullable: true;
73
+ } : DocField };
74
+ /**
75
+ * Intentionally identity — full array element type extraction is deferred.
76
+ * Used by `UnwoundShape` so the unwind result shape can be refined later
77
+ * without changing the public API.
78
+ */
79
+ type UnwrapArrayDocField<F extends DocField> = F;
80
+ type UnwoundShape<S extends DocShape, K$1 extends keyof S & string> = { [P in keyof S & string]: P extends K$1 ? UnwrapArrayDocField<S[P]> : S[P] };
81
+ //#endregion
82
+ //#region src/accumulator-helpers.d.ts
83
+ declare const acc: {
84
+ sum<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<F>;
85
+ avg(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
86
+ min<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
87
+ readonly codecId: F["codecId"];
88
+ readonly nullable: true;
89
+ }>;
90
+ max<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
91
+ readonly codecId: F["codecId"];
92
+ readonly nullable: true;
93
+ }>;
94
+ first<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
95
+ readonly codecId: F["codecId"];
96
+ readonly nullable: true;
97
+ }>;
98
+ last<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
99
+ readonly codecId: F["codecId"];
100
+ readonly nullable: true;
101
+ }>;
102
+ push(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
103
+ addToSet(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
104
+ count(): TypedAccumulatorExpr<NumericField>;
105
+ stdDevPop(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
106
+ stdDevSamp(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
107
+ firstN(args: {
108
+ input: TypedAggExpr<DocField>;
109
+ n: TypedAggExpr<NumericField>;
110
+ }): TypedAccumulatorExpr<ArrayField>;
111
+ lastN(args: {
112
+ input: TypedAggExpr<DocField>;
113
+ n: TypedAggExpr<NumericField>;
114
+ }): TypedAccumulatorExpr<ArrayField>;
115
+ maxN(args: {
116
+ input: TypedAggExpr<DocField>;
117
+ n: TypedAggExpr<NumericField>;
118
+ }): TypedAccumulatorExpr<ArrayField>;
119
+ minN(args: {
120
+ input: TypedAggExpr<DocField>;
121
+ n: TypedAggExpr<NumericField>;
122
+ }): TypedAccumulatorExpr<ArrayField>;
123
+ top(args: {
124
+ output: TypedAggExpr<DocField>;
125
+ sortBy: Readonly<Record<string, 1 | -1>>;
126
+ }): TypedAccumulatorExpr<DocField>;
127
+ bottom(args: {
128
+ output: TypedAggExpr<DocField>;
129
+ sortBy: Readonly<Record<string, 1 | -1>>;
130
+ }): TypedAccumulatorExpr<DocField>;
131
+ topN(args: {
132
+ output: TypedAggExpr<DocField>;
133
+ sortBy: Readonly<Record<string, 1 | -1>>;
134
+ n: TypedAggExpr<NumericField>;
135
+ }): TypedAccumulatorExpr<ArrayField>;
136
+ bottomN(args: {
137
+ output: TypedAggExpr<DocField>;
138
+ sortBy: Readonly<Record<string, 1 | -1>>;
139
+ n: TypedAggExpr<NumericField>;
140
+ }): TypedAccumulatorExpr<ArrayField>;
141
+ };
142
+ //#endregion
143
+ //#region src/resolve-path.d.ts
144
+ /**
145
+ * Marker `DocField` variant representing a non-leaf (value-object) path in
146
+ * a [NestedDocShape]. Extends `DocField` with a `fields` property carrying
147
+ * the sub-shape so the pipeline builder can recurse into it.
148
+ *
149
+ * `codecId` is the reserved literal `'prisma/object@1'`; the accessor's
150
+ * runtime implementation does not serialize it — the codec id is a purely
151
+ * type-level sentinel used by `Expression<F>` to select the reduced
152
+ * operator surface for non-leaf paths.
153
+ *
154
+ * `nullable` tracks whether the value object itself may be absent/null on
155
+ * the parent document. The callable form currently does not propagate the
156
+ * parent's `nullable` flag onto leaves beneath it (path traversal under a
157
+ * nullable parent resolves to the leaf's own `nullable` — matching how
158
+ * MongoDB treats missing intermediate documents).
159
+ */
160
+ interface ObjectField<N$1 extends NestedDocShape> extends DocField {
161
+ readonly codecId: 'prisma/object@1';
162
+ readonly nullable: boolean;
163
+ readonly fields: N$1;
164
+ }
165
+ /**
166
+ * Document shape that carries nested value-object sub-shapes.
167
+ *
168
+ * Structurally identical to a flat `DocShape` (`Record<string, DocField>`),
169
+ * but individual values may be `ObjectField<SubShape>` carrying a nested
170
+ * `NestedDocShape` sub-tree. The pipeline builder threads a
171
+ * `NestedDocShape` alongside the flat `DocShape` so the callable
172
+ * `f('a.b.c')` form can validate dot-paths at the type level.
173
+ *
174
+ * When a stage transforms the root shape in a way that invalidates nested
175
+ * paths (e.g. `$group`, `$project`, `$replaceRoot`), the thread is reset
176
+ * to the empty shape `Record<string, never>` — which makes `ValidPaths`
177
+ * resolve to `never` and so disables the callable form downstream.
178
+ */
179
+ type NestedDocShape = Record<string, DocField>;
180
+ type ContractHasValueObjects = {
181
+ readonly valueObjects?: Record<string, {
182
+ readonly fields: Record<string, unknown>;
183
+ }>;
184
+ };
185
+ type FieldToLeaf<F> = F extends {
186
+ readonly type: {
187
+ readonly kind: 'scalar';
188
+ readonly codecId: infer C extends string;
189
+ };
190
+ readonly nullable: infer N extends boolean;
191
+ } ? {
192
+ readonly codecId: C;
193
+ readonly nullable: N;
194
+ } : F extends {
195
+ readonly many: true;
196
+ readonly nullable: infer N extends boolean;
197
+ } ? {
198
+ readonly codecId: 'mongo/array@1';
199
+ readonly nullable: N;
200
+ } : DocField;
201
+ /**
202
+ * Translate a single contract field to its nested-shape form. Scalars
203
+ * become `DocField` leaves; value-object fields become
204
+ * `ObjectField<Sub>`; `many: true` stops at a leaf; anything else falls
205
+ * through to the opaque `DocField` base.
206
+ *
207
+ * Kept as a per-field helper (rather than a `Fields → NestedShape` helper
208
+ * that maps over keys internally) so the parent mapped type stays
209
+ * homomorphic over the model/value-object `fields` record. Homomorphic
210
+ * mapped types preserve the literal keys of their source object through
211
+ * TypeScript's intersection-collapsing machinery, which keeps
212
+ * `ModelNestedShape` hover output and `keyof`/indexed-access resolution
213
+ * concrete instead of collapsing to `{ [x: string]: … }`.
214
+ */
215
+ type TranslateField<TContract extends ContractHasValueObjects, F> = F extends {
216
+ readonly many: true;
217
+ } ? FieldToLeaf<F> : F extends {
218
+ readonly type: {
219
+ readonly kind: 'valueObject';
220
+ readonly name: infer VOName extends string;
221
+ };
222
+ readonly nullable: infer Null extends boolean;
223
+ } ? ObjectField<VONestedShape<TContract, VOName>> & {
224
+ readonly nullable: Null;
225
+ } : F extends {
226
+ readonly type: {
227
+ readonly kind: 'scalar';
228
+ readonly codecId: string;
229
+ };
230
+ } ? FieldToLeaf<F> : DocField;
231
+ /**
232
+ * Resolve a named value object from the contract into its own
233
+ * `NestedDocShape`. The mapped iteration is inlined here (not delegated
234
+ * to a generic helper) so that the homomorphism over
235
+ * `VOs[VOName]['fields']` is preserved and the hover / indexed-access
236
+ * surface stays concrete at instantiation time.
237
+ */
238
+ type VONestedShape<TContract extends ContractHasValueObjects, VOName$1 extends string> = TContract extends {
239
+ readonly valueObjects: infer VOs extends Record<string, {
240
+ readonly fields: Record<string, unknown>;
241
+ }>;
242
+ } ? VOName$1 extends keyof VOs ? { readonly [K in keyof VOs[VOName$1]['fields'] & string]: TranslateField<TContract, VOs[VOName$1]['fields'][K]> } : never : never;
243
+ /**
244
+ * Build the `NestedDocShape` for a model. Scalar leaves resolve to their
245
+ * concrete codec id; value-object fields recurse into the referenced
246
+ * `valueObjects[VOName].fields` table, producing a tree that
247
+ * `ResolvePath` / `ValidPaths` can walk.
248
+ *
249
+ * The mapped iteration is inlined (not hidden behind a helper type that
250
+ * takes `Fields` as a generic) so TypeScript recognises the mapped type
251
+ * as homomorphic over `TContract['models'][ModelName]['fields']`. That
252
+ * preserves the literal field-name keys at instantiation — without this,
253
+ * the intersection of `Record<string, ContractField>` and the specific
254
+ * literal field record collapses `keyof` to `string` and the result hover
255
+ * degrades to `{ readonly [x: string]: any }`.
256
+ */
257
+ type ModelNestedShape<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { readonly [K in keyof TContract['models'][ModelName]['fields'] & string]: TranslateField<TContract & ContractHasValueObjects, TContract['models'][ModelName]['fields'][K]> };
258
+ /**
259
+ * Resolve a dot-path against a `NestedDocShape`. Returns:
260
+ * - the leaf `DocField` when `Path` terminates on a scalar/array leaf,
261
+ * - the `ObjectField<Sub>` when `Path` terminates on a value object (so
262
+ * the caller can operate on the whole sub-document),
263
+ * - `never` when the path is invalid (unknown segment, or a scalar
264
+ * segment followed by further traversal).
265
+ *
266
+ * Paired with the constrained callable `<P extends ValidPaths<N>>(path: P)
267
+ * => Expression<ResolvePath<N, P>>` so the IDE offers completions and
268
+ * rejects bad paths with a clear error instead of silently resolving to
269
+ * `never`.
270
+ */
271
+ type ResolvePath<N$1 extends NestedDocShape, Path extends string> = Path extends `${infer Head}.${infer Rest}` ? Head extends keyof N$1 & string ? N$1[Head] extends ObjectField<infer Sub> ? ResolvePath<Sub, Rest> : never : never : Path extends keyof N$1 & string ? N$1[Path] : never;
272
+ /**
273
+ * Union of every valid dot-path within a `NestedDocShape`. Includes
274
+ * top-level keys (scalar leaves *and* value-object roots) and every
275
+ * recursive descent through `ObjectField` sub-shapes.
276
+ *
277
+ * Non-leaf paths are intentionally included — `f('address')` yields an
278
+ * `Expression<ObjectField<…>>` whose reduced operator surface (`set`,
279
+ * `unset`, `exists`, `eq(null)`, `ne(null)`) lets callers operate on the
280
+ * whole value object. Leaf paths like `f('address.city')` get the full
281
+ * leaf operator surface.
282
+ *
283
+ * The `string extends keyof N` guard short-circuits to `never` for
284
+ * open-ended index-signature shapes (e.g. the default
285
+ * `Record<string, never>` used to represent "no nested information" —
286
+ * notably downstream of replacement stages in the pipeline builder). An
287
+ * open-ended `keyof` cannot resolve a specific literal path, so the
288
+ * callable form must be disabled at the type level.
289
+ */
290
+ type ValidPaths<N$1 extends NestedDocShape> = string extends keyof N$1 ? never : { [K in keyof N$1 & string]: N$1[K] extends ObjectField<infer Sub> ? K | `${K}.${ValidPaths<Sub>}` : K }[keyof N$1 & string];
291
+ /**
292
+ * IDE-oriented alias for `ValidPaths`. Kept as a separate export so future
293
+ * refinements (e.g. ArkType-style lazy expansion for very deep shapes) can
294
+ * diverge from the strict `ValidPaths` constraint without breaking
295
+ * downstream consumers. For now the two are intentionally equivalent.
296
+ */
297
+ type PathCompletions<N$1 extends NestedDocShape> = ValidPaths<N$1>;
298
+ //#endregion
299
+ //#region src/update-ops.d.ts
300
+ /**
301
+ * Per-field update operations produced by `Expression`'s update methods
302
+ * (`set`, `inc`, `push`, …). A write terminal folds an array of these into a
303
+ * `MongoUpdateSpec` record (`{ $set: { … }, $inc: { … }, … }`) before
304
+ * constructing the underlying `UpdateManyCommand` / `UpdateOneCommand` AST node.
305
+ *
306
+ * One `TypedUpdateOp` value corresponds to one Mongo update operator applied
307
+ * to one field path. The `op` string is the wire-level operator name (`$set`,
308
+ * `$inc`, …); the `path` is the dot-path to the field (or its top-level name).
309
+ */
310
+ type TypedUpdateOp = {
311
+ readonly op: '$set';
312
+ readonly path: string;
313
+ readonly value: MongoValue;
314
+ } | {
315
+ readonly op: '$unset';
316
+ readonly path: string;
317
+ } | {
318
+ readonly op: '$rename';
319
+ readonly path: string;
320
+ readonly newName: string;
321
+ } | {
322
+ readonly op: '$inc';
323
+ readonly path: string;
324
+ readonly amount: number;
325
+ } | {
326
+ readonly op: '$mul';
327
+ readonly path: string;
328
+ readonly factor: number;
329
+ } | {
330
+ readonly op: '$min';
331
+ readonly path: string;
332
+ readonly value: MongoValue;
333
+ } | {
334
+ readonly op: '$max';
335
+ readonly path: string;
336
+ readonly value: MongoValue;
337
+ } | {
338
+ readonly op: '$push';
339
+ readonly path: string;
340
+ readonly value: MongoValue;
341
+ } | {
342
+ readonly op: '$addToSet';
343
+ readonly path: string;
344
+ readonly value: MongoValue;
345
+ } | {
346
+ readonly op: '$pop';
347
+ readonly path: string;
348
+ readonly direction: 1 | -1;
349
+ } | {
350
+ readonly op: '$pull';
351
+ readonly path: string;
352
+ readonly value: MongoValue;
353
+ } | {
354
+ readonly op: '$pullAll';
355
+ readonly path: string;
356
+ readonly values: ReadonlyArray<MongoValue>;
357
+ } | {
358
+ readonly op: '$currentDate';
359
+ readonly path: string;
360
+ } | {
361
+ readonly op: '$setOnInsert';
362
+ readonly path: string;
363
+ readonly value: MongoValue;
364
+ };
365
+ /**
366
+ * The return type for updater callbacks. Typed as a union of homogeneous
367
+ * arrays so mixed-shape updaters (operator + pipeline stage in the same
368
+ * array) are a compile error. The runtime guard in `resolveUpdaterResult`
369
+ * remains as defence-in-depth.
370
+ */
371
+ type UpdaterResult = ReadonlyArray<TypedUpdateOp> | ReadonlyArray<MongoUpdatePipelineStage>;
372
+ //#endregion
373
+ //#region src/field-accessor.d.ts
374
+ /**
375
+ * Operator surface for leaf (scalar) paths — today's full set: filter,
376
+ * update, and aggregation operators. Returned by `Expression<F>` for any
377
+ * `F extends DocField` that is not an `ObjectField<…>` sub-tree.
378
+ *
379
+ * Operator surfaces are intentionally not trait-gated by codec in this
380
+ * revision — tracked on Linear as TML-2259 (scope extended to cover the
381
+ * query-builder's `Expression<F>`). Calling, e.g. `.inc(1)` on a
382
+ * string-typed expression compiles; the runtime relies on Mongo to
383
+ * surface the error. Trait-gating can be tightened in a follow-up
384
+ * without changing the accessor's public shape.
385
+ */
386
+ interface LeafExpression<F extends DocField> extends TypedAggExpr<F> {
387
+ readonly _path: string;
388
+ eq(value: MongoValue): MongoFilterExpr;
389
+ ne(value: MongoValue): MongoFilterExpr;
390
+ gt(value: MongoValue): MongoFilterExpr;
391
+ gte(value: MongoValue): MongoFilterExpr;
392
+ lt(value: MongoValue): MongoFilterExpr;
393
+ lte(value: MongoValue): MongoFilterExpr;
394
+ in(values: ReadonlyArray<MongoValue>): MongoFilterExpr;
395
+ nin(values: ReadonlyArray<MongoValue>): MongoFilterExpr;
396
+ exists(flag?: boolean): MongoFilterExpr;
397
+ set(value: MongoValue): TypedUpdateOp;
398
+ unset(): TypedUpdateOp;
399
+ rename(newName: string): TypedUpdateOp;
400
+ inc(amount: number): TypedUpdateOp;
401
+ mul(factor: number): TypedUpdateOp;
402
+ min(value: MongoValue): TypedUpdateOp;
403
+ max(value: MongoValue): TypedUpdateOp;
404
+ push(value: MongoValue): TypedUpdateOp;
405
+ addToSet(value: MongoValue): TypedUpdateOp;
406
+ pop(direction?: 1 | -1): TypedUpdateOp;
407
+ pull(value: MongoValue): TypedUpdateOp;
408
+ pullAll(values: ReadonlyArray<MongoValue>): TypedUpdateOp;
409
+ currentDate(): TypedUpdateOp;
410
+ setOnInsert(value: MongoValue): TypedUpdateOp;
411
+ }
412
+ /**
413
+ * Operator surface for non-leaf (value-object) paths — `f('address')`
414
+ * when `address` is a `ContractValueObject`. Intentionally minimal: the
415
+ * whole-value ops that make sense on a structured sub-document
416
+ * (`set`/`unset`/`exists`, null presence via `eq(null)`/`ne(null)`). Field-
417
+ * level ops belong on the constituent leaves (`f('address.city')`).
418
+ *
419
+ * The aggregation `node` is still present (`TypedAggExpr<ObjectField<N>>`)
420
+ * so the value object can be piped through `$addFields` /
421
+ * `$replaceRoot` / etc. as-is.
422
+ */
423
+ interface ObjectExpression<N$1 extends NestedDocShape> extends TypedAggExpr<ObjectField<N$1>> {
424
+ readonly _path: string;
425
+ exists(flag?: boolean): MongoFilterExpr;
426
+ eq(value: null): MongoFilterExpr;
427
+ ne(value: null): MongoFilterExpr;
428
+ set(value: MongoValue): TypedUpdateOp;
429
+ unset(): TypedUpdateOp;
430
+ }
431
+ /**
432
+ * The unified field accessor expression returned by `FieldAccessor` (per
433
+ * [ADR 180](../../../../docs/architecture%20docs/adrs/ADR%20180%20-%20Dot-path%20field%20accessor.md)).
434
+ *
435
+ * Resolves to `ObjectExpression<Sub>` when `F` is an `ObjectField<Sub>`
436
+ * (non-leaf path), otherwise to `LeafExpression<F>` (the full operator
437
+ * surface). The conditional is driven off the `fields` marker that
438
+ * `ObjectField` adds to `DocField`, so existing code that uses plain
439
+ * `DocField` shapes continues to resolve to `LeafExpression`.
440
+ */
441
+ type Expression<F extends DocField> = F extends ObjectField<infer N> ? ObjectExpression<N> : LeafExpression<F>;
442
+ /**
443
+ * Emitters for MongoDB update-pipeline stages (`$addFields`/`$set`,
444
+ * `$project`/`$unset`, `$replaceRoot`/`$replaceWith`). These return
445
+ * `MongoUpdatePipelineStage` nodes and let an updater callback express
446
+ * the pipeline-form update as an alternative to the typed-operator form.
447
+ *
448
+ * The two forms are mutually exclusive per updater call: `resolveUpdaterResult`
449
+ * rejects arrays that mix `TypedUpdateOp` and `MongoUpdatePipelineStage`
450
+ * entries with a clear error — an updater callback must return either all
451
+ * typed ops or all pipeline stages. Pick the form that matches the update
452
+ * you want and commit to it for that call site.
453
+ *
454
+ * Accessible via `f.stage` on the `FieldAccessor`.
455
+ */
456
+ interface StageEmitters {
457
+ set(fields: Record<string, MongoAggExpr>): MongoUpdatePipelineStage;
458
+ unset(...paths: ReadonlyArray<string>): MongoUpdatePipelineStage;
459
+ replaceRoot(newRoot: MongoAggExpr): MongoUpdatePipelineStage;
460
+ replaceWith(newRoot: MongoAggExpr): MongoUpdatePipelineStage;
461
+ }
462
+ /**
463
+ * The unified `FieldAccessor` per ADR 180.
464
+ *
465
+ * - Property access (`f.status`) returns an `Expression<F>` whose codec
466
+ * comes from the current pipeline shape `S`.
467
+ * - Callable form (`f('address.city')`) returns an `Expression<ResolvePath<N, P>>`
468
+ * where `N` is the nested shape carrying value-object sub-shapes.
469
+ * Paths that don't exist in `N` are rejected with a compile-time error
470
+ * (via `P extends ValidPaths<N>`). Non-leaf paths like `f('address')`
471
+ * resolve to an `ObjectExpression` whose reduced surface covers the
472
+ * whole-value operations (`set`, `unset`, `exists`, `eq(null)`,
473
+ * `ne(null)`).
474
+ * - `f.rawPath('path')` is a deliberate escape hatch that skips path
475
+ * validation and returns a `LeafExpression<F>` for the given string.
476
+ * Intended for migration authoring where the target field is not yet
477
+ * part of the typed contract (e.g. a backfill writing a newly-added
478
+ * column before the contract hash rolls forward). The method name is
479
+ * deliberately `rawPath` rather than `raw` so it does not shadow a
480
+ * legitimate top-level `raw` field on a user model.
481
+ * - `f.stage` exposes pipeline-style update emitters (`$set`, `$unset`,
482
+ * `$replaceRoot`, `$replaceWith`).
483
+ *
484
+ * When `N` is `Record<string, never>` (the default — e.g. after a
485
+ * replacement stage like `$group` / `$project` / `$replaceRoot`),
486
+ * `ValidPaths<N>` is `never` and the callable form is effectively
487
+ * disabled at the type level. This keeps the builder sound downstream of
488
+ * stages that invalidate the original document's nested-path tree.
489
+ * `f.rawPath(...)` remains available in that state for callers that need
490
+ * an explicit unvalidated path.
491
+ */
492
+ type FieldAccessor<S extends DocShape, N$1 extends NestedDocShape = Record<string, never>> = { readonly [K in keyof S & string]: Expression<S[K]> } & (<P$1 extends ValidPaths<N$1>>(path: P$1) => Expression<ResolvePath<N$1, P$1>>) & {
493
+ readonly stage: StageEmitters;
494
+ /**
495
+ * Escape hatch: build a `LeafExpression<F>` for an unvalidated string
496
+ * path. Use only when the path is intentionally outside the typed
497
+ * model surface — data-migration authoring is the canonical case
498
+ * (e.g. backfilling a field that is not yet in the contract). Default
499
+ * `F` is the opaque `DocField`; callers can narrow via the explicit
500
+ * generic: `f.rawPath<StringField>("status").set("active")`.
501
+ *
502
+ * The method is named `rawPath` (not `raw`) so a user model with a
503
+ * top-level `raw` field still resolves `f.raw` to the field-expression
504
+ * property, not to this escape hatch. Does not participate in
505
+ * `ValidPaths<N>` / `ResolvePath<N, P>` — the path is passed through
506
+ * verbatim and no IDE autocomplete is offered.
507
+ */
508
+ rawPath<F extends DocField = DocField>(path: string): LeafExpression<F>;
509
+ };
510
+ /**
511
+ * Construct a unified `FieldAccessor<S, N>` proxy. Property access creates
512
+ * an `Expression` using the property name as the field path; callable
513
+ * form accepts a dot-path string validated against `N` at compile time.
514
+ *
515
+ * The proxy target is a function so the resulting object is both callable
516
+ * and indexable. Symbol-keyed accesses (e.g. `Symbol.toPrimitive`) return
517
+ * `undefined` to keep accidental coercion behaviour unsurprising —
518
+ * matching the previous `FieldProxy` / `FilterProxy` semantics.
519
+ */
520
+ declare function createFieldAccessor<S extends DocShape, N$1 extends NestedDocShape = Record<string, never>>(): FieldAccessor<S, N$1>;
521
+ //#endregion
522
+ //#region src/markers.d.ts
523
+ /**
524
+ * Phantom capability markers for `PipelineChain`.
525
+ *
526
+ * `UpdateEnabled` — gates `.updateMany()` / `.updateOne()` no-arg form
527
+ * (consume accumulated pipeline as an update-with-pipeline spec).
528
+ * `FindAndModifyEnabled` — gates `.findOneAndUpdate(...)` / `.findOneAndDelete(...)`
529
+ * (deconstruct pipeline into the wire command's filter/sort/skip slots).
530
+ * `LeadingMatch` — internal marker tracking whether the chain is still
531
+ * in its leading-`$match` prefix. Flips to `'past-leading'`
532
+ * after the first non-`$match` stage, which lets
533
+ * `match()` clear `UpdateEnabled` on second `$match`
534
+ * stages that sit past the prefix (and would otherwise
535
+ * fail at runtime inside `deconstructUpdateChain`).
536
+ *
537
+ * Each pipeline-stage method either preserves or clears these markers per
538
+ * the marker table (and rationale per row) in
539
+ * `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.
540
+ *
541
+ * The markers exist only at the type level; nothing reads them at runtime.
542
+ * Value literals are self-identifying so the slots are distinguishable in
543
+ * hover tooltips and error messages (e.g. `'update-ok'` vs `'fam-ok'`).
544
+ */
545
+ type UpdateEnabled = 'update-ok' | 'update-cleared';
546
+ type FindAndModifyEnabled = 'fam-ok' | 'fam-cleared';
547
+ type LeadingMatch = 'leading' | 'past-leading';
548
+ //#endregion
549
+ //#region src/builder.d.ts
550
+ interface PipelineChainState {
551
+ readonly collection: string;
552
+ readonly stages: ReadonlyArray<MongoPipelineStage>;
553
+ readonly storageHash: string;
554
+ }
555
+ /**
556
+ * The pipeline state in the query-builder state machine.
557
+ *
558
+ * Reached from `CollectionHandle` or `FilteredCollection` after the first
559
+ * pipeline-stage method call (or directly via `aggregate()` shortcuts). Holds
560
+ * the accumulated `MongoPipelineStage[]` and exposes pipeline-stage methods,
561
+ * the `merge`/`out` write terminals, and the `build`/`aggregate` read
562
+ * terminals.
563
+ *
564
+ * Two phantom type parameters gate the conditional terminals:
565
+ *
566
+ * - `U extends UpdateEnabled` — when `'update-ok'`, the no-arg `updateMany()` /
567
+ * `updateOne()` form is available (consume the chain as an
568
+ * update-with-pipeline spec). Cleared by stages that produce content the
569
+ * `update` AST cannot represent (e.g. `$group`, `$lookup`, `$limit`).
570
+ * - `F extends FindAndModifyEnabled` — when `'fam-ok'`, the
571
+ * `findOneAndUpdate(...)` / `findOneAndDelete(...)` terminals are
572
+ * available. Cleared by stages incompatible with their wire-command slots
573
+ * (`$limit`, `$group`, mutating stages, …).
574
+ *
575
+ * The marker semantics are encoded in the per-method return types — see the
576
+ * marker table (and rationale per row) in
577
+ * `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.
578
+ */
579
+ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, Shape extends DocShape, U extends UpdateEnabled = 'update-ok', F extends FindAndModifyEnabled = 'fam-ok', L extends LeadingMatch = 'leading', N$1 extends NestedDocShape = Record<string, never>> {
580
+ #private;
581
+ readonly __updateCompat: U;
582
+ readonly __findAndModifyCompat: F;
583
+ readonly __leadingMatch: L;
584
+ constructor(contract: TContract, state: PipelineChainState);
585
+ /**
586
+ * `$match`. `FindAndModifyEnabled` is always preserved. `UpdateEnabled` is
587
+ * preserved only while the chain is still in the leading-`$match` prefix
588
+ * (`L = 'leading'`); a `$match` that follows any non-`$match` stage
589
+ * transitions to `L = 'past-leading'` and clears `UpdateEnabled`, since
590
+ * `deconstructUpdateChain` can only peel leading `$match` stages into the
591
+ * wire-command filter.
592
+ */
593
+ match(filter: MongoFilterExpr): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N$1>;
594
+ match(fn: (fields: FieldAccessor<Shape, N$1>) => MongoFilterExpr): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N$1>;
595
+ /**
596
+ * `$sort`. Clears `UpdateEnabled` (`update` has no per-document sort) but
597
+ * preserves `FindAndModifyEnabled` (`findAndModify` has a `sort` slot).
598
+ */
599
+ sort(spec: SortSpec<Shape>): PipelineChain<TContract, Shape, 'update-cleared', F, 'past-leading', N$1>;
600
+ /**
601
+ * `$limit`. Clears both markers — `limit` is incompatible with the `update`
602
+ * wire command, and `findAndModify` already implies single-document
603
+ * semantics (so `.limit(...)` adds no meaning, only ambiguity).
604
+ */
605
+ limit(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
606
+ /**
607
+ * `$skip`. Clears both markers — MongoDB's `findAndModify` wire command
608
+ * has no `skip` slot, so `deconstructFindAndModifyChain` rejects any
609
+ * `$skip` at runtime; keeping the marker `fam-cleared` makes the type
610
+ * system reflect the same constraint (see ADR 201 marker table).
611
+ */
612
+ skip(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
613
+ sample(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
614
+ /**
615
+ * `$addFields`. Preserves `UpdateEnabled` (representable as
616
+ * update-with-pipeline `$set`); clears `FindAndModifyEnabled` (no analogue
617
+ * in the find-and-modify wire commands). The nested-path shape `N` is
618
+ * preserved — newly added flat fields are reachable via property access
619
+ * (`f.newField`) but do not themselves carry nested structure.
620
+ */
621
+ addFields<NewFields extends Record<string, TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N$1>) => NewFields): PipelineChain<TContract, Shape & ExtractDocShape<NewFields>, U, 'fam-cleared', 'past-leading', N$1>;
622
+ /**
623
+ * `$lookup`. Clears both markers — joins are not representable in either
624
+ * the `update` or `findAndModify` wire commands. The original document's
625
+ * nested-path shape `N` is preserved (the lookup adds a sidecar array
626
+ * field; existing keys are untouched).
627
+ */
628
+ lookup<ForeignRoot extends keyof TContract['roots'] & string, As extends string>(options: {
629
+ from: ForeignRoot;
630
+ localField: keyof Shape & string;
631
+ foreignField: string;
632
+ as: As;
633
+ }): PipelineChain<TContract, Shape & Record<As, {
634
+ readonly codecId: 'mongo/array@1';
635
+ readonly nullable: false;
636
+ }>, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
637
+ /**
638
+ * `$project`. Preserves `UpdateEnabled` (representable as update-with-pipeline
639
+ * `$project` / `$unset`); clears `FindAndModifyEnabled` (use `.project()` on
640
+ * the result of `.build()` if both projection and find-and-modify are
641
+ * needed — see spec).
642
+ *
643
+ * Resets the nested-path shape to `Record<string, never>` — projection
644
+ * fundamentally rewrites the document, so dot-paths into the *source*
645
+ * document are no longer meaningful downstream.
646
+ */
647
+ project<K$1 extends keyof Shape & string>(...keys: K$1[]): PipelineChain<TContract, Pick<Shape, K$1 | ('_id' extends keyof Shape ? '_id' : never)>, U, 'fam-cleared', 'past-leading'>;
648
+ project<Spec extends Record<string, 1 | TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N$1>) => Spec): PipelineChain<TContract, ProjectedShape<Shape, Spec>, U, 'fam-cleared', 'past-leading'>;
649
+ /**
650
+ * `$unwind`. Clears both markers — array unrolling produces multiple output
651
+ * documents per input, incompatible with both single-document update and
652
+ * find-and-modify wire commands. The original `N` is preserved: unwind
653
+ * replaces the unwound array slot with its element but leaves the rest
654
+ * of the document structurally intact.
655
+ */
656
+ unwind<K$1 extends keyof Shape & string>(field: K$1, options?: {
657
+ preserveNullAndEmptyArrays?: boolean;
658
+ }): PipelineChain<TContract, UnwoundShape<Shape, K$1>, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
659
+ /**
660
+ * `$group`. Clears both markers — group output bears no relation to source
661
+ * documents; neither `update` nor `findAndModify` can consume it. Nested
662
+ * path shape is reset (the source document's path tree is gone).
663
+ */
664
+ group<Spec extends GroupSpec>(fn: (fields: FieldAccessor<Shape, N$1>) => Spec): PipelineChain<TContract, GroupedDocShape<Spec>, 'update-cleared', 'fam-cleared', 'past-leading'>;
665
+ /**
666
+ * `$replaceRoot`. Preserves `UpdateEnabled` (representable as
667
+ * update-with-pipeline `$replaceRoot`); clears `FindAndModifyEnabled`.
668
+ * Nested path shape is reset — the replaced root has no relation to
669
+ * the original document structure.
670
+ */
671
+ replaceRoot<NewShape extends DocShape>(fn: (fields: FieldAccessor<Shape, N$1>) => Expression<DocField> | TypedAggExpr<DocField>): PipelineChain<TContract, NewShape, U, 'fam-cleared', 'past-leading'>;
672
+ count<Field extends string>(field: Field): PipelineChain<TContract, Record<Field, {
673
+ readonly codecId: 'mongo/double@1';
674
+ readonly nullable: false;
675
+ }>, 'update-cleared', 'fam-cleared', 'past-leading'>;
676
+ sortByCount<F2 extends DocField>(fn: (fields: FieldAccessor<Shape, N$1>) => Expression<F2> | TypedAggExpr<F2>): PipelineChain<TContract, {
677
+ _id: F2;
678
+ count: {
679
+ readonly codecId: 'mongo/double@1';
680
+ readonly nullable: false;
681
+ };
682
+ }, 'update-cleared', 'fam-cleared', 'past-leading'>;
683
+ /**
684
+ * `$redact`. Preserves `UpdateEnabled`; clears `FindAndModifyEnabled`.
685
+ * Shape- and nested-path-preserving (the document tree is unchanged).
686
+ */
687
+ redact(fn: (fields: FieldAccessor<Shape, N$1>) => Expression<DocField> | TypedAggExpr<DocField>): PipelineChain<TContract, Shape, U, 'fam-cleared', 'past-leading', N$1>;
688
+ /**
689
+ * `$out` write terminal. Materialises the pipeline output into
690
+ * `collection` (optionally in `db`), replacing any prior contents. Unlike
691
+ * the other pipeline-stage methods, this **terminates** the chain — it
692
+ * returns a `MongoQueryPlan` rather than another `PipelineChain`, since
693
+ * `$out` must be the final stage and there is nothing further to chain.
694
+ *
695
+ * Lane is `mongo-query` (matching all other terminals in this package) so
696
+ * middleware can dispatch on intent without inspecting the command.
697
+ *
698
+ * The result row stream is empty (`unknown` row type) — the data lives
699
+ * in the destination collection, not the response.
700
+ */
701
+ out(collection: string, db?: string): MongoQueryPlan<unknown, AggregateCommand>;
702
+ /**
703
+ * `$merge` write terminal. Streams the pipeline output into the target
704
+ * collection per the supplied merge semantics (`whenMatched` /
705
+ * `whenNotMatched`). Like `out()`, terminates the chain — `$merge` must
706
+ * be the final stage.
707
+ */
708
+ merge(options: {
709
+ into: string | {
710
+ db: string;
711
+ coll: string;
712
+ };
713
+ on?: string | ReadonlyArray<string>;
714
+ whenMatched?: string | ReadonlyArray<MongoUpdatePipelineStage>;
715
+ whenNotMatched?: string;
716
+ }): MongoQueryPlan<unknown, AggregateCommand>;
717
+ unionWith(collection: string, pipeline?: ReadonlyArray<MongoPipelineStage>): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
718
+ bucket(options: {
719
+ groupBy: MongoAggExpr;
720
+ boundaries: ReadonlyArray<unknown>;
721
+ default_?: unknown;
722
+ output?: Record<string, MongoAggAccumulator>;
723
+ }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
724
+ bucketAuto(options: {
725
+ groupBy: MongoAggExpr;
726
+ buckets: number;
727
+ output?: Record<string, MongoAggAccumulator>;
728
+ granularity?: string;
729
+ }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
730
+ geoNear(options: {
731
+ near: unknown;
732
+ distanceField: string;
733
+ spherical?: boolean;
734
+ maxDistance?: number;
735
+ minDistance?: number;
736
+ query?: MongoFilterExpr;
737
+ key?: string;
738
+ distanceMultiplier?: number;
739
+ includeLocs?: string;
740
+ }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
741
+ facet(facets: Record<string, ReadonlyArray<MongoPipelineStage>>): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
742
+ graphLookup(options: {
743
+ from: string;
744
+ startWith: MongoAggExpr;
745
+ connectFromField: string;
746
+ connectToField: string;
747
+ as: string;
748
+ maxDepth?: number;
749
+ depthField?: string;
750
+ restrictSearchWithMatch?: MongoFilterExpr;
751
+ }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
752
+ setWindowFields(options: {
753
+ partitionBy?: MongoAggExpr;
754
+ sortBy?: Record<string, 1 | -1>;
755
+ output: Record<string, MongoWindowField>;
756
+ }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
757
+ densify(options: {
758
+ field: string;
759
+ partitionByFields?: ReadonlyArray<string>;
760
+ range: MongoDensifyRange;
761
+ }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
762
+ fill(options: {
763
+ partitionBy?: MongoAggExpr;
764
+ partitionByFields?: ReadonlyArray<string>;
765
+ sortBy?: Record<string, 1 | -1>;
766
+ output: Record<string, MongoFillOutput>;
767
+ }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
768
+ search(config: Record<string, unknown>, index?: string): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
769
+ searchMeta(config: Record<string, unknown>, index?: string): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
770
+ vectorSearch(options: {
771
+ index: string;
772
+ path: string;
773
+ queryVector: ReadonlyArray<number>;
774
+ numCandidates: number;
775
+ limit: number;
776
+ filter?: Record<string, unknown>;
777
+ }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
778
+ pipe(stage: MongoPipelineStage): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading'>;
779
+ pipe<NewShape extends DocShape>(stage: MongoPipelineStage): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
780
+ /**
781
+ * No-arg `updateMany()`: deconstruct the chain into leading `$match`
782
+ * stages (folded into the filter) and remaining stages (which must all
783
+ * be valid pipeline-update stages). Available only when `U = 'update-ok'`.
784
+ *
785
+ * The optional callback parameter exists for subclass-override
786
+ * compatibility with `FilteredCollection.updateMany(updaterFn)` — TS's
787
+ * strict override check requires the parent's parameter to accept at
788
+ * least what the child's signature does. A runtime guard throws if a
789
+ * callback is actually passed on a bare `PipelineChain`. Note that
790
+ * because nothing in the public surface transitions `U` from
791
+ * `'update-cleared'` (the initial state on `CollectionHandle` /
792
+ * `FilteredCollection`) back to `'update-ok'`, the no-arg form is
793
+ * reachable only via explicit type casts in internal tests — the
794
+ * callback-form "type hole" is therefore not reachable from user
795
+ * code. See `docs/architecture docs/adrs/ADR 201 - State-machine
796
+ * pattern for typed DSL builders.md` for the marker-transition table.
797
+ */
798
+ updateMany(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N$1>, updaterFn?: (fields: FieldAccessor<Shape, N$1>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateManyCommand>;
799
+ /**
800
+ * No-arg `updateOne()`: same as `updateMany()` but maps to a single-doc
801
+ * update. Carries the same optional-callback/subclass-compat caveat
802
+ * documented above — the callback form is reachable only via forced
803
+ * casts in internal tests.
804
+ */
805
+ updateOne(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N$1>, updaterFn?: (fields: FieldAccessor<Shape, N$1>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateOneCommand>;
806
+ /**
807
+ * Find a single document matching the accumulated pipeline (which must
808
+ * consist solely of leading `$match` stages followed by at most one
809
+ * `$sort`) and apply `updaterFn`. Available only when
810
+ * `FindAndModifyEnabled` is `'fam-ok'` — stages that clear the marker
811
+ * (including `$skip`, which MongoDB's `findAndModify` has no slot for)
812
+ * make this method invisible at the type level.
813
+ *
814
+ * The pipeline stages are deconstructed into the wire command's `filter`
815
+ * and `sort` slots. If any non-deconstructable stage is present, a
816
+ * runtime error is thrown as a defensive check (the type system should
817
+ * prevent this).
818
+ */
819
+ findOneAndUpdate(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N$1>, updaterFn: (fields: FieldAccessor<Shape, N$1>) => UpdaterResult, opts?: {
820
+ readonly upsert?: boolean;
821
+ readonly returnDocument?: 'before' | 'after';
822
+ }): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>> | null, FindOneAndUpdateCommand>;
823
+ /**
824
+ * Find a single document matching the accumulated pipeline and delete it.
825
+ * Same marker gating and deconstruction as `findOneAndUpdate`.
826
+ */
827
+ findOneAndDelete(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N$1>): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>> | null, FindOneAndDeleteCommand>;
828
+ /**
829
+ * Materialise the chain as a `MongoQueryPlan` wrapping an `AggregateCommand`.
830
+ */
831
+ build(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>>, AggregateCommand>;
832
+ /**
833
+ * Alias for `build()` — surfaces the read intent at the call site.
834
+ */
835
+ aggregate(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>>, AggregateCommand>;
836
+ }
837
+ //#endregion
838
+ //#region src/expression-helpers.d.ts
839
+ declare function literal(value: string): TypedAggExpr<StringField>;
840
+ declare function literal(value: number): TypedAggExpr<NumericField>;
841
+ declare function literal(value: boolean): TypedAggExpr<BooleanField>;
842
+ declare function literal(value: Date): TypedAggExpr<DateField>;
843
+ declare function literal<F extends DocField>(value: LiteralValue<F>): TypedAggExpr<F>;
844
+ declare const fn: {
845
+ add(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField>;
846
+ subtract(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
847
+ multiply(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField>;
848
+ divide(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
849
+ concat(...args: TypedAggExpr<DocField>[]): TypedAggExpr<StringField>;
850
+ toLower(a: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
851
+ toUpper(a: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
852
+ size(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
853
+ cond<F extends DocField>(condition: MongoAggExpr, thenExpr: TypedAggExpr<F>, elseExpr: TypedAggExpr<DocField>): TypedAggExpr<F>;
854
+ literal: typeof literal;
855
+ year(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
856
+ month(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
857
+ dayOfMonth(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
858
+ hour(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
859
+ minute(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
860
+ second(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
861
+ millisecond(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
862
+ dateToString(args: {
863
+ date: TypedAggExpr<DateField>;
864
+ format?: TypedAggExpr<StringField>;
865
+ timezone?: TypedAggExpr<StringField>;
866
+ onNull?: TypedAggExpr<DocField>;
867
+ }): TypedAggExpr<StringField>;
868
+ dateFromString(args: {
869
+ dateString: TypedAggExpr<StringField>;
870
+ format?: TypedAggExpr<StringField>;
871
+ timezone?: TypedAggExpr<StringField>;
872
+ onError?: TypedAggExpr<DocField>;
873
+ onNull?: TypedAggExpr<DocField>;
874
+ }): TypedAggExpr<DateField>;
875
+ dateDiff(args: {
876
+ startDate: TypedAggExpr<DateField>;
877
+ endDate: TypedAggExpr<DateField>;
878
+ unit: TypedAggExpr<StringField>;
879
+ timezone?: TypedAggExpr<StringField>;
880
+ startOfWeek?: TypedAggExpr<StringField>;
881
+ }): TypedAggExpr<NumericField>;
882
+ dateAdd(args: {
883
+ startDate: TypedAggExpr<DateField>;
884
+ unit: TypedAggExpr<StringField>;
885
+ amount: TypedAggExpr<NumericField>;
886
+ timezone?: TypedAggExpr<StringField>;
887
+ }): TypedAggExpr<DateField>;
888
+ dateSubtract(args: {
889
+ startDate: TypedAggExpr<DateField>;
890
+ unit: TypedAggExpr<StringField>;
891
+ amount: TypedAggExpr<NumericField>;
892
+ timezone?: TypedAggExpr<StringField>;
893
+ }): TypedAggExpr<DateField>;
894
+ dateTrunc(args: {
895
+ date: TypedAggExpr<DateField>;
896
+ unit: TypedAggExpr<StringField>;
897
+ binSize?: TypedAggExpr<NumericField>;
898
+ timezone?: TypedAggExpr<StringField>;
899
+ startOfWeek?: TypedAggExpr<StringField>;
900
+ }): TypedAggExpr<DateField>;
901
+ substr(str: TypedAggExpr<DocField>, start: TypedAggExpr<DocField>, length: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
902
+ substrBytes(str: TypedAggExpr<DocField>, start: TypedAggExpr<DocField>, count: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
903
+ trim(args: {
904
+ input: TypedAggExpr<StringField>;
905
+ chars?: TypedAggExpr<StringField>;
906
+ }): TypedAggExpr<StringField>;
907
+ ltrim(args: {
908
+ input: TypedAggExpr<StringField>;
909
+ chars?: TypedAggExpr<StringField>;
910
+ }): TypedAggExpr<StringField>;
911
+ rtrim(args: {
912
+ input: TypedAggExpr<StringField>;
913
+ chars?: TypedAggExpr<StringField>;
914
+ }): TypedAggExpr<StringField>;
915
+ split(str: TypedAggExpr<DocField>, delimiter: TypedAggExpr<DocField>): TypedAggExpr<ArrayField>;
916
+ strLenCP(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
917
+ strLenBytes(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
918
+ regexMatch(args: {
919
+ input: TypedAggExpr<StringField>;
920
+ regex: TypedAggExpr<StringField>;
921
+ options?: TypedAggExpr<StringField>;
922
+ }): TypedAggExpr<BooleanField>;
923
+ regexFind(args: {
924
+ input: TypedAggExpr<StringField>;
925
+ regex: TypedAggExpr<StringField>;
926
+ options?: TypedAggExpr<StringField>;
927
+ }): TypedAggExpr<DocField>;
928
+ regexFindAll(args: {
929
+ input: TypedAggExpr<StringField>;
930
+ regex: TypedAggExpr<StringField>;
931
+ options?: TypedAggExpr<StringField>;
932
+ }): TypedAggExpr<ArrayField>;
933
+ replaceOne(args: {
934
+ input: TypedAggExpr<StringField>;
935
+ find: TypedAggExpr<StringField>;
936
+ replacement: TypedAggExpr<StringField>;
937
+ }): TypedAggExpr<StringField>;
938
+ replaceAll(args: {
939
+ input: TypedAggExpr<StringField>;
940
+ find: TypedAggExpr<StringField>;
941
+ replacement: TypedAggExpr<StringField>;
942
+ }): TypedAggExpr<StringField>;
943
+ cmp(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
944
+ eq(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
945
+ ne(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
946
+ gt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
947
+ gte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
948
+ lt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
949
+ lte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
950
+ arrayElemAt(arr: TypedAggExpr<DocField>, idx: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField>;
951
+ concatArrays(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField>;
952
+ firstElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField>;
953
+ lastElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField>;
954
+ isIn(elem: TypedAggExpr<DocField>, arr: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
955
+ indexOfArray(arr: TypedAggExpr<DocField>, value: TypedAggExpr<DocField>, ...rest: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField>;
956
+ isArray(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
957
+ reverseArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField>;
958
+ slice(arr: TypedAggExpr<DocField>, ...rest: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField>;
959
+ zip(args: {
960
+ inputs: TypedAggExpr<ArrayField>[];
961
+ useLongestLength?: TypedAggExpr<BooleanField>;
962
+ defaults?: TypedAggExpr<ArrayField>;
963
+ }): TypedAggExpr<ArrayField>;
964
+ range(start: TypedAggExpr<DocField>, end: TypedAggExpr<DocField>, step: TypedAggExpr<DocField>): TypedAggExpr<ArrayField>;
965
+ setUnion(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField>;
966
+ setIntersection(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField>;
967
+ setDifference(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<ArrayField>;
968
+ setEquals(...args: TypedAggExpr<DocField>[]): TypedAggExpr<BooleanField>;
969
+ setIsSubset(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
970
+ anyElementTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
971
+ allElementsTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
972
+ typeOf(a: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
973
+ convert(args: {
974
+ input: TypedAggExpr<DocField>;
975
+ to: TypedAggExpr<StringField | NumericField>;
976
+ onError?: TypedAggExpr<DocField>;
977
+ onNull?: TypedAggExpr<DocField>;
978
+ }): TypedAggExpr<DocField>;
979
+ toInt(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
980
+ toLong(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
981
+ toDouble(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
982
+ toDecimal(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField>;
983
+ toString_(a: TypedAggExpr<DocField>): TypedAggExpr<StringField>;
984
+ toObjectId(a: TypedAggExpr<DocField>): TypedAggExpr<DocField>;
985
+ toBool(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField>;
986
+ toDate(a: TypedAggExpr<DocField>): TypedAggExpr<DateField>;
987
+ objectToArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField>;
988
+ arrayToObject(a: TypedAggExpr<DocField>): TypedAggExpr<DocField>;
989
+ getField(args: {
990
+ field: TypedAggExpr<StringField>;
991
+ input?: TypedAggExpr<DocField>;
992
+ }): TypedAggExpr<DocField>;
993
+ setField(args: {
994
+ field: TypedAggExpr<StringField>;
995
+ input: TypedAggExpr<DocField>;
996
+ value: TypedAggExpr<DocField>;
997
+ }): TypedAggExpr<DocField>;
998
+ };
999
+ //#endregion
1000
+ //#region src/state-classes.d.ts
1001
+ /**
1002
+ * Root state of the query-builder state machine. Returned from
1003
+ * `mongoQuery(...).from(name)` and bound to a single collection.
1004
+ *
1005
+ * Inherits the entire pipeline-stage surface from `PipelineChain` (since an
1006
+ * empty `CollectionHandle` is observably an empty pipeline). Adds:
1007
+ *
1008
+ * - `match(...)` — overridden to transition to `FilteredCollection`, which
1009
+ * accumulates filters for eventual splatting into write/find-and-modify
1010
+ * wire commands.
1011
+ * - **Insert / unqualified-write methods** (M2): `insertOne`, `insertMany`,
1012
+ * `updateAll`, `deleteAll`. These live *only* here — the corresponding
1013
+ * methods are absent from `FilteredCollection`, so a caller cannot
1014
+ * accidentally produce an unqualified write by forgetting to `.match(...)`
1015
+ * later in the chain. Bodies land in M2.
1016
+ */
1017
+ declare class CollectionHandle<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends keyof TContract['models'] & string> extends PipelineChain<TContract, ModelToDocShape<TContract, ModelName>, 'update-cleared', 'fam-cleared', 'leading', ModelNestedShape<TContract, ModelName>> {
1018
+ #private;
1019
+ constructor(ctx: BindingContext<TContract>, modelName: ModelName);
1020
+ /**
1021
+ * Bound model name. Exposed so type tests can assert the binding without
1022
+ * flipping into a pipeline. Not part of the public-API contract.
1023
+ */
1024
+ get _modelName(): ModelName;
1025
+ /**
1026
+ * Begin accumulating a filter. Transitions to `FilteredCollection`.
1027
+ *
1028
+ * Overrides `PipelineChain.match` (which appends another `$match` stage
1029
+ * and stays in the chain). The two implementations are semantically
1030
+ * equivalent for the read terminal — multiple `$match` stages AND-fold in
1031
+ * Mongo — but `FilteredCollection` makes the accumulated filter
1032
+ * addressable for the write/find-and-modify terminals landing in M2/M3.
1033
+ */
1034
+ match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;
1035
+ match(fn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => MongoFilterExpr): FilteredCollection<TContract, ModelName>;
1036
+ /**
1037
+ * Insert a single document. Document fields are passed straight through to
1038
+ * the wire `InsertOneCommand` — codec normalisation happens at the
1039
+ * adapter/driver boundary, identically to the SQL builder (see Open Item
1040
+ * #14 confirmation in the design conversation).
1041
+ *
1042
+ * Returns a `MongoQueryPlan<InsertOneResult>` whose row stream yields a
1043
+ * single result document with the server-assigned `insertedId`.
1044
+ */
1045
+ insertOne(document: Record<string, MongoValue>): MongoQueryPlan<InsertOneResult$1, InsertOneCommand>;
1046
+ /**
1047
+ * Insert a batch of documents. Order is preserved in the returned
1048
+ * `insertedIds` array.
1049
+ */
1050
+ insertMany(documents: ReadonlyArray<Record<string, MongoValue>>): MongoQueryPlan<InsertManyResult$1, InsertManyCommand>;
1051
+ /**
1052
+ * Update *every* document in the collection. Lives only on
1053
+ * `CollectionHandle` — the corresponding method is intentionally absent
1054
+ * from `FilteredCollection` so a caller cannot accidentally produce an
1055
+ * unqualified write by forgetting to `.match(...)` first. Pair with
1056
+ * `.match(...).updateMany(...)` for the filtered case.
1057
+ */
1058
+ updateAll(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateManyCommand>;
1059
+ /**
1060
+ * Delete *every* document in the collection. See `updateAll` for the
1061
+ * rationale around the unqualified-write surface being limited to this
1062
+ * state class.
1063
+ */
1064
+ deleteAll(): MongoQueryPlan<DeleteResult$1, DeleteManyCommand>;
1065
+ /**
1066
+ * Insert-or-update the document matching `filterFn`. The filter is
1067
+ * mandatory (vs. `updateAll`'s tautological match) because an upsert
1068
+ * without a discriminating predicate would either match every existing
1069
+ * document or insert an indistinguishable new one.
1070
+ *
1071
+ * Maps to `UpdateOneCommand` with `upsert: true`. The driver inserts a
1072
+ * new document derived from the filter equality fields plus the update
1073
+ * spec when no match is found; otherwise updates the matched document.
1074
+ */
1075
+ upsertOne(filterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => MongoFilterExpr, updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateOneCommand>;
1076
+ }
1077
+ /**
1078
+ * State reached after one or more `.match(...)` calls on `CollectionHandle`.
1079
+ *
1080
+ * Inherits the pipeline-stage surface from `PipelineChain`, with the
1081
+ * accumulated filters baked in as a leading `$match` stage on the underlying
1082
+ * pipeline state. This means read-terminal output (`.aggregate()` /
1083
+ * `.build()`) and any subsequent pipeline-stage chain see the filtered
1084
+ * collection as input — the read story works through pure inheritance.
1085
+ *
1086
+ * Adds:
1087
+ *
1088
+ * - `match(...)` — pushes another `$match` stage *and* records the filter in
1089
+ * the accumulator, so the eventual write/find-and-modify terminal can
1090
+ * splat the AND-folded filter into the wire command's `filter` slot.
1091
+ * - **Filtered writes** (M2): `updateMany`, `updateOne`, `deleteMany`,
1092
+ * `deleteOne`, `upsertOne`. Stubbed in M1. (Upsert-many is an open
1093
+ * question in the spec — see TML-2267 — and is intentionally absent.)
1094
+ * - **Find-and-modify** (M3): `findOneAndUpdate`, `findOneAndDelete`.
1095
+ * Stubbed in M1.
1096
+ *
1097
+ * Notably *does not* expose `insertOne`/`insertMany`/`updateAll`/`deleteAll`
1098
+ * — those are insert or unqualified-write operations that are nonsense
1099
+ * after a filter has been applied.
1100
+ */
1101
+ declare class FilteredCollection<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends keyof TContract['models'] & string> extends PipelineChain<TContract, ModelToDocShape<TContract, ModelName>, 'update-cleared', 'fam-cleared', 'leading', ModelNestedShape<TContract, ModelName>> {
1102
+ #private;
1103
+ constructor(ctx: BindingContext<TContract>, modelName: ModelName, filters: ReadonlyArray<MongoFilterExpr>);
1104
+ get _modelName(): ModelName;
1105
+ /**
1106
+ * Accumulated filter list. Exposed for the M2/M3 write/find-and-modify
1107
+ * terminals to splat into wire-command `filter` slots; not part of the
1108
+ * public-API contract.
1109
+ */
1110
+ get _filters(): ReadonlyArray<MongoFilterExpr>;
1111
+ /**
1112
+ * Append another filter to the accumulator. Returns a new
1113
+ * `FilteredCollection` whose underlying pipeline rebuilds the leading
1114
+ * `$match` from the AND-folded accumulator (rather than appending a
1115
+ * second `$match` stage), so the write/find-and-modify terminals see a
1116
+ * single authoritative filter expression.
1117
+ */
1118
+ match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;
1119
+ match(fn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => MongoFilterExpr): FilteredCollection<TContract, ModelName>;
1120
+ /**
1121
+ * Update every matching document. `updaterFn` receives a `FieldAccessor`
1122
+ * and returns an array of `TypedUpdateOp` (e.g. `[f.amount.inc(1),
1123
+ * f.status.set('done')]`). Operators are folded into the wire-format
1124
+ * update spec by `foldUpdateOps`, which throws on operator+path
1125
+ * collisions.
1126
+ */
1127
+ updateMany(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateManyCommand>;
1128
+ /**
1129
+ * Update at most one matching document. The driver picks the document
1130
+ * (typically the first one matched by the underlying scan); no ordering
1131
+ * guarantee is implied — chain `.sort(...)` and use the M3
1132
+ * `.findOneAndUpdate(...)` terminal when ordering matters.
1133
+ */
1134
+ updateOne(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateOneCommand>;
1135
+ /**
1136
+ * Delete every matching document.
1137
+ */
1138
+ deleteMany(): MongoQueryPlan<DeleteResult$1, DeleteManyCommand>;
1139
+ /**
1140
+ * Delete at most one matching document. See the `updateOne` note about
1141
+ * driver-chosen victim selection.
1142
+ */
1143
+ deleteOne(): MongoQueryPlan<DeleteResult$1, DeleteOneCommand>;
1144
+ /**
1145
+ * Insert-or-update against the accumulated filter. Maps to
1146
+ * `UpdateOneCommand` with `upsert: true`. Equivalent to
1147
+ * `CollectionHandle.upsertOne(f => filter, updaterFn)` but reuses the
1148
+ * already-accumulated `.match(...)` filter chain.
1149
+ */
1150
+ upsertOne(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateOneCommand>;
1151
+ /**
1152
+ * Find a single matching document and apply `updaterFn` to it.
1153
+ *
1154
+ * `opts.upsert` (default `false`) toggles insert-on-miss behaviour.
1155
+ * `opts.returnDocument` (default `'after'`) controls whether the row
1156
+ * stream yields the document as it was before or after the update.
1157
+ */
1158
+ findOneAndUpdate(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult, opts?: {
1159
+ readonly upsert?: boolean;
1160
+ readonly returnDocument?: 'before' | 'after';
1161
+ }): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>> | null, FindOneAndUpdateCommand>;
1162
+ /**
1163
+ * Find a single matching document and delete it. Returns the deleted
1164
+ * document via the row stream.
1165
+ */
1166
+ findOneAndDelete(): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>> | null, FindOneAndDeleteCommand>;
1167
+ }
1168
+ /**
1169
+ * Bound execution context shared across the three state classes.
1170
+ */
1171
+ interface BindingContext<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>> {
1172
+ readonly contract: TContract;
1173
+ readonly collection: string;
1174
+ readonly storageHash: string;
1175
+ }
1176
+ //#endregion
1177
+ //#region src/query.d.ts
1178
+ /**
1179
+ * Public entry point of the query builder. `mongoQuery(...).from(rootName)`
1180
+ * yields the root state of the three-state machine
1181
+ * (`CollectionHandle` → `FilteredCollection` → `PipelineChain`).
1182
+ *
1183
+ * `rawCommand(cmd)` is the escape hatch for cases the typed surface does
1184
+ * not cover (yet) — it accepts any `AnyMongoCommand` (typed CRUD or a
1185
+ * `RawMongoCommand` of `Document`s) and packages it into a `MongoQueryPlan`
1186
+ * with `lane: 'mongo-query'`. Row type is `unknown` because the runtime
1187
+ * cannot know what the caller's command yields.
1188
+ */
1189
+ interface QueryRoot<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>> {
1190
+ from<K$1 extends keyof TContract['roots'] & string>(rootName: K$1): CollectionHandle<TContract, TContract['roots'][K$1] & string & keyof TContract['models']>;
1191
+ rawCommand<C$1 extends AnyMongoCommand>(command: C$1): MongoQueryPlan<unknown, C$1>;
1192
+ }
1193
+ declare function mongoQuery<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(options: {
1194
+ contractJson: unknown;
1195
+ }): QueryRoot<TContract>;
1196
+ //#endregion
1197
+ export { type ArrayField, type BooleanField, CollectionHandle, type DateField, type DeleteResult, type DocField, type DocShape, type Expression, type ExtractDocShape, type FieldAccessor, FilteredCollection, type FindAndModifyEnabled, type GroupSpec, type GroupedDocShape, type InsertManyResult, type InsertOneResult, type LeafExpression, type LiteralValue, type ModelNestedShape, type ModelToDocShape, type NestedDocShape, type NullableDocField, type NullableNumericField, type NumericField, type ObjectExpression, type ObjectField, type PathCompletions, PipelineChain, type ProjectedShape, type QueryRoot, type ResolvePath, type ResolveRow, type SortSpec, type StringField, type TypedAccumulatorExpr, type TypedAggExpr, type TypedUpdateOp, type UnwoundShape, type UpdateEnabled, type UpdateResult, type UpdaterResult, type ValidPaths, acc, createFieldAccessor, fn, mongoQuery };
1198
+ //# sourceMappingURL=index.d.mts.map