@prisma-next/mongo-query-builder 0.5.0-dev.9 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["result: Record<string, MongoAggExpr>","buckets: UpdateOpBuckets","spec: Record<string, 0>","#contract","#state","#withStage","fn","exprRecord: Record<string, MongoAggExpr>","contract: MongoContract","projection: Record<string, MongoProjectionValue>","projection","projection: Record<string, 1>","accumulators: Record<string, MongoAggAccumulator>","#writeTerminal","meta: PlanMeta","#writeMeta","matchFilters: MongoFilterExpr[]","sort: Record<string, 1 | -1> | undefined","updatePipeline: MongoUpdatePipelineStage[]","nodeArgs: Record<string, MongoAggExpr>","NUMERIC: NumericField","STRING: StringField","BOOLEAN: BooleanField","DATE: DateField","ARRAY: ArrayField","DOC: DocField","nodeArgs: Record<string, MongoAggExpr | ReadonlyArray<MongoAggExpr>>","#ctx","#modelName","#filters","#foldedFilter","meta: PlanMeta"],"sources":["../src/accumulator-helpers.ts","../src/update-ops.ts","../src/field-accessor.ts","../src/builder.ts","../src/expression-helpers.ts","../src/state-classes.ts","../src/query.ts"],"sourcesContent":["import type { MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';\nimport { MongoAggAccumulator, MongoAggLiteral } from '@prisma-next/mongo-query-ast/execution';\nimport type {\n ArrayField,\n DocField,\n NullableNumericField,\n NumericField,\n TypedAccumulatorExpr,\n TypedAggExpr,\n} from './types';\n\nfunction namedAccumulatorArgs(\n args: Readonly<Record<string, TypedAggExpr<DocField> | undefined>>,\n): Record<string, MongoAggExpr> {\n const result: Record<string, MongoAggExpr> = {};\n for (const [key, val] of Object.entries(args)) {\n if (val !== undefined) {\n result[key] = val.node;\n }\n }\n return result;\n}\n\nexport const acc = {\n sum<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<F> {\n return { _field: undefined as never, node: MongoAggAccumulator.sum(expr.node) };\n },\n\n avg(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.avg(expr.node) };\n },\n\n min<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.min(expr.node) };\n },\n\n max<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.max(expr.node) };\n },\n\n first<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.first(expr.node) };\n },\n\n last<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.last(expr.node) };\n },\n\n push(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField> {\n return { _field: undefined as never, node: MongoAggAccumulator.push(expr.node) };\n },\n\n addToSet(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField> {\n return { _field: undefined as never, node: MongoAggAccumulator.addToSet(expr.node) };\n },\n\n count(): TypedAccumulatorExpr<NumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.count() };\n },\n\n stdDevPop(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.stdDevPop(expr.node) };\n },\n\n stdDevSamp(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.stdDevSamp(expr.node) };\n },\n\n firstN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$firstN', namedAccumulatorArgs(args)),\n };\n },\n\n lastN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$lastN', namedAccumulatorArgs(args)),\n };\n },\n\n maxN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$maxN', namedAccumulatorArgs(args)),\n };\n },\n\n minN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$minN', namedAccumulatorArgs(args)),\n };\n },\n\n top(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n }): TypedAccumulatorExpr<DocField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$top', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n }),\n };\n },\n\n bottom(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n }): TypedAccumulatorExpr<DocField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$bottom', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n }),\n };\n },\n\n topN(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$topN', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n n: args.n.node,\n }),\n };\n },\n\n bottomN(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$bottomN', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n n: args.n.node,\n }),\n };\n },\n};\n","import type {\n MongoUpdatePipelineStage,\n MongoUpdateSpec,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\n\n/**\n * Per-field update operations produced by `Expression`'s update methods\n * (`set`, `inc`, `push`, …). A write terminal folds an array of these into a\n * `MongoUpdateSpec` record (`{ $set: { … }, $inc: { … }, … }`) before\n * constructing the underlying `UpdateManyCommand` / `UpdateOneCommand` AST node.\n *\n * One `TypedUpdateOp` value corresponds to one Mongo update operator applied\n * to one field path. The `op` string is the wire-level operator name (`$set`,\n * `$inc`, …); the `path` is the dot-path to the field (or its top-level name).\n */\nexport type TypedUpdateOp =\n | { readonly op: '$set'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$unset'; readonly path: string }\n | { readonly op: '$rename'; readonly path: string; readonly newName: string }\n | { readonly op: '$inc'; readonly path: string; readonly amount: number }\n | { readonly op: '$mul'; readonly path: string; readonly factor: number }\n | { readonly op: '$min'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$max'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$push'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$addToSet'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$pop'; readonly path: string; readonly direction: 1 | -1 }\n | { readonly op: '$pull'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$pullAll'; readonly path: string; readonly values: ReadonlyArray<MongoValue> }\n | { readonly op: '$currentDate'; readonly path: string }\n | { readonly op: '$setOnInsert'; readonly path: string; readonly value: MongoValue };\n\nexport const setOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$set',\n path,\n value,\n});\nexport const unsetOp = (path: string): TypedUpdateOp => ({ op: '$unset', path });\nexport const renameOp = (path: string, newName: string): TypedUpdateOp => ({\n op: '$rename',\n path,\n newName,\n});\nexport const incOp = (path: string, amount: number): TypedUpdateOp => ({\n op: '$inc',\n path,\n amount,\n});\nexport const mulOp = (path: string, factor: number): TypedUpdateOp => ({\n op: '$mul',\n path,\n factor,\n});\nexport const minOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$min',\n path,\n value,\n});\nexport const maxOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$max',\n path,\n value,\n});\nexport const pushOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$push',\n path,\n value,\n});\nexport const addToSetOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$addToSet',\n path,\n value,\n});\nexport const popOp = (path: string, direction: 1 | -1): TypedUpdateOp => ({\n op: '$pop',\n path,\n direction,\n});\nexport const pullOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$pull',\n path,\n value,\n});\nexport const pullAllOp = (path: string, values: ReadonlyArray<MongoValue>): TypedUpdateOp => ({\n op: '$pullAll',\n path,\n values,\n});\nexport const currentDateOp = (path: string): TypedUpdateOp => ({ op: '$currentDate', path });\nexport const setOnInsertOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$setOnInsert',\n path,\n value,\n});\n\n/**\n * Per-operator bucket: `{ '<fieldPath>': <operatorValue> }`. Every value is\n * already a `MongoValue` (operators store numbers/strings/booleans/arrays\n * directly), so no blind casts are needed at assignment sites.\n */\ntype UpdateOpBucket = Record<string, MongoValue>;\n\n/**\n * The full nested shape that `foldUpdateOps` accumulates before returning a\n * `MongoUpdateSpec`: `operator → fieldPath → value`. Each inner bucket is\n * itself a `MongoDocument`-compatible record, which is why the outer map is\n * structurally a `MongoUpdateSpec` (`Record<string, MongoValue>` where every\n * value is a document).\n */\ntype UpdateOpBuckets = Record<string, UpdateOpBucket>;\n\n/**\n * Fold an array of `TypedUpdateOp` into the non-pipeline variant of\n * `MongoUpdateSpec` (`{ $set: { … }, $inc: { … }, … }`).\n *\n * Throws if the same operator targets the same path twice — a clear authoring\n * error that Mongo would otherwise silently coalesce.\n */\nexport function foldUpdateOps(ops: ReadonlyArray<TypedUpdateOp>): MongoUpdateSpec {\n const buckets: UpdateOpBuckets = {};\n const seen = new Set<string>();\n\n const ensure = (key: string): UpdateOpBucket => {\n let bucket = buckets[key];\n if (!bucket) {\n bucket = {};\n buckets[key] = bucket;\n }\n return bucket;\n };\n\n const claim = (op: string, path: string): void => {\n const k = `${op}::${path}`;\n if (seen.has(k)) {\n throw new Error(\n `Update spec collision: ${op} on '${path}' was specified more than once. Combine the operations into a single call site.`,\n );\n }\n seen.add(k);\n };\n\n for (const entry of ops) {\n claim(entry.op, entry.path);\n switch (entry.op) {\n case '$set':\n case '$min':\n case '$max':\n case '$push':\n case '$addToSet':\n case '$pull':\n case '$setOnInsert':\n ensure(entry.op)[entry.path] = entry.value;\n break;\n case '$unset':\n ensure('$unset')[entry.path] = '';\n break;\n case '$rename':\n ensure('$rename')[entry.path] = entry.newName;\n break;\n case '$inc':\n ensure('$inc')[entry.path] = entry.amount;\n break;\n case '$mul':\n ensure('$mul')[entry.path] = entry.factor;\n break;\n case '$pop':\n ensure('$pop')[entry.path] = entry.direction;\n break;\n case '$pullAll':\n ensure('$pullAll')[entry.path] = entry.values;\n break;\n case '$currentDate':\n ensure('$currentDate')[entry.path] = true;\n break;\n }\n }\n\n return buckets;\n}\n\nexport type UpdaterItem = TypedUpdateOp | MongoUpdatePipelineStage;\n\n/**\n * The return type for updater callbacks. Typed as a union of homogeneous\n * arrays so mixed-shape updaters (operator + pipeline stage in the same\n * array) are a compile error. The runtime guard in `resolveUpdaterResult`\n * remains as defence-in-depth.\n */\nexport type UpdaterResult = ReadonlyArray<TypedUpdateOp> | ReadonlyArray<MongoUpdatePipelineStage>;\n\n/**\n * Classify an array of updater items and produce a `MongoUpdateSpec`.\n *\n * - All `TypedUpdateOp` → fold via `foldUpdateOps` (classic `{ $set, $inc, … }`)\n * - All `MongoUpdatePipelineStage` → return as-is (pipeline-style update)\n * - Mixed → throw (also a type error at the call site via the union shape)\n */\nexport function resolveUpdaterResult(items: ReadonlyArray<UpdaterItem>): MongoUpdateSpec {\n if (items.length === 0) {\n throw new Error(\n 'Updater returned no operations. Return at least one update from the callback (e.g. `[f.amount.set(0)]`).',\n );\n }\n\n const isOp = (item: UpdaterItem): item is TypedUpdateOp =>\n 'op' in item && typeof (item as TypedUpdateOp).op === 'string';\n\n const first = items[0];\n if (first === undefined) {\n throw new Error('Unreachable: items.length > 0 but first is undefined');\n }\n const firstIsOp = isOp(first);\n\n for (let i = 1; i < items.length; i++) {\n const item = items[i];\n if (item === undefined) continue;\n if (isOp(item) !== firstIsOp) {\n throw new Error(\n 'Cannot mix TypedUpdateOp values and pipeline stages in a single updater. ' +\n 'Use either `[f.amount.set(0)]` (operator form) or `[f.stage.set({...})]` (pipeline form), not both.',\n );\n }\n }\n\n if (firstIsOp) {\n return foldUpdateOps(items as ReadonlyArray<TypedUpdateOp>);\n }\n return items as ReadonlyArray<MongoUpdatePipelineStage>;\n}\n","import type {\n MongoAggExpr,\n MongoFilterExpr,\n MongoUpdatePipelineStage,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n MongoAddFieldsStage,\n MongoAggFieldRef,\n MongoExistsExpr,\n MongoFieldFilter,\n MongoProjectStage,\n MongoReplaceRootStage,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport type { NestedDocShape, ObjectField, ResolvePath, ValidPaths } from './resolve-path';\nimport type { DocField, DocShape, TypedAggExpr } from './types';\nimport type { TypedUpdateOp } from './update-ops';\nimport {\n addToSetOp,\n currentDateOp,\n incOp,\n maxOp,\n minOp,\n mulOp,\n popOp,\n pullAllOp,\n pullOp,\n pushOp,\n renameOp,\n setOnInsertOp,\n setOp,\n unsetOp,\n} from './update-ops';\n\n/**\n * Operator surface for leaf (scalar) paths — today's full set: filter,\n * update, and aggregation operators. Returned by `Expression<F>` for any\n * `F extends DocField` that is not an `ObjectField<…>` sub-tree.\n *\n * Operator surfaces are intentionally not trait-gated by codec in this\n * revision — tracked on Linear as TML-2259 (scope extended to cover the\n * query-builder's `Expression<F>`). Calling, e.g. `.inc(1)` on a\n * string-typed expression compiles; the runtime relies on Mongo to\n * surface the error. Trait-gating can be tightened in a follow-up\n * without changing the accessor's public shape.\n */\nexport interface LeafExpression<F extends DocField> extends TypedAggExpr<F> {\n readonly _path: string;\n\n // Filter operators\n eq(value: MongoValue): MongoFilterExpr;\n ne(value: MongoValue): MongoFilterExpr;\n gt(value: MongoValue): MongoFilterExpr;\n gte(value: MongoValue): MongoFilterExpr;\n lt(value: MongoValue): MongoFilterExpr;\n lte(value: MongoValue): MongoFilterExpr;\n in(values: ReadonlyArray<MongoValue>): MongoFilterExpr;\n nin(values: ReadonlyArray<MongoValue>): MongoFilterExpr;\n exists(flag?: boolean): MongoFilterExpr;\n\n // Update operators ($set family)\n set(value: MongoValue): TypedUpdateOp;\n unset(): TypedUpdateOp;\n rename(newName: string): TypedUpdateOp;\n\n // Numeric update operators\n inc(amount: number): TypedUpdateOp;\n mul(factor: number): TypedUpdateOp;\n min(value: MongoValue): TypedUpdateOp;\n max(value: MongoValue): TypedUpdateOp;\n\n // Array update operators\n push(value: MongoValue): TypedUpdateOp;\n addToSet(value: MongoValue): TypedUpdateOp;\n pop(direction?: 1 | -1): TypedUpdateOp;\n pull(value: MongoValue): TypedUpdateOp;\n pullAll(values: ReadonlyArray<MongoValue>): TypedUpdateOp;\n\n // Date / upsert helpers\n currentDate(): TypedUpdateOp;\n setOnInsert(value: MongoValue): TypedUpdateOp;\n}\n\n/**\n * Operator surface for non-leaf (value-object) paths — `f('address')`\n * when `address` is a `ContractValueObject`. Intentionally minimal: the\n * whole-value ops that make sense on a structured sub-document\n * (`set`/`unset`/`exists`, null presence via `eq(null)`/`ne(null)`). Field-\n * level ops belong on the constituent leaves (`f('address.city')`).\n *\n * The aggregation `node` is still present (`TypedAggExpr<ObjectField<N>>`)\n * so the value object can be piped through `$addFields` /\n * `$replaceRoot` / etc. as-is.\n */\nexport interface ObjectExpression<N extends NestedDocShape> extends TypedAggExpr<ObjectField<N>> {\n readonly _path: string;\n\n exists(flag?: boolean): MongoFilterExpr;\n eq(value: null): MongoFilterExpr;\n ne(value: null): MongoFilterExpr;\n\n set(value: MongoValue): TypedUpdateOp;\n unset(): TypedUpdateOp;\n}\n\n/**\n * The unified field accessor expression returned by `FieldAccessor` (per\n * [ADR 180](../../../../docs/architecture%20docs/adrs/ADR%20180%20-%20Dot-path%20field%20accessor.md)).\n *\n * Resolves to `ObjectExpression<Sub>` when `F` is an `ObjectField<Sub>`\n * (non-leaf path), otherwise to `LeafExpression<F>` (the full operator\n * surface). The conditional is driven off the `fields` marker that\n * `ObjectField` adds to `DocField`, so existing code that uses plain\n * `DocField` shapes continues to resolve to `LeafExpression`.\n */\nexport type Expression<F extends DocField> =\n F extends ObjectField<infer N> ? ObjectExpression<N> : LeafExpression<F>;\n\n/**\n * Emitters for MongoDB update-pipeline stages (`$addFields`/`$set`,\n * `$project`/`$unset`, `$replaceRoot`/`$replaceWith`). These return\n * `MongoUpdatePipelineStage` nodes and let an updater callback express\n * the pipeline-form update as an alternative to the typed-operator form.\n *\n * The two forms are mutually exclusive per updater call: `resolveUpdaterResult`\n * rejects arrays that mix `TypedUpdateOp` and `MongoUpdatePipelineStage`\n * entries with a clear error — an updater callback must return either all\n * typed ops or all pipeline stages. Pick the form that matches the update\n * you want and commit to it for that call site.\n *\n * Accessible via `f.stage` on the `FieldAccessor`.\n */\nexport interface StageEmitters {\n set(fields: Record<string, MongoAggExpr>): MongoUpdatePipelineStage;\n unset(...paths: ReadonlyArray<string>): MongoUpdatePipelineStage;\n replaceRoot(newRoot: MongoAggExpr): MongoUpdatePipelineStage;\n replaceWith(newRoot: MongoAggExpr): MongoUpdatePipelineStage;\n}\n\nfunction buildStageEmitters(): StageEmitters {\n return {\n set: (fields) => new MongoAddFieldsStage(fields),\n unset: (...paths) => {\n const spec: Record<string, 0> = {};\n for (const p of paths) {\n spec[p] = 0;\n }\n return new MongoProjectStage(spec);\n },\n replaceRoot: (newRoot) => new MongoReplaceRootStage(newRoot),\n replaceWith: (newRoot) => new MongoReplaceRootStage(newRoot),\n };\n}\n\n/**\n * The unified `FieldAccessor` per ADR 180.\n *\n * - Property access (`f.status`) returns an `Expression<F>` whose codec\n * comes from the current pipeline shape `S`.\n * - Callable form (`f('address.city')`) returns an `Expression<ResolvePath<N, P>>`\n * where `N` is the nested shape carrying value-object sub-shapes.\n * Paths that don't exist in `N` are rejected with a compile-time error\n * (via `P extends ValidPaths<N>`). Non-leaf paths like `f('address')`\n * resolve to an `ObjectExpression` whose reduced surface covers the\n * whole-value operations (`set`, `unset`, `exists`, `eq(null)`,\n * `ne(null)`).\n * - `f.rawPath('path')` is a deliberate escape hatch that skips path\n * validation and returns a `LeafExpression<F>` for the given string.\n * Intended for migration authoring where the target field is not yet\n * part of the typed contract (e.g. a backfill writing a newly-added\n * column before the contract hash rolls forward). The method name is\n * deliberately `rawPath` rather than `raw` so it does not shadow a\n * legitimate top-level `raw` field on a user model.\n * - `f.stage` exposes pipeline-style update emitters (`$set`, `$unset`,\n * `$replaceRoot`, `$replaceWith`).\n *\n * When `N` is `Record<string, never>` (the default — e.g. after a\n * replacement stage like `$group` / `$project` / `$replaceRoot`),\n * `ValidPaths<N>` is `never` and the callable form is effectively\n * disabled at the type level. This keeps the builder sound downstream of\n * stages that invalidate the original document's nested-path tree.\n * `f.rawPath(...)` remains available in that state for callers that need\n * an explicit unvalidated path.\n */\nexport type FieldAccessor<S extends DocShape, N extends NestedDocShape = Record<string, never>> = {\n readonly [K in keyof S & string]: Expression<S[K]>;\n} & (<P extends ValidPaths<N>>(path: P) => Expression<ResolvePath<N, P>>) & {\n readonly stage: StageEmitters;\n /**\n * Escape hatch: build a `LeafExpression<F>` for an unvalidated string\n * path. Use only when the path is intentionally outside the typed\n * model surface — data-migration authoring is the canonical case\n * (e.g. backfilling a field that is not yet in the contract). Default\n * `F` is the opaque `DocField`; callers can narrow via the explicit\n * generic: `f.rawPath<StringField>(\"status\").set(\"active\")`.\n *\n * The method is named `rawPath` (not `raw`) so a user model with a\n * top-level `raw` field still resolves `f.raw` to the field-expression\n * property, not to this escape hatch. Does not participate in\n * `ValidPaths<N>` / `ResolvePath<N, P>` — the path is passed through\n * verbatim and no IDE autocomplete is offered.\n */\n rawPath<F extends DocField = DocField>(path: string): LeafExpression<F>;\n };\n\nfunction buildExpression<F extends DocField>(path: string): Expression<F> {\n // The runtime object carries the full operator surface unconditionally;\n // `ObjectExpression` is a strict subset of `LeafExpression`, so a single\n // implementation satisfies both type-level shapes. Compile-time gating\n // prevents misuse of leaf-only operators on object paths.\n return {\n _field: undefined as never,\n _path: path,\n node: MongoAggFieldRef.of(path),\n\n eq: (value: MongoValue) => MongoFieldFilter.eq(path, value),\n ne: (value: MongoValue) => MongoFieldFilter.neq(path, value),\n gt: (value: MongoValue) => MongoFieldFilter.gt(path, value),\n gte: (value: MongoValue) => MongoFieldFilter.gte(path, value),\n lt: (value: MongoValue) => MongoFieldFilter.lt(path, value),\n lte: (value: MongoValue) => MongoFieldFilter.lte(path, value),\n in: (values: ReadonlyArray<MongoValue>) => MongoFieldFilter.in(path, values),\n nin: (values: ReadonlyArray<MongoValue>) => MongoFieldFilter.nin(path, values),\n exists: (flag?: boolean) =>\n flag === false ? MongoExistsExpr.notExists(path) : MongoExistsExpr.exists(path),\n\n set: (value: MongoValue) => setOp(path, value),\n unset: () => unsetOp(path),\n rename: (newName: string) => renameOp(path, newName),\n\n inc: (amount: number) => incOp(path, amount),\n mul: (factor: number) => mulOp(path, factor),\n min: (value: MongoValue) => minOp(path, value),\n max: (value: MongoValue) => maxOp(path, value),\n\n push: (value: MongoValue) => pushOp(path, value),\n addToSet: (value: MongoValue) => addToSetOp(path, value),\n pop: (direction: 1 | -1 = 1) => popOp(path, direction),\n pull: (value: MongoValue) => pullOp(path, value),\n pullAll: (values: ReadonlyArray<MongoValue>) => pullAllOp(path, values),\n\n currentDate: () => currentDateOp(path),\n setOnInsert: (value: MongoValue) => setOnInsertOp(path, value),\n } as unknown as Expression<F>;\n}\n\n/**\n * Construct a unified `FieldAccessor<S, N>` proxy. Property access creates\n * an `Expression` using the property name as the field path; callable\n * form accepts a dot-path string validated against `N` at compile time.\n *\n * The proxy target is a function so the resulting object is both callable\n * and indexable. Symbol-keyed accesses (e.g. `Symbol.toPrimitive`) return\n * `undefined` to keep accidental coercion behaviour unsurprising —\n * matching the previous `FieldProxy` / `FilterProxy` semantics.\n */\nexport function createFieldAccessor<\n S extends DocShape,\n N extends NestedDocShape = Record<string, never>,\n>(): FieldAccessor<S, N> {\n const stageInstance = buildStageEmitters();\n const callable = ((path: string) => buildExpression<DocField>(path)) as unknown as FieldAccessor<\n S,\n N\n >;\n return new Proxy(callable, {\n get(target, prop, receiver) {\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n if (prop === 'stage') {\n return stageInstance;\n }\n if (prop === 'rawPath') {\n return (path: string) => buildExpression<DocField>(path);\n }\n return buildExpression(prop);\n },\n });\n}\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n ExtractMongoCodecTypes,\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type {\n MongoAggAccumulator,\n MongoAggExpr,\n MongoDensifyRange,\n MongoFillOutput,\n MongoFilterExpr,\n MongoPipelineStage,\n MongoProjectionValue,\n MongoQueryPlan,\n MongoUpdatePipelineStage,\n MongoWindowField,\n UpdateResult,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n AggregateCommand,\n FindOneAndDeleteCommand,\n FindOneAndUpdateCommand,\n MongoAddFieldsStage,\n MongoAndExpr,\n MongoBucketAutoStage,\n MongoBucketStage,\n MongoCountStage,\n MongoDensifyStage,\n MongoFacetStage,\n MongoFillStage,\n MongoGeoNearStage,\n MongoGraphLookupStage,\n MongoGroupStage,\n MongoLimitStage,\n MongoLookupStage,\n MongoMatchStage,\n MongoMergeStage,\n MongoOutStage,\n MongoProjectStage,\n MongoRedactStage,\n MongoReplaceRootStage,\n MongoSampleStage,\n MongoSearchMetaStage,\n MongoSearchStage,\n MongoSetWindowFieldsStage,\n MongoSkipStage,\n MongoSortByCountStage,\n MongoSortStage,\n MongoUnionWithStage,\n MongoUnwindStage,\n MongoVectorSearchStage,\n UpdateManyCommand,\n UpdateOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport { createFieldAccessor, type Expression, type FieldAccessor } from './field-accessor';\nimport type { FindAndModifyEnabled, LeadingMatch, UpdateEnabled } from './markers';\nimport type { NestedDocShape } from './resolve-path';\nimport type {\n DocField,\n DocShape,\n ExtractDocShape,\n GroupedDocShape,\n GroupSpec,\n ProjectedShape,\n ResolveRow,\n SortSpec,\n TypedAggExpr,\n UnwoundShape,\n} from './types';\nimport { resolveUpdaterResult, type UpdaterResult } from './update-ops';\n\ninterface PipelineChainState {\n readonly collection: string;\n readonly stages: ReadonlyArray<MongoPipelineStage>;\n readonly storageHash: string;\n}\n\n/**\n * The pipeline state in the query-builder state machine.\n *\n * Reached from `CollectionHandle` or `FilteredCollection` after the first\n * pipeline-stage method call (or directly via `aggregate()` shortcuts). Holds\n * the accumulated `MongoPipelineStage[]` and exposes pipeline-stage methods,\n * the `merge`/`out` write terminals, and the `build`/`aggregate` read\n * terminals.\n *\n * Two phantom type parameters gate the conditional terminals:\n *\n * - `U extends UpdateEnabled` — when `'update-ok'`, the no-arg `updateMany()` /\n * `updateOne()` form is available (consume the chain as an\n * update-with-pipeline spec). Cleared by stages that produce content the\n * `update` AST cannot represent (e.g. `$group`, `$lookup`, `$limit`).\n * - `F extends FindAndModifyEnabled` — when `'fam-ok'`, the\n * `findOneAndUpdate(...)` / `findOneAndDelete(...)` terminals are\n * available. Cleared by stages incompatible with their wire-command slots\n * (`$limit`, `$group`, mutating stages, …).\n *\n * The marker semantics are encoded in the per-method return types — see the\n * marker table (and rationale per row) in\n * `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.\n */\nexport class PipelineChain<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n Shape extends DocShape,\n U extends UpdateEnabled = 'update-ok',\n F extends FindAndModifyEnabled = 'fam-ok',\n L extends LeadingMatch = 'leading',\n N extends NestedDocShape = Record<string, never>,\n> {\n declare readonly __updateCompat: U;\n declare readonly __findAndModifyCompat: F;\n declare readonly __leadingMatch: L;\n\n readonly #contract: TContract;\n readonly #state: PipelineChainState;\n\n constructor(contract: TContract, state: PipelineChainState) {\n this.#contract = contract;\n this.#state = state;\n }\n\n /**\n * Internal helper that appends a pipeline stage and branches into a new\n * state-type. The fifth type parameter `NewN` carries the nested-path\n * shape forward. It defaults to `Record<string, never>` so stages that\n * fundamentally rewrite the document (`$group`, `$project`,\n * `$replaceRoot`, …) automatically disable the callable form of\n * `FieldAccessor` downstream. Additive stages (`match`, `addFields`,\n * `sort`, `lookup`, …) explicitly re-thread the current `N`.\n */\n #withStage<\n NewShape extends DocShape,\n NewU extends UpdateEnabled,\n NewF extends FindAndModifyEnabled,\n NewL extends LeadingMatch = 'past-leading',\n NewN extends NestedDocShape = Record<string, never>,\n >(stage: MongoPipelineStage): PipelineChain<TContract, NewShape, NewU, NewF, NewL, NewN> {\n return new PipelineChain<TContract, NewShape, NewU, NewF, NewL, NewN>(this.#contract, {\n ...this.#state,\n stages: [...this.#state.stages, stage],\n });\n }\n\n #writeMeta(): PlanMeta {\n return {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n }\n\n // --- Identity stages ---\n\n /**\n * `$match`. `FindAndModifyEnabled` is always preserved. `UpdateEnabled` is\n * preserved only while the chain is still in the leading-`$match` prefix\n * (`L = 'leading'`); a `$match` that follows any non-`$match` stage\n * transitions to `L = 'past-leading'` and clears `UpdateEnabled`, since\n * `deconstructUpdateChain` can only peel leading `$match` stages into the\n * wire-command filter.\n */\n match(\n filter: MongoFilterExpr,\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;\n match(\n fn: (fields: FieldAccessor<Shape, N>) => MongoFilterExpr,\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;\n match(\n filterOrFn: MongoFilterExpr | ((fields: FieldAccessor<Shape, N>) => MongoFilterExpr),\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N> {\n const filter =\n typeof filterOrFn === 'function' ? filterOrFn(createFieldAccessor<Shape, N>()) : filterOrFn;\n return this.#withStage<Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>(\n new MongoMatchStage(filter),\n );\n }\n\n /**\n * `$sort`. Clears `UpdateEnabled` (`update` has no per-document sort) but\n * preserves `FindAndModifyEnabled` (`findAndModify` has a `sort` slot).\n */\n sort(\n spec: SortSpec<Shape>,\n ): PipelineChain<TContract, Shape, 'update-cleared', F, 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', F, 'past-leading', N>(\n new MongoSortStage(spec as Record<string, 1 | -1>),\n );\n }\n\n /**\n * `$limit`. Clears both markers — `limit` is incompatible with the `update`\n * wire command, and `findAndModify` already implies single-document\n * semantics (so `.limit(...)` adds no meaning, only ambiguity).\n */\n limit(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoLimitStage(n),\n );\n }\n\n /**\n * `$skip`. Clears both markers — MongoDB's `findAndModify` wire command\n * has no `skip` slot, so `deconstructFindAndModifyChain` rejects any\n * `$skip` at runtime; keeping the marker `fam-cleared` makes the type\n * system reflect the same constraint (see ADR 201 marker table).\n */\n skip(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSkipStage(n),\n );\n }\n\n sample(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSampleStage(n),\n );\n }\n\n // --- Additive stages ---\n\n /**\n * `$addFields`. Preserves `UpdateEnabled` (representable as\n * update-with-pipeline `$set`); clears `FindAndModifyEnabled` (no analogue\n * in the find-and-modify wire commands). The nested-path shape `N` is\n * preserved — newly added flat fields are reachable via property access\n * (`f.newField`) but do not themselves carry nested structure.\n */\n addFields<NewFields extends Record<string, TypedAggExpr<DocField>>>(\n fn: (fields: FieldAccessor<Shape, N>) => NewFields,\n ): PipelineChain<\n TContract,\n Shape & ExtractDocShape<NewFields>,\n U,\n 'fam-cleared',\n 'past-leading',\n N\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const newFields = fn(accessor);\n const exprRecord: Record<string, MongoAggExpr> = {};\n for (const [key, typed] of Object.entries(newFields)) {\n exprRecord[key] = typed.node;\n }\n return this.#withStage<Shape & ExtractDocShape<NewFields>, U, 'fam-cleared', 'past-leading', N>(\n new MongoAddFieldsStage(exprRecord),\n );\n }\n\n /**\n * `$lookup`. Clears both markers — joins are not representable in either\n * the `update` or `findAndModify` wire commands. The original document's\n * nested-path shape `N` is preserved (the lookup adds a sidecar array\n * field; existing keys are untouched).\n */\n lookup<ForeignRoot extends keyof TContract['roots'] & string, As extends string>(options: {\n from: ForeignRoot;\n localField: keyof Shape & string;\n foreignField: string;\n as: As;\n }): PipelineChain<\n TContract,\n Shape & Record<As, { readonly codecId: 'mongo/array@1'; readonly nullable: false }>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n > {\n const contract: MongoContract = this.#contract;\n const modelName = contract.roots[options.from];\n if (!modelName) {\n const validRoots = Object.keys(contract.roots).join(', ');\n throw new Error(`lookup() unknown root: \"${options.from}\". Valid roots: ${validRoots}`);\n }\n const model = contract.models[modelName];\n const collectionName = model?.storage?.collection ?? options.from;\n return this.#withStage<\n Shape & Record<As, { readonly codecId: 'mongo/array@1'; readonly nullable: false }>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n >(\n new MongoLookupStage({\n from: collectionName,\n localField: options.localField,\n foreignField: options.foreignField,\n as: options.as,\n }),\n );\n }\n\n // --- Narrowing stages ---\n\n /**\n * `$project`. Preserves `UpdateEnabled` (representable as update-with-pipeline\n * `$project` / `$unset`); clears `FindAndModifyEnabled` (use `.project()` on\n * the result of `.build()` if both projection and find-and-modify are\n * needed — see spec).\n *\n * Resets the nested-path shape to `Record<string, never>` — projection\n * fundamentally rewrites the document, so dot-paths into the *source*\n * document are no longer meaningful downstream.\n */\n project<K extends keyof Shape & string>(\n ...keys: K[]\n ): PipelineChain<\n TContract,\n Pick<Shape, K | ('_id' extends keyof Shape ? '_id' : never)>,\n U,\n 'fam-cleared',\n 'past-leading'\n >;\n project<Spec extends Record<string, 1 | TypedAggExpr<DocField>>>(\n fn: (fields: FieldAccessor<Shape, N>) => Spec,\n ): PipelineChain<TContract, ProjectedShape<Shape, Spec>, U, 'fam-cleared', 'past-leading'>;\n project(\n ...args: unknown[]\n ): PipelineChain<TContract, DocShape, U, 'fam-cleared', 'past-leading'> {\n if (args.length === 1 && typeof args[0] === 'function') {\n const fn = args[0] as (\n fields: FieldAccessor<Shape, N>,\n ) => Record<string, 1 | TypedAggExpr<DocField>>;\n const accessor = createFieldAccessor<Shape, N>();\n const spec = fn(accessor);\n const projection: Record<string, MongoProjectionValue> = {};\n for (const [key, val] of Object.entries(spec)) {\n projection[key] = val === 1 ? 1 : (val as TypedAggExpr<DocField>).node;\n }\n return this.#withStage(new MongoProjectStage(projection));\n }\n const keys = args as string[];\n const projection: Record<string, 1> = {};\n for (const key of keys) {\n projection[key] = 1;\n }\n return this.#withStage(new MongoProjectStage(projection));\n }\n\n /**\n * `$unwind`. Clears both markers — array unrolling produces multiple output\n * documents per input, incompatible with both single-document update and\n * find-and-modify wire commands. The original `N` is preserved: unwind\n * replaces the unwound array slot with its element but leaves the rest\n * of the document structurally intact.\n */\n unwind<K extends keyof Shape & string>(\n field: K,\n options?: { preserveNullAndEmptyArrays?: boolean },\n ): PipelineChain<\n TContract,\n UnwoundShape<Shape, K>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n > {\n return this.#withStage<\n UnwoundShape<Shape, K>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n >(new MongoUnwindStage(`$${field}`, options?.preserveNullAndEmptyArrays ?? false));\n }\n\n // --- Replacement stages ---\n\n /**\n * `$group`. Clears both markers — group output bears no relation to source\n * documents; neither `update` nor `findAndModify` can consume it. Nested\n * path shape is reset (the source document's path tree is gone).\n */\n group<Spec extends GroupSpec>(\n fn: (fields: FieldAccessor<Shape, N>) => Spec,\n ): PipelineChain<\n TContract,\n GroupedDocShape<Spec>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const spec = fn(accessor);\n const { _id: groupIdExpr, ...rest } = spec;\n const groupId = groupIdExpr === null ? null : groupIdExpr.node;\n const accumulators: Record<string, MongoAggAccumulator> = {};\n for (const [key, typed] of Object.entries(rest)) {\n if (typed === null) {\n throw new Error(`group() field \"${key}\" must not be null. Only _id can be null.`);\n }\n if (typed.node.kind !== 'accumulator') {\n throw new Error(\n `group() field \"${key}\" must use an accumulator (e.g. acc.sum(), acc.count()). Got \"${typed.node.kind}\" expression.`,\n );\n }\n accumulators[key] = typed.node as MongoAggAccumulator;\n }\n return this.#withStage<GroupedDocShape<Spec>, 'update-cleared', 'fam-cleared'>(\n new MongoGroupStage(groupId, accumulators),\n );\n }\n\n /**\n * `$replaceRoot`. Preserves `UpdateEnabled` (representable as\n * update-with-pipeline `$replaceRoot`); clears `FindAndModifyEnabled`.\n * Nested path shape is reset — the replaced root has no relation to\n * the original document structure.\n */\n replaceRoot<NewShape extends DocShape>(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>,\n ): PipelineChain<TContract, NewShape, U, 'fam-cleared', 'past-leading'> {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage<NewShape, U, 'fam-cleared'>(new MongoReplaceRootStage(expr.node));\n }\n\n count<Field extends string>(\n field: Field,\n ): PipelineChain<\n TContract,\n Record<Field, { readonly codecId: 'mongo/double@1'; readonly nullable: false }>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n return this.#withStage(new MongoCountStage(field));\n }\n\n sortByCount<F2 extends DocField>(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<F2> | TypedAggExpr<F2>,\n ): PipelineChain<\n TContract,\n {\n _id: F2;\n count: { readonly codecId: 'mongo/double@1'; readonly nullable: false };\n },\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage(new MongoSortByCountStage(expr.node));\n }\n\n // --- Filter stages ---\n\n /**\n * `$redact`. Preserves `UpdateEnabled`; clears `FindAndModifyEnabled`.\n * Shape- and nested-path-preserving (the document tree is unchanged).\n */\n redact(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>,\n ): PipelineChain<TContract, Shape, U, 'fam-cleared', 'past-leading', N> {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage<Shape, U, 'fam-cleared', 'past-leading', N>(\n new MongoRedactStage(expr.node),\n );\n }\n\n // --- Write terminals (output stages) ---\n\n /**\n * `$out` write terminal. Materialises the pipeline output into\n * `collection` (optionally in `db`), replacing any prior contents. Unlike\n * the other pipeline-stage methods, this **terminates** the chain — it\n * returns a `MongoQueryPlan` rather than another `PipelineChain`, since\n * `$out` must be the final stage and there is nothing further to chain.\n *\n * Lane is `mongo-query` (matching all other terminals in this package) so\n * middleware can dispatch on intent without inspecting the command.\n *\n * The result row stream is empty (`unknown` row type) — the data lives\n * in the destination collection, not the response.\n */\n out(collection: string, db?: string): MongoQueryPlan<unknown, AggregateCommand> {\n return this.#writeTerminal(new MongoOutStage(collection, db));\n }\n\n /**\n * `$merge` write terminal. Streams the pipeline output into the target\n * collection per the supplied merge semantics (`whenMatched` /\n * `whenNotMatched`). Like `out()`, terminates the chain — `$merge` must\n * be the final stage.\n */\n merge(options: {\n into: string | { db: string; coll: string };\n on?: string | ReadonlyArray<string>;\n whenMatched?: string | ReadonlyArray<MongoUpdatePipelineStage>;\n whenNotMatched?: string;\n }): MongoQueryPlan<unknown, AggregateCommand> {\n return this.#writeTerminal(new MongoMergeStage(options));\n }\n\n #writeTerminal(stage: MongoPipelineStage): MongoQueryPlan<unknown, AggregateCommand> {\n const pipeline = [...this.#state.stages, stage];\n const command = new AggregateCommand(this.#state.collection, pipeline);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n // --- Union stages ---\n\n unionWith(\n collection: string,\n pipeline?: ReadonlyArray<MongoPipelineStage>,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoUnionWithStage(collection, pipeline),\n );\n }\n\n // --- Bucketing stages ---\n\n bucket(options: {\n groupBy: MongoAggExpr;\n boundaries: ReadonlyArray<unknown>;\n default_?: unknown;\n output?: Record<string, MongoAggAccumulator>;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoBucketStage(options),\n );\n }\n\n bucketAuto(options: {\n groupBy: MongoAggExpr;\n buckets: number;\n output?: Record<string, MongoAggAccumulator>;\n granularity?: string;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoBucketAutoStage(options),\n );\n }\n\n // --- Geo stages ---\n\n geoNear(options: {\n near: unknown;\n distanceField: string;\n spherical?: boolean;\n maxDistance?: number;\n minDistance?: number;\n query?: MongoFilterExpr;\n key?: string;\n distanceMultiplier?: number;\n includeLocs?: string;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoGeoNearStage(options),\n );\n }\n\n // --- Multi-facet stages ---\n\n facet(\n facets: Record<string, ReadonlyArray<MongoPipelineStage>>,\n ): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(new MongoFacetStage(facets));\n }\n\n // --- Graph stages ---\n\n graphLookup(options: {\n from: string;\n startWith: MongoAggExpr;\n connectFromField: string;\n connectToField: string;\n as: string;\n maxDepth?: number;\n depthField?: string;\n restrictSearchWithMatch?: MongoFilterExpr;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoGraphLookupStage(options),\n );\n }\n\n // --- Window stages ---\n\n setWindowFields(options: {\n partitionBy?: MongoAggExpr;\n sortBy?: Record<string, 1 | -1>;\n output: Record<string, MongoWindowField>;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoSetWindowFieldsStage(options),\n );\n }\n\n densify(options: {\n field: string;\n partitionByFields?: ReadonlyArray<string>;\n range: MongoDensifyRange;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoDensifyStage(options),\n );\n }\n\n fill(options: {\n partitionBy?: MongoAggExpr;\n partitionByFields?: ReadonlyArray<string>;\n sortBy?: Record<string, 1 | -1>;\n output: Record<string, MongoFillOutput>;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoFillStage(options),\n );\n }\n\n // --- Search stages ---\n\n search(\n config: Record<string, unknown>,\n index?: string,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSearchStage(config, index),\n );\n }\n\n searchMeta(\n config: Record<string, unknown>,\n index?: string,\n ): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoSearchMetaStage(config, index),\n );\n }\n\n vectorSearch(options: {\n index: string;\n path: string;\n queryVector: ReadonlyArray<number>;\n numCandidates: number;\n limit: number;\n filter?: Record<string, unknown>;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoVectorSearchStage(options),\n );\n }\n\n // --- Escape hatch ---\n\n pipe(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading'>;\n pipe<NewShape extends DocShape>(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'>;\n pipe<NewShape extends DocShape = Shape>(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<NewShape, 'update-cleared', 'fam-cleared'>(stage);\n }\n\n // --- Pipeline-style write terminals (UpdateEnabled-gated) ---\n\n /**\n * No-arg `updateMany()`: deconstruct the chain into leading `$match`\n * stages (folded into the filter) and remaining stages (which must all\n * be valid pipeline-update stages). Available only when `U = 'update-ok'`.\n *\n * The optional callback parameter exists for subclass-override\n * compatibility with `FilteredCollection.updateMany(updaterFn)` — TS's\n * strict override check requires the parent's parameter to accept at\n * least what the child's signature does. A runtime guard throws if a\n * callback is actually passed on a bare `PipelineChain`. Note that\n * because nothing in the public surface transitions `U` from\n * `'update-cleared'` (the initial state on `CollectionHandle` /\n * `FilteredCollection`) back to `'update-ok'`, the no-arg form is\n * reachable only via explicit type casts in internal tests — the\n * callback-form \"type hole\" is therefore not reachable from user\n * code. See `docs/architecture docs/adrs/ADR 201 - State-machine\n * pattern for typed DSL builders.md` for the marker-transition table.\n */\n updateMany(\n this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>,\n updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n if (updaterFn !== undefined) {\n throw new Error(\n 'updateMany() on a PipelineChain expects no arguments — the chain itself is the update pipeline. ' +\n 'To update with an operator callback, call .updateMany(fn) on a FilteredCollection (i.e. after .match()).',\n );\n }\n const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);\n const command = new UpdateManyCommand(this.#state.collection, filter, updatePipeline);\n return { collection: this.#state.collection, command, meta: this.#writeMeta() };\n }\n\n /**\n * No-arg `updateOne()`: same as `updateMany()` but maps to a single-doc\n * update. Carries the same optional-callback/subclass-compat caveat\n * documented above — the callback form is reachable only via forced\n * casts in internal tests.\n */\n updateOne(\n this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>,\n updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n if (updaterFn !== undefined) {\n throw new Error(\n 'updateOne() on a PipelineChain expects no arguments — the chain itself is the update pipeline. ' +\n 'To update with an operator callback, call .updateOne(fn) on a FilteredCollection (i.e. after .match()).',\n );\n }\n const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);\n const command = new UpdateOneCommand(this.#state.collection, filter, updatePipeline);\n return { collection: this.#state.collection, command, meta: this.#writeMeta() };\n }\n\n // --- Find-and-modify terminals (marker-gated) ---\n\n /**\n * Find a single document matching the accumulated pipeline (which must\n * consist solely of leading `$match` stages followed by at most one\n * `$sort`) and apply `updaterFn`. Available only when\n * `FindAndModifyEnabled` is `'fam-ok'` — stages that clear the marker\n * (including `$skip`, which MongoDB's `findAndModify` has no slot for)\n * make this method invisible at the type level.\n *\n * The pipeline stages are deconstructed into the wire command's `filter`\n * and `sort` slots. If any non-deconstructable stage is present, a\n * runtime error is thrown as a defensive check (the type system should\n * prevent this).\n */\n findOneAndUpdate(\n this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>,\n updaterFn: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n opts: { readonly upsert?: boolean; readonly returnDocument?: 'before' | 'after' } = {},\n ): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>> | null,\n FindOneAndUpdateCommand\n > {\n const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);\n const accessor = createFieldAccessor<Shape, N>();\n const items = updaterFn(accessor);\n const update = resolveUpdaterResult(items);\n const command = new FindOneAndUpdateCommand(\n this.#state.collection,\n filter,\n update,\n opts.upsert ?? false,\n sort,\n opts.returnDocument ?? 'after',\n );\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n /**\n * Find a single document matching the accumulated pipeline and delete it.\n * Same marker gating and deconstruction as `findOneAndUpdate`.\n */\n findOneAndDelete(\n this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>,\n ): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>> | null,\n FindOneAndDeleteCommand\n > {\n const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);\n const command = new FindOneAndDeleteCommand(this.#state.collection, filter, sort);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n // --- Read terminals ---\n\n /**\n * Materialise the chain as a `MongoQueryPlan` wrapping an `AggregateCommand`.\n */\n build(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>>, AggregateCommand> {\n const command = new AggregateCommand(this.#state.collection, this.#state.stages);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n /**\n * Alias for `build()` — surfaces the read intent at the call site.\n */\n aggregate(): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>>,\n AggregateCommand\n > {\n return this.build();\n }\n}\n\ninterface DeconstructedFindAndModify {\n filter: MongoFilterExpr;\n sort: Record<string, 1 | -1> | undefined;\n}\n\n/**\n * Walk the accumulated pipeline stages and extract the `filter` and `sort`\n * slots for a `findOneAndUpdate` / `findOneAndDelete` wire command.\n *\n * The helper accepts exactly the canonical shape `match+ -> sort?` and\n * nothing else:\n *\n * - one or more `$match` stages (AND-folded into a single filter),\n * - optionally followed by a single `$sort` stage.\n *\n * Anything else — a `$sort` before `$match`, multiple `$sort` stages, a\n * `$skip` stage, or any non-`$match`/`$sort` stage — is rejected with a\n * clear error. The type system already prevents most of these at compile\n * time via the `FindAndModifyEnabled` marker, but the runtime check\n * guards the escape hatches (e.g. `.pipe(...)`) and future marker gaps.\n *\n * `$skip` is rejected outright because MongoDB's `findAndModify` command\n * has no skip slot; a silently-dropped skip is a latent correctness bug\n * waiting to happen. (A02 removed skip from the typed AST for the same\n * reason.)\n */\nfunction deconstructFindAndModifyChain(\n stages: ReadonlyArray<MongoPipelineStage>,\n): DeconstructedFindAndModify {\n const matchFilters: MongoFilterExpr[] = [];\n let sort: Record<string, 1 | -1> | undefined;\n let seenNonMatch = false;\n\n for (const stage of stages) {\n if (stage instanceof MongoMatchStage) {\n if (seenNonMatch) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete requires the canonical $match+ -> $sort? shape, ' +\n 'but a $match stage was found after a $sort. Re-order the chain so every .match() ' +\n 'call precedes the .sort() call.',\n );\n }\n matchFilters.push(stage.filter);\n } else if (stage instanceof MongoSortStage) {\n if (sort !== undefined) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete accepts at most one $sort stage; drop the extra ' +\n '.sort() call or combine the keys into a single sort spec.',\n );\n }\n sort = { ...stage.sort };\n seenNonMatch = true;\n } else if (stage instanceof MongoSkipStage) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete does not support .skip() — MongoDB findAndModify ' +\n 'has no skip slot. Remove the .skip() call, or use .aggregate()/.build() if the ' +\n 'chain needs skip semantics.',\n );\n } else {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete requires the canonical $match+ -> $sort? shape, ' +\n `but encountered a '${stage.constructor.name}' stage. ` +\n 'This is likely a bug — the type system should have prevented this chain.',\n );\n }\n }\n\n if (matchFilters.length === 0) {\n throw new Error('findOneAndUpdate/findOneAndDelete requires at least one .match() call.');\n }\n const first = matchFilters[0];\n if (first === undefined) {\n throw new Error('Unreachable: matchFilters.length > 0 but first is undefined');\n }\n const filter: MongoFilterExpr = matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters);\n\n return { filter, sort };\n}\n\ninterface DeconstructedUpdate {\n filter: MongoFilterExpr;\n updatePipeline: ReadonlyArray<MongoUpdatePipelineStage>;\n}\n\n/**\n * Walk the accumulated pipeline stages: leading `$match` stages become the\n * filter, remaining stages must all be valid `MongoUpdatePipelineStage`\n * members (currently `$addFields`, `$project`, `$replaceRoot`).\n */\nfunction deconstructUpdateChain(stages: ReadonlyArray<MongoPipelineStage>): DeconstructedUpdate {\n const matchFilters: MongoFilterExpr[] = [];\n let boundary = 0;\n\n for (const stage of stages) {\n if (!(stage instanceof MongoMatchStage)) break;\n matchFilters.push(stage.filter);\n boundary++;\n }\n\n if (matchFilters.length === 0) {\n throw new Error('No-arg updateMany/updateOne requires at least one .match() call.');\n }\n\n const remaining = stages.slice(boundary);\n if (remaining.length === 0) {\n throw new Error(\n 'No-arg updateMany/updateOne requires at least one pipeline-update stage ' +\n '(e.g. .addFields(), .project(), .replaceRoot()) after the .match() stages.',\n );\n }\n\n const updatePipeline: MongoUpdatePipelineStage[] = [];\n for (const stage of remaining) {\n if (\n stage instanceof MongoAddFieldsStage ||\n stage instanceof MongoProjectStage ||\n stage instanceof MongoReplaceRootStage\n ) {\n updatePipeline.push(stage);\n } else {\n throw new Error(\n `No-arg updateMany/updateOne: encountered non-update stage '${stage.constructor.name}' ` +\n 'after the leading $match stages. Only $addFields/$set, $project/$unset, ' +\n 'and $replaceRoot/$replaceWith stages are valid in an update pipeline.',\n );\n }\n }\n\n const first = matchFilters[0];\n if (first === undefined) {\n throw new Error('Unreachable: matchFilters.length > 0 but first is undefined');\n }\n const filter: MongoFilterExpr = matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters);\n\n return { filter, updatePipeline };\n}\n","import type { MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';\nimport {\n MongoAggCond,\n MongoAggLiteral,\n MongoAggOperator,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type {\n ArrayField,\n BooleanField,\n DateField,\n DocField,\n LiteralValue,\n NullableDocField,\n NumericField,\n StringField,\n TypedAggExpr,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Internal factory helpers\n// ---------------------------------------------------------------------------\n\nfunction numericExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return {\n _field: { codecId: 'mongo/double@1', nullable: false } as NumericField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction numericUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return {\n _field: { codecId: 'mongo/double@1', nullable: false } as NumericField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction stringExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<StringField> {\n return {\n _field: { codecId: 'mongo/string@1', nullable: false } as StringField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction stringUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return {\n _field: { codecId: 'mongo/string@1', nullable: false } as StringField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction booleanExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<BooleanField> {\n return {\n _field: { codecId: 'mongo/bool@1', nullable: false } as BooleanField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction booleanUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return {\n _field: { codecId: 'mongo/bool@1', nullable: false } as BooleanField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction dateUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<DateField> {\n return {\n _field: { codecId: 'mongo/date@1', nullable: false } as DateField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction arrayExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return {\n _field: { codecId: 'mongo/array@1', nullable: false } as ArrayField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction arrayUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return {\n _field: { codecId: 'mongo/array@1', nullable: false } as ArrayField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction docUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return {\n _field: { codecId: arg._field.codecId, nullable: false },\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction namedArgsExpr<F extends DocField>(\n op: string,\n args: Readonly<Record<string, TypedAggExpr<DocField> | undefined>>,\n _field: F,\n): TypedAggExpr<F> {\n const nodeArgs: Record<string, MongoAggExpr> = {};\n for (const [key, val] of Object.entries(args)) {\n if (val !== undefined) {\n nodeArgs[key] = val.node;\n }\n }\n return { _field, node: MongoAggOperator.of(op, nodeArgs) };\n}\n\nconst NUMERIC: NumericField = { codecId: 'mongo/double@1', nullable: false } as NumericField;\nconst STRING: StringField = { codecId: 'mongo/string@1', nullable: false } as StringField;\nconst BOOLEAN: BooleanField = { codecId: 'mongo/bool@1', nullable: false } as BooleanField;\nconst DATE: DateField = { codecId: 'mongo/date@1', nullable: false } as DateField;\nconst ARRAY: ArrayField = { codecId: 'mongo/array@1', nullable: false } as ArrayField;\nconst DOC: DocField = { codecId: 'mongo/document@1', nullable: false };\n\nfunction literal(value: string): TypedAggExpr<StringField>;\nfunction literal(value: number): TypedAggExpr<NumericField>;\nfunction literal(value: boolean): TypedAggExpr<BooleanField>;\nfunction literal(value: Date): TypedAggExpr<DateField>;\nfunction literal<F extends DocField>(value: LiteralValue<F>): TypedAggExpr<F>;\nfunction literal(value: unknown): TypedAggExpr<DocField> {\n return { _field: undefined as never, node: MongoAggLiteral.of(value) };\n}\n\n// ---------------------------------------------------------------------------\n// Public helpers\n// ---------------------------------------------------------------------------\n\nexport const fn = {\n // -- Arithmetic (existing) ------------------------------------------------\n\n add(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return numericExpr('$add', args);\n },\n\n subtract(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$subtract', [a, b]);\n },\n\n multiply(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return numericExpr('$multiply', args);\n },\n\n divide(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$divide', [a, b]);\n },\n\n // -- String (existing) ----------------------------------------------------\n\n concat(...args: TypedAggExpr<DocField>[]): TypedAggExpr<StringField> {\n return stringExpr('$concat', args);\n },\n\n toLower(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toLower', a);\n },\n\n toUpper(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toUpper', a);\n },\n\n // -- Size (existing) ------------------------------------------------------\n\n size(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$size', a);\n },\n\n // -- Control flow (existing) ----------------------------------------------\n\n cond<F extends DocField>(\n condition: MongoAggExpr,\n thenExpr: TypedAggExpr<F>,\n elseExpr: TypedAggExpr<DocField>,\n ): TypedAggExpr<F> {\n return {\n _field: thenExpr._field,\n node: new MongoAggCond(condition, thenExpr.node, elseExpr.node),\n };\n },\n\n literal,\n\n // -- Date helpers ---------------------------------------------------------\n\n year(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$year', a);\n },\n month(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$month', a);\n },\n dayOfMonth(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$dayOfMonth', a);\n },\n hour(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$hour', a);\n },\n minute(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$minute', a);\n },\n second(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$second', a);\n },\n millisecond(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$millisecond', a);\n },\n dateToString(args: {\n date: TypedAggExpr<DateField>;\n format?: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$dateToString', args, STRING);\n },\n dateFromString(args: {\n dateString: TypedAggExpr<StringField>;\n format?: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n onError?: TypedAggExpr<DocField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateFromString', args, DATE);\n },\n dateDiff(args: {\n startDate: TypedAggExpr<DateField>;\n endDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n startOfWeek?: TypedAggExpr<StringField>;\n }): TypedAggExpr<NumericField> {\n return namedArgsExpr('$dateDiff', args, NUMERIC);\n },\n dateAdd(args: {\n startDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n amount: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateAdd', args, DATE);\n },\n dateSubtract(args: {\n startDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n amount: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateSubtract', args, DATE);\n },\n dateTrunc(args: {\n date: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n binSize?: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n startOfWeek?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateTrunc', args, DATE);\n },\n\n // -- String helpers -------------------------------------------------------\n\n substr(\n str: TypedAggExpr<DocField>,\n start: TypedAggExpr<DocField>,\n length: TypedAggExpr<DocField>,\n ): TypedAggExpr<StringField> {\n return stringExpr('$substr', [str, start, length]);\n },\n substrBytes(\n str: TypedAggExpr<DocField>,\n start: TypedAggExpr<DocField>,\n count: TypedAggExpr<DocField>,\n ): TypedAggExpr<StringField> {\n return stringExpr('$substrBytes', [str, start, count]);\n },\n trim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$trim', args, STRING);\n },\n ltrim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$ltrim', args, STRING);\n },\n rtrim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$rtrim', args, STRING);\n },\n split(str: TypedAggExpr<DocField>, delimiter: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayExpr('$split', [str, delimiter]);\n },\n strLenCP(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$strLenCP', a);\n },\n strLenBytes(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$strLenBytes', a);\n },\n regexMatch(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<BooleanField> {\n return namedArgsExpr('$regexMatch', args, BOOLEAN);\n },\n regexFind(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$regexFind', args, DOC);\n },\n regexFindAll(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<ArrayField> {\n return namedArgsExpr('$regexFindAll', args, ARRAY);\n },\n replaceOne(args: {\n input: TypedAggExpr<StringField>;\n find: TypedAggExpr<StringField>;\n replacement: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$replaceOne', args, STRING);\n },\n replaceAll(args: {\n input: TypedAggExpr<StringField>;\n find: TypedAggExpr<StringField>;\n replacement: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$replaceAll', args, STRING);\n },\n\n // -- Comparison helpers ---------------------------------------------------\n\n cmp(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$cmp', [a, b]);\n },\n eq(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$eq', [a, b]);\n },\n ne(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$ne', [a, b]);\n },\n gt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$gt', [a, b]);\n },\n gte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$gte', [a, b]);\n },\n lt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$lt', [a, b]);\n },\n lte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$lte', [a, b]);\n },\n\n // -- Array helpers --------------------------------------------------------\n\n arrayElemAt(\n arr: TypedAggExpr<DocField>,\n idx: TypedAggExpr<DocField>,\n ): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$arrayElemAt', [arr.node, idx.node]),\n };\n },\n concatArrays(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$concatArrays', args);\n },\n firstElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$first', a.node),\n };\n },\n lastElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$last', a.node),\n };\n },\n isIn(elem: TypedAggExpr<DocField>, arr: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$in', [elem, arr]);\n },\n indexOfArray(\n arr: TypedAggExpr<DocField>,\n value: TypedAggExpr<DocField>,\n ...rest: TypedAggExpr<DocField>[]\n ): TypedAggExpr<NumericField> {\n return numericExpr('$indexOfArray', [arr, value, ...rest]);\n },\n isArray(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$isArray', a);\n },\n reverseArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayUnaryExpr('$reverseArray', a);\n },\n slice(arr: TypedAggExpr<DocField>, ...rest: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$slice', [arr, ...rest]);\n },\n zip(args: {\n inputs: TypedAggExpr<ArrayField>[];\n useLongestLength?: TypedAggExpr<BooleanField>;\n defaults?: TypedAggExpr<ArrayField>;\n }): TypedAggExpr<ArrayField> {\n const nodeArgs: Record<string, MongoAggExpr | ReadonlyArray<MongoAggExpr>> = {\n inputs: args.inputs.map((a) => a.node),\n };\n if (args.useLongestLength) nodeArgs['useLongestLength'] = args.useLongestLength.node;\n if (args.defaults) nodeArgs['defaults'] = args.defaults.node;\n return { _field: ARRAY, node: MongoAggOperator.of('$zip', nodeArgs) };\n },\n range(\n start: TypedAggExpr<DocField>,\n end: TypedAggExpr<DocField>,\n step: TypedAggExpr<DocField>,\n ): TypedAggExpr<ArrayField> {\n return arrayExpr('$range', [start, end, step]);\n },\n\n // -- Set helpers ----------------------------------------------------------\n\n setUnion(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$setUnion', args);\n },\n setIntersection(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$setIntersection', args);\n },\n setDifference(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayExpr('$setDifference', [a, b]);\n },\n setEquals(...args: TypedAggExpr<DocField>[]): TypedAggExpr<BooleanField> {\n return booleanExpr('$setEquals', args);\n },\n setIsSubset(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$setIsSubset', [a, b]);\n },\n anyElementTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$anyElementTrue', a);\n },\n allElementsTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$allElementsTrue', a);\n },\n\n // -- Type helpers ---------------------------------------------------------\n\n typeOf(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$type', a);\n },\n convert(args: {\n input: TypedAggExpr<DocField>;\n to: TypedAggExpr<StringField | NumericField>;\n onError?: TypedAggExpr<DocField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$convert', args, DOC);\n },\n toInt(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toInt', a);\n },\n toLong(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toLong', a);\n },\n toDouble(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toDouble', a);\n },\n toDecimal(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toDecimal', a);\n },\n toString_(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toString', a);\n },\n toObjectId(a: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return docUnaryExpr('$toObjectId', a);\n },\n toBool(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$toBool', a);\n },\n toDate(a: TypedAggExpr<DocField>): TypedAggExpr<DateField> {\n return dateUnaryExpr('$toDate', a);\n },\n\n // -- Object helpers -------------------------------------------------------\n\n objectToArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayUnaryExpr('$objectToArray', a);\n },\n arrayToObject(a: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return { _field: DOC, node: MongoAggOperator.of('$arrayToObject', a.node) };\n },\n getField(args: {\n field: TypedAggExpr<StringField>;\n input?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$getField', args, DOC);\n },\n setField(args: {\n field: TypedAggExpr<StringField>;\n input: TypedAggExpr<DocField>;\n value: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$setField', args, DOC);\n },\n};\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n ExtractMongoCodecTypes,\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type {\n DeleteResult,\n InsertManyResult,\n InsertOneResult,\n MongoFilterExpr,\n MongoQueryPlan,\n MongoUpdateSpec,\n UpdateResult,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n DeleteManyCommand,\n DeleteOneCommand,\n FindOneAndDeleteCommand,\n FindOneAndUpdateCommand,\n InsertManyCommand,\n InsertOneCommand,\n MongoAndExpr,\n MongoExistsExpr,\n MongoMatchStage,\n UpdateManyCommand,\n UpdateOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport { PipelineChain } from './builder';\nimport { createFieldAccessor, type FieldAccessor } from './field-accessor';\nimport type { ModelNestedShape, NestedDocShape } from './resolve-path';\nimport type { ModelToDocShape, ResolveRow } from './types';\nimport { resolveUpdaterResult, type UpdaterResult } from './update-ops';\n\n/**\n * \"Match-all\" filter used by the unqualified-write terminals\n * (`updateAll`/`deleteAll`). The canonical representation is still\n * undecided — `MongoAndExpr` with an empty conjunction and a dedicated\n * `MongoMatchAllExpr` node are both candidates. For now we use\n * `_id $exists: true`, which is trivially true on every document and\n * avoids introducing a new AST node before the wider question is\n * resolved. Centralised so the eventual switch is a one-line change.\n */\nfunction matchAllFilter(): MongoFilterExpr {\n return MongoExistsExpr.exists('_id');\n}\n\n/**\n * Resolve an updater callback into a `MongoUpdateSpec` (either the folded\n * operator object or a pipeline-stage array). Centralised so all write\n * terminals share the same fold / dispatch semantics.\n */\nfunction resolveUpdaterCallback<\n Shape extends ModelToDocShape<MongoContract, string>,\n Nested extends NestedDocShape,\n>(updaterFn: (fields: FieldAccessor<Shape, Nested>) => UpdaterResult): MongoUpdateSpec {\n const accessor = createFieldAccessor<Shape, Nested>();\n const items = updaterFn(accessor);\n return resolveUpdaterResult(items);\n}\n\n/**\n * Build the `PlanMeta` envelope shared by every write terminal in this\n * package. Lane is `mongo-query` (single lane for all query-builder terminals)\n * so middleware can dispatch on intent without inspecting the command.\n */\nfunction writeMeta(storageHash: string): PlanMeta {\n return {\n target: 'mongo',\n storageHash,\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n}\n\n/**\n * Root state of the query-builder state machine. Returned from\n * `mongoQuery(...).from(name)` and bound to a single collection.\n *\n * Inherits the entire pipeline-stage surface from `PipelineChain` (since an\n * empty `CollectionHandle` is observably an empty pipeline). Adds:\n *\n * - `match(...)` — overridden to transition to `FilteredCollection`, which\n * accumulates filters for eventual splatting into write/find-and-modify\n * wire commands.\n * - **Insert / unqualified-write methods** (M2): `insertOne`, `insertMany`,\n * `updateAll`, `deleteAll`. These live *only* here — the corresponding\n * methods are absent from `FilteredCollection`, so a caller cannot\n * accidentally produce an unqualified write by forgetting to `.match(...)`\n * later in the chain. Bodies land in M2.\n */\nexport class CollectionHandle<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n ModelName extends keyof TContract['models'] & string,\n> extends PipelineChain<\n TContract,\n ModelToDocShape<TContract, ModelName>,\n 'update-cleared',\n 'fam-cleared',\n 'leading',\n ModelNestedShape<TContract, ModelName>\n> {\n readonly #ctx: BindingContext<TContract>;\n readonly #modelName: ModelName;\n\n constructor(ctx: BindingContext<TContract>, modelName: ModelName) {\n super(ctx.contract, {\n collection: ctx.collection,\n stages: [],\n storageHash: ctx.storageHash,\n });\n this.#ctx = ctx;\n this.#modelName = modelName;\n }\n\n /**\n * Bound model name. Exposed so type tests can assert the binding without\n * flipping into a pipeline. Not part of the public-API contract.\n */\n get _modelName(): ModelName {\n return this.#modelName;\n }\n\n /**\n * Begin accumulating a filter. Transitions to `FilteredCollection`.\n *\n * Overrides `PipelineChain.match` (which appends another `$match` stage\n * and stays in the chain). The two implementations are semantically\n * equivalent for the read terminal — multiple `$match` stages AND-fold in\n * Mongo — but `FilteredCollection` makes the accumulated filter\n * addressable for the write/find-and-modify terminals landing in M2/M3.\n */\n override match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;\n override match(\n fn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n ): FilteredCollection<TContract, ModelName>;\n override match(\n filterOrFn:\n | MongoFilterExpr\n | ((\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr),\n ): FilteredCollection<TContract, ModelName> {\n const resolved =\n typeof filterOrFn === 'function'\n ? filterOrFn(\n createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(),\n )\n : filterOrFn;\n return new FilteredCollection<TContract, ModelName>(this.#ctx, this.#modelName, [resolved]);\n }\n\n // --- Inserts ---\n\n /**\n * Insert a single document. Document fields are passed straight through to\n * the wire `InsertOneCommand` — codec normalisation happens at the\n * adapter/driver boundary, identically to the SQL builder (see Open Item\n * #14 confirmation in the design conversation).\n *\n * Returns a `MongoQueryPlan<InsertOneResult>` whose row stream yields a\n * single result document with the server-assigned `insertedId`.\n */\n insertOne(\n document: Record<string, MongoValue>,\n ): MongoQueryPlan<InsertOneResult, InsertOneCommand> {\n const command = new InsertOneCommand(this.#ctx.collection, document);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Insert a batch of documents. Order is preserved in the returned\n * `insertedIds` array.\n */\n insertMany(\n documents: ReadonlyArray<Record<string, MongoValue>>,\n ): MongoQueryPlan<InsertManyResult, InsertManyCommand> {\n if (documents.length === 0) {\n throw new Error('insertMany() requires at least one document.');\n }\n const command = new InsertManyCommand(this.#ctx.collection, documents);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Unqualified writes ---\n\n /**\n * Update *every* document in the collection. Lives only on\n * `CollectionHandle` — the corresponding method is intentionally absent\n * from `FilteredCollection` so a caller cannot accidentally produce an\n * unqualified write by forgetting to `.match(...)` first. Pair with\n * `.match(...).updateMany(...)` for the filtered case.\n */\n updateAll(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateManyCommand(this.#ctx.collection, matchAllFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete *every* document in the collection. See `updateAll` for the\n * rationale around the unqualified-write surface being limited to this\n * state class.\n */\n deleteAll(): MongoQueryPlan<DeleteResult, DeleteManyCommand> {\n const command = new DeleteManyCommand(this.#ctx.collection, matchAllFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Upserts ---\n\n /**\n * Insert-or-update the document matching `filterFn`. The filter is\n * mandatory (vs. `updateAll`'s tautological match) because an upsert\n * without a discriminating predicate would either match every existing\n * document or insert an indistinguishable new one.\n *\n * Maps to `UpdateOneCommand` with `upsert: true`. The driver inserts a\n * new document derived from the filter equality fields plus the update\n * spec when no match is found; otherwise updates the matched document.\n */\n upsertOne(\n filterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const accessor = createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >();\n const filter = filterFn(accessor);\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, filter, update, true);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n}\n\n/**\n * State reached after one or more `.match(...)` calls on `CollectionHandle`.\n *\n * Inherits the pipeline-stage surface from `PipelineChain`, with the\n * accumulated filters baked in as a leading `$match` stage on the underlying\n * pipeline state. This means read-terminal output (`.aggregate()` /\n * `.build()`) and any subsequent pipeline-stage chain see the filtered\n * collection as input — the read story works through pure inheritance.\n *\n * Adds:\n *\n * - `match(...)` — pushes another `$match` stage *and* records the filter in\n * the accumulator, so the eventual write/find-and-modify terminal can\n * splat the AND-folded filter into the wire command's `filter` slot.\n * - **Filtered writes** (M2): `updateMany`, `updateOne`, `deleteMany`,\n * `deleteOne`, `upsertOne`. Stubbed in M1. (Upsert-many is an open\n * question in the spec — see TML-2267 — and is intentionally absent.)\n * - **Find-and-modify** (M3): `findOneAndUpdate`, `findOneAndDelete`.\n * Stubbed in M1.\n *\n * Notably *does not* expose `insertOne`/`insertMany`/`updateAll`/`deleteAll`\n * — those are insert or unqualified-write operations that are nonsense\n * after a filter has been applied.\n */\nexport class FilteredCollection<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n ModelName extends keyof TContract['models'] & string,\n> extends PipelineChain<\n TContract,\n ModelToDocShape<TContract, ModelName>,\n 'update-cleared',\n 'fam-cleared',\n 'leading',\n ModelNestedShape<TContract, ModelName>\n> {\n readonly #ctx: BindingContext<TContract>;\n readonly #modelName: ModelName;\n readonly #filters: ReadonlyArray<MongoFilterExpr>;\n\n constructor(\n ctx: BindingContext<TContract>,\n modelName: ModelName,\n filters: ReadonlyArray<MongoFilterExpr>,\n ) {\n if (filters.length === 0) {\n throw new Error('FilteredCollection requires at least one accumulated filter');\n }\n const first = filters[0];\n if (first === undefined) {\n throw new Error('FilteredCollection: unreachable empty-filters branch');\n }\n const leading = filters.length === 1 ? first : foldAnd(filters);\n super(ctx.contract, {\n collection: ctx.collection,\n stages: [new MongoMatchStage(leading)],\n storageHash: ctx.storageHash,\n });\n this.#ctx = ctx;\n this.#modelName = modelName;\n this.#filters = filters;\n }\n\n get _modelName(): ModelName {\n return this.#modelName;\n }\n\n /**\n * Accumulated filter list. Exposed for the M2/M3 write/find-and-modify\n * terminals to splat into wire-command `filter` slots; not part of the\n * public-API contract.\n */\n get _filters(): ReadonlyArray<MongoFilterExpr> {\n return this.#filters;\n }\n\n /**\n * Append another filter to the accumulator. Returns a new\n * `FilteredCollection` whose underlying pipeline rebuilds the leading\n * `$match` from the AND-folded accumulator (rather than appending a\n * second `$match` stage), so the write/find-and-modify terminals see a\n * single authoritative filter expression.\n */\n override match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;\n override match(\n fn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n ): FilteredCollection<TContract, ModelName>;\n override match(\n filterOrFn:\n | MongoFilterExpr\n | ((\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr),\n ): FilteredCollection<TContract, ModelName> {\n const resolved =\n typeof filterOrFn === 'function'\n ? filterOrFn(\n createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(),\n )\n : filterOrFn;\n return new FilteredCollection<TContract, ModelName>(this.#ctx, this.#modelName, [\n ...this.#filters,\n resolved,\n ]);\n }\n\n // --- Filtered writes ---\n\n /**\n * AND-fold the accumulated filters into a single `MongoFilterExpr` for\n * splatting into a write/find-and-modify wire command's `filter` slot.\n * Length-1 short-circuits to avoid a redundant `$and` wrapper.\n */\n #foldedFilter(): MongoFilterExpr {\n const first = this.#filters[0];\n if (first === undefined) {\n throw new Error('FilteredCollection: invariant violated — empty filter accumulator');\n }\n return this.#filters.length === 1 ? first : foldAnd(this.#filters);\n }\n\n /**\n * Update every matching document. `updaterFn` receives a `FieldAccessor`\n * and returns an array of `TypedUpdateOp` (e.g. `[f.amount.inc(1),\n * f.status.set('done')]`). Operators are folded into the wire-format\n * update spec by `foldUpdateOps`, which throws on operator+path\n * collisions.\n */\n override updateMany(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateManyCommand(this.#ctx.collection, this.#foldedFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Update at most one matching document. The driver picks the document\n * (typically the first one matched by the underlying scan); no ordering\n * guarantee is implied — chain `.sort(...)` and use the M3\n * `.findOneAndUpdate(...)` terminal when ordering matters.\n */\n override updateOne(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete every matching document.\n */\n deleteMany(): MongoQueryPlan<DeleteResult, DeleteManyCommand> {\n const command = new DeleteManyCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete at most one matching document. See the `updateOne` note about\n * driver-chosen victim selection.\n */\n deleteOne(): MongoQueryPlan<DeleteResult, DeleteOneCommand> {\n const command = new DeleteOneCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Upserts ---\n\n /**\n * Insert-or-update against the accumulated filter. Maps to\n * `UpdateOneCommand` with `upsert: true`. Equivalent to\n * `CollectionHandle.upsertOne(f => filter, updaterFn)` but reuses the\n * already-accumulated `.match(...)` filter chain.\n */\n upsertOne(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update, true);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Find-and-modify ---\n\n /**\n * Find a single matching document and apply `updaterFn` to it.\n *\n * `opts.upsert` (default `false`) toggles insert-on-miss behaviour.\n * `opts.returnDocument` (default `'after'`) controls whether the row\n * stream yields the document as it was before or after the update.\n */\n override findOneAndUpdate(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n opts: { readonly upsert?: boolean; readonly returnDocument?: 'before' | 'after' } = {},\n ): MongoQueryPlan<\n ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>> | null,\n FindOneAndUpdateCommand\n > {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new FindOneAndUpdateCommand(\n this.#ctx.collection,\n this.#foldedFilter(),\n update,\n opts.upsert ?? false,\n undefined,\n opts.returnDocument ?? 'after',\n );\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Find a single matching document and delete it. Returns the deleted\n * document via the row stream.\n */\n override findOneAndDelete(): MongoQueryPlan<\n ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>> | null,\n FindOneAndDeleteCommand\n > {\n const command = new FindOneAndDeleteCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n}\n\nfunction foldAnd(filters: ReadonlyArray<MongoFilterExpr>): MongoFilterExpr {\n return MongoAndExpr.of(filters);\n}\n\n/**\n * Narrow a `MongoContractWithTypeMaps`-shaped value down to its underlying\n * `MongoContract` view. `MongoContractWithTypeMaps<C, ...>` is defined as\n * `C & { readonly [phantom]?: TTypeMaps }`, so every contract we accept is\n * structurally a `MongoContract` — the phantom is type-only. This helper\n * centralises that narrowing so callers don't reach for `as unknown as\n * MongoContract` double-casts.\n */\nexport function asMongoContract(\n contract: MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n): MongoContract {\n return contract;\n}\n\n/**\n * Bound execution context shared across the three state classes.\n */\nexport interface BindingContext<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n readonly contract: TContract;\n readonly collection: string;\n readonly storageHash: string;\n}\n\n/**\n * Construct a `CollectionHandle` from a validated contract + root name.\n * Used by `mongoQuery(...).from(name)` to enter the state machine.\n */\nexport function createCollectionHandle<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n RootName extends keyof TContract['roots'] & string,\n>(\n contract: TContract,\n rootName: RootName,\n): CollectionHandle<TContract, TContract['roots'][RootName] & string & keyof TContract['models']> {\n const c = asMongoContract(contract);\n const modelName = c.roots[rootName];\n if (!modelName) {\n const validRoots = Object.keys(c.roots).join(', ');\n throw new Error(`Unknown root: \"${rootName}\". Valid roots: ${validRoots}`);\n }\n const model = c.models[modelName];\n if (!model) {\n throw new Error(`Unknown model: \"${modelName}\" referenced by root \"${rootName}\".`);\n }\n const collectionName = model.storage?.collection ?? rootName;\n if (!c.storage?.storageHash) {\n throw new Error(\n 'Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().',\n );\n }\n return new CollectionHandle(\n {\n contract,\n collection: collectionName,\n storageHash: String(c.storage.storageHash),\n },\n modelName as TContract['roots'][RootName] & string & keyof TContract['models'],\n );\n}\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type { AnyMongoCommand, MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { asMongoContract, type CollectionHandle, createCollectionHandle } from './state-classes';\n\n/**\n * Public entry point of the query builder. `mongoQuery(...).from(rootName)`\n * yields the root state of the three-state machine\n * (`CollectionHandle` → `FilteredCollection` → `PipelineChain`).\n *\n * `rawCommand(cmd)` is the escape hatch for cases the typed surface does\n * not cover (yet) — it accepts any `AnyMongoCommand` (typed CRUD or a\n * `RawMongoCommand` of `Document`s) and packages it into a `MongoQueryPlan`\n * with `lane: 'mongo-query'`. Row type is `unknown` because the runtime\n * cannot know what the caller's command yields.\n */\nexport interface QueryRoot<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n from<K extends keyof TContract['roots'] & string>(\n rootName: K,\n ): CollectionHandle<TContract, TContract['roots'][K] & string & keyof TContract['models']>;\n rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C>;\n}\n\nexport function mongoQuery<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: { contractJson: unknown }): QueryRoot<TContract> {\n const contract = options.contractJson as TContract;\n return {\n from<K extends keyof TContract['roots'] & string>(rootName: K) {\n return createCollectionHandle(contract, rootName);\n },\n rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C> {\n const c = asMongoContract(contract);\n const storageHash = c.storage?.storageHash;\n if (!storageHash) {\n throw new Error(\n 'Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().',\n );\n }\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: String(storageHash),\n lane: 'mongo-query',\n paramDescriptors: [],\n };\n return { collection: command.collection, command, meta };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["#contract","#state","#withStage","#writeTerminal","#writeMeta","#ctx","#modelName","#filters","#foldedFilter"],"sources":["../src/accumulator-helpers.ts","../src/update-ops.ts","../src/field-accessor.ts","../src/lookup-builder.ts","../src/pipeline-result-shape.ts","../src/result-shape.ts","../src/builder.ts","../src/expression-helpers.ts","../src/state-classes.ts","../src/query.ts"],"sourcesContent":["import type { MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';\nimport { MongoAggAccumulator, MongoAggLiteral } from '@prisma-next/mongo-query-ast/execution';\nimport type {\n ArrayField,\n DocField,\n NullableNumericField,\n NumericField,\n TypedAccumulatorExpr,\n TypedAggExpr,\n} from './types';\n\nfunction namedAccumulatorArgs(\n args: Readonly<Record<string, TypedAggExpr<DocField> | undefined>>,\n): Record<string, MongoAggExpr> {\n const result: Record<string, MongoAggExpr> = {};\n for (const [key, val] of Object.entries(args)) {\n if (val !== undefined) {\n result[key] = val.node;\n }\n }\n return result;\n}\n\nexport const acc = {\n sum<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<F> {\n return { _field: undefined as never, node: MongoAggAccumulator.sum(expr.node) };\n },\n\n avg(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.avg(expr.node) };\n },\n\n min<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.min(expr.node) };\n },\n\n max<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.max(expr.node) };\n },\n\n first<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.first(expr.node) };\n },\n\n last<F extends DocField>(\n expr: TypedAggExpr<F>,\n ): TypedAccumulatorExpr<{ readonly codecId: F['codecId']; readonly nullable: true }> {\n return { _field: undefined as never, node: MongoAggAccumulator.last(expr.node) };\n },\n\n push(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField> {\n return { _field: undefined as never, node: MongoAggAccumulator.push(expr.node) };\n },\n\n addToSet(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField> {\n return { _field: undefined as never, node: MongoAggAccumulator.addToSet(expr.node) };\n },\n\n count(): TypedAccumulatorExpr<NumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.count() };\n },\n\n stdDevPop(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.stdDevPop(expr.node) };\n },\n\n stdDevSamp(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField> {\n return { _field: undefined as never, node: MongoAggAccumulator.stdDevSamp(expr.node) };\n },\n\n firstN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$firstN', namedAccumulatorArgs(args)),\n };\n },\n\n lastN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$lastN', namedAccumulatorArgs(args)),\n };\n },\n\n maxN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$maxN', namedAccumulatorArgs(args)),\n };\n },\n\n minN(args: {\n input: TypedAggExpr<DocField>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$minN', namedAccumulatorArgs(args)),\n };\n },\n\n top(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n }): TypedAccumulatorExpr<DocField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$top', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n }),\n };\n },\n\n bottom(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n }): TypedAccumulatorExpr<DocField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$bottom', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n }),\n };\n },\n\n topN(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$topN', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n n: args.n.node,\n }),\n };\n },\n\n bottomN(args: {\n output: TypedAggExpr<DocField>;\n sortBy: Readonly<Record<string, 1 | -1>>;\n n: TypedAggExpr<NumericField>;\n }): TypedAccumulatorExpr<ArrayField> {\n return {\n _field: undefined as never,\n node: MongoAggAccumulator.of('$bottomN', {\n output: args.output.node,\n sortBy: MongoAggLiteral.of(args.sortBy),\n n: args.n.node,\n }),\n };\n },\n};\n","import type {\n MongoUpdatePipelineStage,\n MongoUpdateSpec,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\n\n/**\n * Per-field update operations produced by `Expression`'s update methods\n * (`set`, `inc`, `push`, …). A write terminal folds an array of these into a\n * `MongoUpdateSpec` record (`{ $set: { … }, $inc: { … }, … }`) before\n * constructing the underlying `UpdateManyCommand` / `UpdateOneCommand` AST node.\n *\n * One `TypedUpdateOp` value corresponds to one Mongo update operator applied\n * to one field path. The `op` string is the wire-level operator name (`$set`,\n * `$inc`, …); the `path` is the dot-path to the field (or its top-level name).\n */\nexport type TypedUpdateOp =\n | { readonly op: '$set'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$unset'; readonly path: string }\n | { readonly op: '$rename'; readonly path: string; readonly newName: string }\n | { readonly op: '$inc'; readonly path: string; readonly amount: number }\n | { readonly op: '$mul'; readonly path: string; readonly factor: number }\n | { readonly op: '$min'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$max'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$push'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$addToSet'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$pop'; readonly path: string; readonly direction: 1 | -1 }\n | { readonly op: '$pull'; readonly path: string; readonly value: MongoValue }\n | { readonly op: '$pullAll'; readonly path: string; readonly values: ReadonlyArray<MongoValue> }\n | { readonly op: '$currentDate'; readonly path: string }\n | { readonly op: '$setOnInsert'; readonly path: string; readonly value: MongoValue };\n\nexport const setOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$set',\n path,\n value,\n});\nexport const unsetOp = (path: string): TypedUpdateOp => ({ op: '$unset', path });\nexport const renameOp = (path: string, newName: string): TypedUpdateOp => ({\n op: '$rename',\n path,\n newName,\n});\nexport const incOp = (path: string, amount: number): TypedUpdateOp => ({\n op: '$inc',\n path,\n amount,\n});\nexport const mulOp = (path: string, factor: number): TypedUpdateOp => ({\n op: '$mul',\n path,\n factor,\n});\nexport const minOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$min',\n path,\n value,\n});\nexport const maxOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$max',\n path,\n value,\n});\nexport const pushOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$push',\n path,\n value,\n});\nexport const addToSetOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$addToSet',\n path,\n value,\n});\nexport const popOp = (path: string, direction: 1 | -1): TypedUpdateOp => ({\n op: '$pop',\n path,\n direction,\n});\nexport const pullOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$pull',\n path,\n value,\n});\nexport const pullAllOp = (path: string, values: ReadonlyArray<MongoValue>): TypedUpdateOp => ({\n op: '$pullAll',\n path,\n values,\n});\nexport const currentDateOp = (path: string): TypedUpdateOp => ({ op: '$currentDate', path });\nexport const setOnInsertOp = (path: string, value: MongoValue): TypedUpdateOp => ({\n op: '$setOnInsert',\n path,\n value,\n});\n\n/**\n * Per-operator bucket: `{ '<fieldPath>': <operatorValue> }`. Every value is\n * already a `MongoValue` (operators store numbers/strings/booleans/arrays\n * directly), so no blind casts are needed at assignment sites.\n */\ntype UpdateOpBucket = Record<string, MongoValue>;\n\n/**\n * The full nested shape that `foldUpdateOps` accumulates before returning a\n * `MongoUpdateSpec`: `operator → fieldPath → value`. Each inner bucket is\n * itself a `MongoDocument`-compatible record, which is why the outer map is\n * structurally a `MongoUpdateSpec` (`Record<string, MongoValue>` where every\n * value is a document).\n */\ntype UpdateOpBuckets = Record<string, UpdateOpBucket>;\n\n/**\n * Fold an array of `TypedUpdateOp` into the non-pipeline variant of\n * `MongoUpdateSpec` (`{ $set: { … }, $inc: { … }, … }`).\n *\n * Throws if the same operator targets the same path twice — a clear authoring\n * error that Mongo would otherwise silently coalesce.\n */\nexport function foldUpdateOps(ops: ReadonlyArray<TypedUpdateOp>): MongoUpdateSpec {\n const buckets: UpdateOpBuckets = {};\n const seen = new Set<string>();\n\n const ensure = (key: string): UpdateOpBucket => {\n let bucket = buckets[key];\n if (!bucket) {\n bucket = {};\n buckets[key] = bucket;\n }\n return bucket;\n };\n\n const claim = (op: string, path: string): void => {\n const k = `${op}::${path}`;\n if (seen.has(k)) {\n throw new Error(\n `Update spec collision: ${op} on '${path}' was specified more than once. Combine the operations into a single call site.`,\n );\n }\n seen.add(k);\n };\n\n for (const entry of ops) {\n claim(entry.op, entry.path);\n switch (entry.op) {\n case '$set':\n case '$min':\n case '$max':\n case '$push':\n case '$addToSet':\n case '$pull':\n case '$setOnInsert':\n ensure(entry.op)[entry.path] = entry.value;\n break;\n case '$unset':\n ensure('$unset')[entry.path] = '';\n break;\n case '$rename':\n ensure('$rename')[entry.path] = entry.newName;\n break;\n case '$inc':\n ensure('$inc')[entry.path] = entry.amount;\n break;\n case '$mul':\n ensure('$mul')[entry.path] = entry.factor;\n break;\n case '$pop':\n ensure('$pop')[entry.path] = entry.direction;\n break;\n case '$pullAll':\n ensure('$pullAll')[entry.path] = entry.values;\n break;\n case '$currentDate':\n ensure('$currentDate')[entry.path] = true;\n break;\n }\n }\n\n return buckets;\n}\n\nexport type UpdaterItem = TypedUpdateOp | MongoUpdatePipelineStage;\n\n/**\n * The return type for updater callbacks. Typed as a union of homogeneous\n * arrays so mixed-shape updaters (operator + pipeline stage in the same\n * array) are a compile error. The runtime guard in `resolveUpdaterResult`\n * remains as defence-in-depth.\n */\nexport type UpdaterResult = ReadonlyArray<TypedUpdateOp> | ReadonlyArray<MongoUpdatePipelineStage>;\n\n/**\n * Classify an array of updater items and produce a `MongoUpdateSpec`.\n *\n * - All `TypedUpdateOp` → fold via `foldUpdateOps` (classic `{ $set, $inc, … }`)\n * - All `MongoUpdatePipelineStage` → return as-is (pipeline-style update)\n * - Mixed → throw (also a type error at the call site via the union shape)\n */\nexport function resolveUpdaterResult(items: ReadonlyArray<UpdaterItem>): MongoUpdateSpec {\n if (items.length === 0) {\n throw new Error(\n 'Updater returned no operations. Return at least one update from the callback (e.g. `[f.amount.set(0)]`).',\n );\n }\n\n const isOp = (item: UpdaterItem): item is TypedUpdateOp =>\n 'op' in item && typeof (item as TypedUpdateOp).op === 'string';\n\n const first = items[0];\n if (first === undefined) {\n throw new Error('Unreachable: items.length > 0 but first is undefined');\n }\n const firstIsOp = isOp(first);\n\n for (let i = 1; i < items.length; i++) {\n const item = items[i];\n if (item === undefined) continue;\n if (isOp(item) !== firstIsOp) {\n throw new Error(\n 'Cannot mix TypedUpdateOp values and pipeline stages in a single updater. ' +\n 'Use either `[f.amount.set(0)]` (operator form) or `[f.stage.set({...})]` (pipeline form), not both.',\n );\n }\n }\n\n if (firstIsOp) {\n return foldUpdateOps(items as ReadonlyArray<TypedUpdateOp>);\n }\n return items as ReadonlyArray<MongoUpdatePipelineStage>;\n}\n","import type {\n MongoAggExpr,\n MongoFilterExpr,\n MongoUpdatePipelineStage,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n MongoAddFieldsStage,\n MongoAggFieldRef,\n MongoExistsExpr,\n MongoFieldFilter,\n MongoProjectStage,\n MongoReplaceRootStage,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport type { NestedDocShape, ObjectField, ResolvePath, ValidPaths } from './resolve-path';\nimport type { DocField, DocShape, TypedAggExpr } from './types';\nimport type { TypedUpdateOp } from './update-ops';\nimport {\n addToSetOp,\n currentDateOp,\n incOp,\n maxOp,\n minOp,\n mulOp,\n popOp,\n pullAllOp,\n pullOp,\n pushOp,\n renameOp,\n setOnInsertOp,\n setOp,\n unsetOp,\n} from './update-ops';\n\n/**\n * Operator surface for leaf (scalar) paths — today's full set: filter,\n * update, and aggregation operators. Returned by `Expression<F>` for any\n * `F extends DocField` that is not an `ObjectField<…>` sub-tree.\n *\n * Operator surfaces are intentionally not trait-gated by codec in this\n * revision — tracked on Linear as TML-2259 (scope extended to cover the\n * query-builder's `Expression<F>`). Calling, e.g. `.inc(1)` on a\n * string-typed expression compiles; the runtime relies on Mongo to\n * surface the error. Trait-gating can be tightened in a follow-up\n * without changing the accessor's public shape.\n */\nexport interface LeafExpression<F extends DocField> extends TypedAggExpr<F> {\n readonly _path: string;\n\n // Filter operators\n eq(value: MongoValue): MongoFilterExpr;\n ne(value: MongoValue): MongoFilterExpr;\n gt(value: MongoValue): MongoFilterExpr;\n gte(value: MongoValue): MongoFilterExpr;\n lt(value: MongoValue): MongoFilterExpr;\n lte(value: MongoValue): MongoFilterExpr;\n in(values: ReadonlyArray<MongoValue>): MongoFilterExpr;\n nin(values: ReadonlyArray<MongoValue>): MongoFilterExpr;\n exists(flag?: boolean): MongoFilterExpr;\n\n // Update operators ($set family)\n set(value: MongoValue): TypedUpdateOp;\n unset(): TypedUpdateOp;\n rename(newName: string): TypedUpdateOp;\n\n // Numeric update operators\n inc(amount: number): TypedUpdateOp;\n mul(factor: number): TypedUpdateOp;\n min(value: MongoValue): TypedUpdateOp;\n max(value: MongoValue): TypedUpdateOp;\n\n // Array update operators\n push(value: MongoValue): TypedUpdateOp;\n addToSet(value: MongoValue): TypedUpdateOp;\n pop(direction?: 1 | -1): TypedUpdateOp;\n pull(value: MongoValue): TypedUpdateOp;\n pullAll(values: ReadonlyArray<MongoValue>): TypedUpdateOp;\n\n // Date / upsert helpers\n currentDate(): TypedUpdateOp;\n setOnInsert(value: MongoValue): TypedUpdateOp;\n}\n\n/**\n * Operator surface for non-leaf (value-object) paths — `f('address')`\n * when `address` is a `ContractValueObject`. Intentionally minimal: the\n * whole-value ops that make sense on a structured sub-document\n * (`set`/`unset`/`exists`, null presence via `eq(null)`/`ne(null)`). Field-\n * level ops belong on the constituent leaves (`f('address.city')`).\n *\n * The aggregation `node` is still present (`TypedAggExpr<ObjectField<N>>`)\n * so the value object can be piped through `$addFields` /\n * `$replaceRoot` / etc. as-is.\n */\nexport interface ObjectExpression<N extends NestedDocShape> extends TypedAggExpr<ObjectField<N>> {\n readonly _path: string;\n\n exists(flag?: boolean): MongoFilterExpr;\n eq(value: null): MongoFilterExpr;\n ne(value: null): MongoFilterExpr;\n\n set(value: MongoValue): TypedUpdateOp;\n unset(): TypedUpdateOp;\n}\n\n/**\n * The unified field accessor expression returned by `FieldAccessor` (per\n * [ADR 180](../../../../docs/architecture%20docs/adrs/ADR%20180%20-%20Dot-path%20field%20accessor.md)).\n *\n * Resolves to `ObjectExpression<Sub>` when `F` is an `ObjectField<Sub>`\n * (non-leaf path), otherwise to `LeafExpression<F>` (the full operator\n * surface). The conditional is driven off the `fields` marker that\n * `ObjectField` adds to `DocField`, so existing code that uses plain\n * `DocField` shapes continues to resolve to `LeafExpression`.\n */\nexport type Expression<F extends DocField> =\n F extends ObjectField<infer N> ? ObjectExpression<N> : LeafExpression<F>;\n\n/**\n * Emitters for MongoDB update-pipeline stages (`$addFields`/`$set`,\n * `$project`/`$unset`, `$replaceRoot`/`$replaceWith`). These return\n * `MongoUpdatePipelineStage` nodes and let an updater callback express\n * the pipeline-form update as an alternative to the typed-operator form.\n *\n * The two forms are mutually exclusive per updater call: `resolveUpdaterResult`\n * rejects arrays that mix `TypedUpdateOp` and `MongoUpdatePipelineStage`\n * entries with a clear error — an updater callback must return either all\n * typed ops or all pipeline stages. Pick the form that matches the update\n * you want and commit to it for that call site.\n *\n * Accessible via `f.stage` on the `FieldAccessor`.\n */\nexport interface StageEmitters {\n set(fields: Record<string, MongoAggExpr>): MongoUpdatePipelineStage;\n unset(...paths: ReadonlyArray<string>): MongoUpdatePipelineStage;\n replaceRoot(newRoot: MongoAggExpr): MongoUpdatePipelineStage;\n replaceWith(newRoot: MongoAggExpr): MongoUpdatePipelineStage;\n}\n\nfunction buildStageEmitters(): StageEmitters {\n return {\n set: (fields) => new MongoAddFieldsStage(fields),\n unset: (...paths) => {\n const spec: Record<string, 0> = {};\n for (const p of paths) {\n spec[p] = 0;\n }\n return new MongoProjectStage(spec);\n },\n replaceRoot: (newRoot) => new MongoReplaceRootStage(newRoot),\n replaceWith: (newRoot) => new MongoReplaceRootStage(newRoot),\n };\n}\n\n/**\n * The unified `FieldAccessor` per ADR 180.\n *\n * - Property access (`f.status`) returns an `Expression<F>` whose codec\n * comes from the current pipeline shape `S`.\n * - Callable form (`f('address.city')`) returns an `Expression<ResolvePath<N, P>>`\n * where `N` is the nested shape carrying value-object sub-shapes.\n * Paths that don't exist in `N` are rejected with a compile-time error\n * (via `P extends ValidPaths<N>`). Non-leaf paths like `f('address')`\n * resolve to an `ObjectExpression` whose reduced surface covers the\n * whole-value operations (`set`, `unset`, `exists`, `eq(null)`,\n * `ne(null)`).\n * - `f.rawPath('path')` is a deliberate escape hatch that skips path\n * validation and returns a `LeafExpression<F>` for the given string.\n * Intended for migration authoring where the target field is not yet\n * part of the typed contract (e.g. a backfill writing a newly-added\n * column before the contract hash rolls forward). The method name is\n * deliberately `rawPath` rather than `raw` so it does not shadow a\n * legitimate top-level `raw` field on a user model.\n * - `f.stage` exposes pipeline-style update emitters (`$set`, `$unset`,\n * `$replaceRoot`, `$replaceWith`).\n *\n * When `N` is `Record<string, never>` (the default — e.g. after a\n * replacement stage like `$group` / `$project` / `$replaceRoot`),\n * `ValidPaths<N>` is `never` and the callable form is effectively\n * disabled at the type level. This keeps the builder sound downstream of\n * stages that invalidate the original document's nested-path tree.\n * `f.rawPath(...)` remains available in that state for callers that need\n * an explicit unvalidated path.\n */\nexport type FieldAccessor<S extends DocShape, N extends NestedDocShape = Record<string, never>> = {\n readonly [K in keyof S & string]: Expression<S[K]>;\n} & (<P extends ValidPaths<N>>(path: P) => Expression<ResolvePath<N, P>>) & {\n readonly stage: StageEmitters;\n /**\n * Escape hatch: build a `LeafExpression<F>` for an unvalidated string\n * path. Use only when the path is intentionally outside the typed\n * model surface — data-migration authoring is the canonical case\n * (e.g. backfilling a field that is not yet in the contract). Default\n * `F` is the opaque `DocField`; callers can narrow via the explicit\n * generic: `f.rawPath<StringField>(\"status\").set(\"active\")`.\n *\n * The method is named `rawPath` (not `raw`) so a user model with a\n * top-level `raw` field still resolves `f.raw` to the field-expression\n * property, not to this escape hatch. Does not participate in\n * `ValidPaths<N>` / `ResolvePath<N, P>` — the path is passed through\n * verbatim and no IDE autocomplete is offered.\n */\n rawPath<F extends DocField = DocField>(path: string): LeafExpression<F>;\n };\n\nfunction buildExpression<F extends DocField>(path: string): Expression<F> {\n // The runtime object carries the full operator surface unconditionally;\n // `ObjectExpression` is a strict subset of `LeafExpression`, so a single\n // implementation satisfies both type-level shapes. Compile-time gating\n // prevents misuse of leaf-only operators on object paths.\n return {\n _field: undefined as never,\n _path: path,\n node: MongoAggFieldRef.of(path),\n\n eq: (value: MongoValue) => MongoFieldFilter.eq(path, value),\n ne: (value: MongoValue) => MongoFieldFilter.neq(path, value),\n gt: (value: MongoValue) => MongoFieldFilter.gt(path, value),\n gte: (value: MongoValue) => MongoFieldFilter.gte(path, value),\n lt: (value: MongoValue) => MongoFieldFilter.lt(path, value),\n lte: (value: MongoValue) => MongoFieldFilter.lte(path, value),\n in: (values: ReadonlyArray<MongoValue>) => MongoFieldFilter.in(path, values),\n nin: (values: ReadonlyArray<MongoValue>) => MongoFieldFilter.nin(path, values),\n exists: (flag?: boolean) =>\n flag === false ? MongoExistsExpr.notExists(path) : MongoExistsExpr.exists(path),\n\n set: (value: MongoValue) => setOp(path, value),\n unset: () => unsetOp(path),\n rename: (newName: string) => renameOp(path, newName),\n\n inc: (amount: number) => incOp(path, amount),\n mul: (factor: number) => mulOp(path, factor),\n min: (value: MongoValue) => minOp(path, value),\n max: (value: MongoValue) => maxOp(path, value),\n\n push: (value: MongoValue) => pushOp(path, value),\n addToSet: (value: MongoValue) => addToSetOp(path, value),\n pop: (direction: 1 | -1 = 1) => popOp(path, direction),\n pull: (value: MongoValue) => pullOp(path, value),\n pullAll: (values: ReadonlyArray<MongoValue>) => pullAllOp(path, values),\n\n currentDate: () => currentDateOp(path),\n setOnInsert: (value: MongoValue) => setOnInsertOp(path, value),\n } as unknown as Expression<F>;\n}\n\n/**\n * Construct a unified `FieldAccessor<S, N>` proxy. Property access creates\n * an `Expression` using the property name as the field path; callable\n * form accepts a dot-path string validated against `N` at compile time.\n *\n * The proxy target is a function so the resulting object is both callable\n * and indexable. Symbol-keyed accesses (e.g. `Symbol.toPrimitive`) return\n * `undefined` to keep accidental coercion behaviour unsurprising —\n * matching the previous `FieldProxy` / `FilterProxy` semantics.\n */\nexport function createFieldAccessor<\n S extends DocShape,\n N extends NestedDocShape = Record<string, never>,\n>(): FieldAccessor<S, N> {\n const stageInstance = buildStageEmitters();\n const callable = ((path: string) => buildExpression<DocField>(path)) as unknown as FieldAccessor<\n S,\n N\n >;\n return new Proxy(callable, {\n get(target, prop, receiver) {\n if (typeof prop === 'symbol') {\n return Reflect.get(target, prop, receiver);\n }\n if (prop === 'stage') {\n return stageInstance;\n }\n if (prop === 'rawPath') {\n return (path: string) => buildExpression<DocField>(path);\n }\n return buildExpression(prop);\n },\n });\n}\n","import type { MongoContract } from '@prisma-next/mongo-contract';\nimport { createFieldAccessor, type FieldAccessor, type LeafExpression } from './field-accessor';\nimport type { ModelNestedShape } from './resolve-path';\nimport type { DocField, DocShape, ModelToDocShape } from './types';\n\n/**\n * Resolved foreign-model name for a contract root. Looks `RootName` up\n * through `TContract['roots']` and intersects the result back with\n * `keyof TContract['models']` so it can be used as a `ModelName` index\n * into `models`. Resolves to `never` when the root is not present (this\n * surface should never be reachable through normal use because `from()`\n * constrains its `R` parameter to `keyof TContract['roots']`).\n */\nexport type ModelOf<\n TContract extends MongoContract,\n RootName extends keyof TContract['roots'] & string,\n> = TContract['roots'][RootName] & string & keyof TContract['models'];\n\n/**\n * Object returned by the user from the `on(...)` callback. Each side is\n * a `LeafExpression` produced by property access on the corresponding\n * `FieldAccessor` (`local._id`, `foreign.customerId`, etc.). Carrying\n * `LeafExpression` rather than the broader `TypedAggExpr` is what makes\n * non-leaf returns (e.g. `fn.toUpper(local._id)`) a compile-time error\n * without per-field operator gating — `LeafExpression` carries `_path`,\n * `TypedAggExpr` does not (see field-accessor.ts L47–L82).\n */\nexport interface LookupOnResult {\n readonly local: LeafExpression<DocField>;\n readonly foreign: LeafExpression<DocField>;\n}\n\n/**\n * Marker brand on the captured spec returned by the `lookup(...)`\n * callback. The phantom `_brand` literal lets `PipelineChain.lookup`\n * accept the result of `from(...).on(...).as(...)` without exposing the\n * internal field shape to user code, and prevents accidental\n * construction of a malformed spec by hand.\n */\nexport type LookupResultBrand = 'mongo-query-builder/lookup-result@1';\n\n/**\n * Captured output of the inner `from(name).on(cb).as(name)` chain. The\n * contract is consumed by `PipelineChain.lookup` to construct the\n * `MongoLookupStage` (collection name comes from `models[ModelName]\n * .storage.collection`) and to thread `ModelArrayField<ModelName>` into\n * the resulting `Shape` so the resolver yields `Array<ForeignRow>`.\n *\n * Type parameters carry the foreign-root literal `RootName`, the\n * resolved foreign model name `ModelName`, and the `As` literal so\n * `PipelineChain.lookup`'s return type can encode the result-row\n * promotion precisely.\n */\nexport interface LookupResult<\n RootName extends string,\n ModelName extends string,\n As extends string,\n> {\n readonly _brand: LookupResultBrand;\n readonly _root: RootName;\n readonly _model: ModelName;\n readonly _localField: string;\n readonly _foreignField: string;\n readonly _as: As;\n}\n\n/**\n * Builder returned by `from(name).on(cb)`. Carries the foreign root /\n * model literals plus the captured local / foreign paths, and exposes\n * `.as(name)` to finalise the spec with the user-chosen field name.\n */\nexport interface LookupBuilderWithKey<RootName extends string, ModelName extends string> {\n as<As extends string>(name: As): LookupResult<RootName, ModelName, As>;\n}\n\n/**\n * Builder returned by `from(name)`. Carries the foreign root / model\n * literals and the local pipeline's `Shape` / nested shape so the\n * `on(...)` callback's `local` and `foreign` accessors are typed\n * narrowly.\n *\n * `on(cb)` runs the user's callback to capture the leaf paths and\n * returns a `LookupBuilderWithKey` that exposes `.as(name)`.\n */\nexport interface LookupBuilder<\n TContract extends MongoContract,\n Shape extends DocShape,\n Nested extends Record<string, DocField>,\n RootName extends string,\n ModelName extends string,\n> {\n on(\n cb: (\n local: FieldAccessor<Shape, Nested>,\n foreign: ModelName extends keyof TContract['models'] & string\n ? FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >\n : never,\n ) => LookupOnResult,\n ): LookupBuilderWithKey<RootName, ModelName>;\n}\n\n/**\n * Type of the `from` callable passed to `PipelineChain.lookup`'s outer\n * callback. The generic argument is inferred from a string-literal\n * argument (the same pattern as `mongoQuery<TC>(...).from('orders')`),\n * which grounds `RootName` into the returned `LookupBuilder` *before*\n * the inner `on(...)` callback is type-checked. This sequential\n * inference is what makes `foreign` resolve narrowly to the foreign\n * model's `FieldAccessor` (verified in the R1.5 spike — see spec § Open\n * Questions / Resolved decisions).\n */\nexport type LookupFrom<\n TContract extends MongoContract,\n Shape extends DocShape,\n Nested extends Record<string, DocField>,\n> = <RootName extends keyof TContract['roots'] & string>(\n name: RootName,\n) => LookupBuilder<TContract, Shape, Nested, RootName, ModelOf<TContract, RootName>>;\n\n/**\n * Construct the `from` callable for `PipelineChain.lookup`. The contract\n * is captured so `from(name)` can resolve `roots[name]` to the foreign\n * model name at runtime, look up the foreign collection name from\n * `models[modelName].storage.collection`, and assemble a `LookupResult`\n * for the outer `lookup` to consume.\n *\n * The `Shape`/`Nested` generics are erased at runtime — they exist only\n * to type the local accessor inside the user's `on(...)` callback. The\n * contract value at runtime carries the real model lookup table.\n */\nexport function createLookupFrom<\n TContract extends MongoContract,\n Shape extends DocShape,\n Nested extends Record<string, DocField>,\n>(contract: TContract): LookupFrom<TContract, Shape, Nested> {\n const callable = ((rootName) => {\n const modelName = contract.roots[rootName];\n if (!modelName) {\n const validRoots = Object.keys(contract.roots).join(', ');\n throw new Error(`lookup() unknown root: \"${rootName}\". Valid roots: ${validRoots}`);\n }\n const model = contract.models[modelName];\n const foreignCollection = model?.storage?.collection ?? rootName;\n return createLookupBuilder({\n rootName,\n modelName,\n foreignCollection,\n });\n // The runtime callable accepts a single `string` and returns a\n // generic `LookupBuilder`; the literal `RootName` / `ModelName`\n // generics on `LookupFrom` are erased at runtime and re-asserted\n // here so the surface contract is what the consumer actually sees.\n }) as LookupFrom<TContract, Shape, Nested>;\n return callable;\n}\n\ninterface LookupBuilderRuntimeState {\n readonly rootName: string;\n readonly modelName: string;\n readonly foreignCollection: string;\n}\n\nfunction createLookupBuilder<\n TContract extends MongoContract,\n Shape extends DocShape,\n Nested extends Record<string, DocField>,\n RootName extends string,\n ModelName extends string,\n>(state: LookupBuilderRuntimeState): LookupBuilder<TContract, Shape, Nested, RootName, ModelName> {\n return {\n on(cb) {\n const localAccessor = createFieldAccessor<Shape, Nested>();\n // Foreign accessor is built unparameterised at runtime — the codec\n // metadata is type-only, and `_path` (the only thing we read off\n // either side) is filled by property access regardless of the\n // generic parameters. The narrow generic on the callback signature\n // is what gives the user the foreign model's keys at compile time.\n const foreignAccessor = createFieldAccessor<DocShape, Record<string, DocField>>();\n const result = cb(localAccessor, foreignAccessor as Parameters<typeof cb>[1]);\n assertLeafExpression(result.local, 'local');\n assertLeafExpression(result.foreign, 'foreign');\n return createLookupBuilderWithKey<RootName, ModelName>({\n ...state,\n localField: result.local._path,\n foreignField: result.foreign._path,\n });\n },\n };\n}\n\ninterface LookupBuilderWithKeyRuntimeState extends LookupBuilderRuntimeState {\n readonly localField: string;\n readonly foreignField: string;\n}\n\nfunction createLookupBuilderWithKey<RootName extends string, ModelName extends string>(\n state: LookupBuilderWithKeyRuntimeState,\n): LookupBuilderWithKey<RootName, ModelName> {\n return {\n as<As extends string>(name: As): LookupResult<RootName, ModelName, As> {\n return {\n _brand: 'mongo-query-builder/lookup-result@1',\n // The `RootName` / `ModelName` literal generics are erased at\n // runtime; the runtime state holds the same strings as plain\n // `string`. Re-brand so consumers (the lookup-stage builder)\n // can read the literals back without a downstream cast.\n _root: state.rootName as RootName,\n _model: state.modelName as ModelName,\n _localField: state.localField,\n _foreignField: state.foreignField,\n _as: name,\n };\n },\n };\n}\n\n/**\n * Defensive runtime guard catching the case where a user returns a\n * non-`LeafExpression` from the `on(...)` callback (e.g. by casting\n * around the type system, or threading a value in from outside the\n * callback). Compile-time gating via `LookupOnResult`'s `LeafExpression`\n * type already rejects `fn.<op>(…)` returns at the type level — this\n * guard is the runtime backstop matching the defensive style of\n * `deconstructFindAndModifyChain` in builder.ts.\n */\nfunction assertLeafExpression(\n value: LeafExpression<DocField>,\n side: 'local' | 'foreign',\n): asserts value is LeafExpression<DocField> {\n if (!value || typeof value._path !== 'string' || value._path.length === 0) {\n throw new Error(\n `lookup().on() ${side} side must return a leaf field reference (e.g. \\`${side}.<field>\\`). ` +\n 'Aggregation expressions and computed values are not supported.',\n );\n }\n}\n\n/**\n * Extract the runtime metadata from a `LookupResult` for `PipelineChain\n * .lookup` to construct the `MongoLookupStage`. The internal fields are\n * intentionally underscore-prefixed and brand-checked here so user code\n * cannot synthesise a fake spec; this is the single ingress point.\n */\nexport function extractLookupResult(\n result: LookupResult<string, string, string>,\n contract: MongoContract,\n): {\n readonly foreignCollection: string;\n readonly localField: string;\n readonly foreignField: string;\n readonly as: string;\n readonly modelName: string;\n} {\n if (!result || result._brand !== 'mongo-query-builder/lookup-result@1') {\n throw new Error(\n 'lookup() callback must return the result of `from(name).on(cb).as(name)`. ' +\n 'Returning a hand-rolled options object is not supported.',\n );\n }\n const model = contract.models[result._model];\n const foreignCollection = model?.storage?.collection ?? result._root;\n return {\n foreignCollection,\n localField: result._localField,\n foreignField: result._foreignField,\n as: result._as,\n modelName: result._model,\n };\n}\n","import type { MongoPipelineStage } from '@prisma-next/mongo-query-ast/execution';\n\nconst identityStageKinds = new Set(['match', 'sort', 'limit', 'skip', 'sample']);\n\nexport function pipelineSupportsFlatResultShape(\n stages: ReadonlyArray<MongoPipelineStage>,\n): boolean {\n for (const stage of stages) {\n const k = stage.kind;\n if (!identityStageKinds.has(k)) {\n return false;\n }\n }\n return true;\n}\n","import type { ContractField } from '@prisma-next/contract/types';\nimport type { MongoModelDefinition } from '@prisma-next/mongo-contract';\nimport type { MongoFieldShape, MongoResultShape } from '@prisma-next/mongo-query-ast/execution';\nimport {\n freezeMongoFieldShape,\n freezeMongoResultShape,\n} from '@prisma-next/mongo-query-ast/execution';\n\nexport function contractFieldToMongoFieldShape(field: ContractField): MongoFieldShape {\n const { type, nullable, many } = field;\n if (type.kind === 'valueObject' || type.kind === 'union') {\n return Object.freeze({ kind: 'unknown' as const });\n }\n if (type.kind !== 'scalar') {\n return Object.freeze({ kind: 'unknown' as const });\n }\n if (field.dict === true) {\n return Object.freeze({ kind: 'unknown' as const });\n }\n if (many === true) {\n return freezeMongoFieldShape({\n kind: 'array',\n nullable,\n element: { kind: 'leaf', codecId: type.codecId, nullable: false },\n });\n }\n return freezeMongoFieldShape({\n kind: 'leaf',\n codecId: type.codecId,\n nullable,\n });\n}\n\nexport function contractModelToMongoResultShape(\n model: MongoModelDefinition,\n options?: {\n readonly selection?: readonly string[];\n readonly includeRelationNames?: readonly string[];\n },\n): MongoResultShape {\n const fields: Record<string, MongoFieldShape> = {};\n for (const rel of options?.includeRelationNames ?? []) {\n fields[rel] = Object.freeze({ kind: 'unknown' as const });\n }\n const modelFields = model.fields;\n // An explicit empty selection is honored as-is (returns a document shape\n // with no fields). Only the absence of a selection falls back to the model's\n // full field set.\n const keys = options?.selection !== undefined ? options.selection : Object.keys(modelFields);\n\n for (const key of keys) {\n if (Object.hasOwn(fields, key)) {\n continue;\n }\n const cf = modelFields[key];\n if (!cf) {\n fields[key] = Object.freeze({ kind: 'unknown' as const });\n continue;\n }\n fields[key] = contractFieldToMongoFieldShape(cf);\n }\n return freezeMongoResultShape({ kind: 'document', fields });\n}\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n ExtractMongoCodecTypes,\n MongoContract,\n MongoContractWithTypeMaps,\n MongoModelDefinition,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type {\n MongoAggAccumulator,\n MongoAggExpr,\n MongoDensifyRange,\n MongoFillOutput,\n MongoFilterExpr,\n MongoPipelineStage,\n MongoProjectionValue,\n MongoQueryPlan,\n MongoResultShape,\n MongoUpdatePipelineStage,\n MongoWindowField,\n UpdateResult,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n AggregateCommand,\n FindOneAndDeleteCommand,\n FindOneAndUpdateCommand,\n MongoAddFieldsStage,\n MongoAndExpr,\n MongoBucketAutoStage,\n MongoBucketStage,\n MongoCountStage,\n MongoDensifyStage,\n MongoFacetStage,\n MongoFillStage,\n MongoGeoNearStage,\n MongoGraphLookupStage,\n MongoGroupStage,\n MongoLimitStage,\n MongoLookupStage,\n MongoMatchStage,\n MongoMergeStage,\n MongoOutStage,\n MongoProjectStage,\n MongoRedactStage,\n MongoReplaceRootStage,\n MongoSampleStage,\n MongoSearchMetaStage,\n MongoSearchStage,\n MongoSetWindowFieldsStage,\n MongoSkipStage,\n MongoSortByCountStage,\n MongoSortStage,\n MongoUnionWithStage,\n MongoUnwindStage,\n MongoVectorSearchStage,\n UpdateManyCommand,\n UpdateOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { createFieldAccessor, type Expression, type FieldAccessor } from './field-accessor';\nimport {\n createLookupFrom,\n extractLookupResult,\n type LookupFrom,\n type LookupResult,\n} from './lookup-builder';\nimport type { FindAndModifyEnabled, LeadingMatch, UpdateEnabled } from './markers';\nimport { pipelineSupportsFlatResultShape } from './pipeline-result-shape';\nimport type { ModelArrayField, NestedDocShape } from './resolve-path';\nimport { contractModelToMongoResultShape } from './result-shape';\nimport type {\n DocField,\n DocShape,\n ExtractDocShape,\n GroupedDocShape,\n GroupSpec,\n ProjectedShape,\n ResolveRow,\n SortSpec,\n TypedAggExpr,\n UnwoundShape,\n} from './types';\nimport { resolveUpdaterResult, type UpdaterResult } from './update-ops';\n\ninterface PipelineChainState {\n readonly collection: string;\n readonly stages: ReadonlyArray<MongoPipelineStage>;\n readonly storageHash: string;\n readonly modelName?: string;\n}\n\n/**\n * The pipeline state in the query-builder state machine.\n *\n * Reached from `CollectionHandle` or `FilteredCollection` after the first\n * pipeline-stage method call (or directly via `aggregate()` shortcuts). Holds\n * the accumulated `MongoPipelineStage[]` and exposes pipeline-stage methods,\n * the `merge`/`out` write terminals, and the `build`/`aggregate` read\n * terminals.\n *\n * Two phantom type parameters gate the conditional terminals:\n *\n * - `U extends UpdateEnabled` — when `'update-ok'`, the no-arg `updateMany()` /\n * `updateOne()` form is available (consume the chain as an\n * update-with-pipeline spec). Cleared by stages that produce content the\n * `update` AST cannot represent (e.g. `$group`, `$lookup`, `$limit`).\n * - `F extends FindAndModifyEnabled` — when `'fam-ok'`, the\n * `findOneAndUpdate(...)` / `findOneAndDelete(...)` terminals are\n * available. Cleared by stages incompatible with their wire-command slots\n * (`$limit`, `$group`, mutating stages, …).\n *\n * The marker semantics are encoded in the per-method return types — see the\n * marker table (and rationale per row) in\n * `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.\n */\nexport class PipelineChain<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n Shape extends DocShape,\n U extends UpdateEnabled = 'update-ok',\n F extends FindAndModifyEnabled = 'fam-ok',\n L extends LeadingMatch = 'leading',\n N extends NestedDocShape = Record<string, never>,\n> {\n declare readonly __updateCompat: U;\n declare readonly __findAndModifyCompat: F;\n declare readonly __leadingMatch: L;\n\n readonly #contract: TContract;\n readonly #state: PipelineChainState;\n\n constructor(contract: TContract, state: PipelineChainState) {\n this.#contract = contract;\n this.#state = state;\n }\n\n /**\n * Internal helper that appends a pipeline stage and branches into a new\n * state-type. The fifth type parameter `NewN` carries the nested-path\n * shape forward. It defaults to `Record<string, never>` so stages that\n * fundamentally rewrite the document (`$group`, `$project`,\n * `$replaceRoot`, …) automatically disable the callable form of\n * `FieldAccessor` downstream. Additive stages (`match`, `addFields`,\n * `sort`, `lookup`, …) explicitly re-thread the current `N`.\n */\n #withStage<\n NewShape extends DocShape,\n NewU extends UpdateEnabled,\n NewF extends FindAndModifyEnabled,\n NewL extends LeadingMatch = 'past-leading',\n NewN extends NestedDocShape = Record<string, never>,\n >(stage: MongoPipelineStage): PipelineChain<TContract, NewShape, NewU, NewF, NewL, NewN> {\n return new PipelineChain<TContract, NewShape, NewU, NewF, NewL, NewN>(this.#contract, {\n ...this.#state,\n stages: [...this.#state.stages, stage],\n });\n }\n\n #writeMeta(): PlanMeta {\n return {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n };\n }\n\n // --- Identity stages ---\n\n /**\n * `$match`. `FindAndModifyEnabled` is always preserved. `UpdateEnabled` is\n * preserved only while the chain is still in the leading-`$match` prefix\n * (`L = 'leading'`); a `$match` that follows any non-`$match` stage\n * transitions to `L = 'past-leading'` and clears `UpdateEnabled`, since\n * `deconstructUpdateChain` can only peel leading `$match` stages into the\n * wire-command filter.\n */\n match(\n filter: MongoFilterExpr,\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;\n match(\n fn: (fields: FieldAccessor<Shape, N>) => MongoFilterExpr,\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;\n match(\n filterOrFn: MongoFilterExpr | ((fields: FieldAccessor<Shape, N>) => MongoFilterExpr),\n ): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N> {\n const filter =\n typeof filterOrFn === 'function' ? filterOrFn(createFieldAccessor<Shape, N>()) : filterOrFn;\n return this.#withStage<Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>(\n new MongoMatchStage(filter),\n );\n }\n\n /**\n * `$sort`. Clears `UpdateEnabled` (`update` has no per-document sort) but\n * preserves `FindAndModifyEnabled` (`findAndModify` has a `sort` slot).\n */\n sort(\n spec: SortSpec<Shape>,\n ): PipelineChain<TContract, Shape, 'update-cleared', F, 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', F, 'past-leading', N>(\n new MongoSortStage(spec as Record<string, 1 | -1>),\n );\n }\n\n /**\n * `$limit`. Clears both markers — `limit` is incompatible with the `update`\n * wire command, and `findAndModify` already implies single-document\n * semantics (so `.limit(...)` adds no meaning, only ambiguity).\n */\n limit(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoLimitStage(n),\n );\n }\n\n /**\n * `$skip`. Clears both markers — MongoDB's `findAndModify` wire command\n * has no `skip` slot, so `deconstructFindAndModifyChain` rejects any\n * `$skip` at runtime; keeping the marker `fam-cleared` makes the type\n * system reflect the same constraint (see ADR 201 marker table).\n */\n skip(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSkipStage(n),\n );\n }\n\n sample(\n n: number,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSampleStage(n),\n );\n }\n\n // --- Additive stages ---\n\n /**\n * `$addFields`. Preserves `UpdateEnabled` (representable as\n * update-with-pipeline `$set`); clears `FindAndModifyEnabled` (no analogue\n * in the find-and-modify wire commands). The nested-path shape `N` is\n * preserved — newly added flat fields are reachable via property access\n * (`f.newField`) but do not themselves carry nested structure.\n */\n addFields<NewFields extends Record<string, TypedAggExpr<DocField>>>(\n fn: (fields: FieldAccessor<Shape, N>) => NewFields,\n ): PipelineChain<\n TContract,\n Shape & ExtractDocShape<NewFields>,\n U,\n 'fam-cleared',\n 'past-leading',\n N\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const newFields = fn(accessor);\n const exprRecord: Record<string, MongoAggExpr> = {};\n for (const [key, typed] of Object.entries(newFields)) {\n exprRecord[key] = typed.node;\n }\n return this.#withStage<Shape & ExtractDocShape<NewFields>, U, 'fam-cleared', 'past-leading', N>(\n new MongoAddFieldsStage(exprRecord),\n );\n }\n\n /**\n * `$lookup`. Clears both markers — joins are not representable in either\n * the `update` or `findAndModify` wire commands. The original document's\n * nested-path shape `N` is preserved (the lookup adds a sidecar array\n * field; existing keys are untouched).\n *\n * The single callback receives a `from` callable that grounds the\n * foreign-root literal sequentially before the inner `on(...)`\n * callback is type-checked — see `lookup-builder.ts`. The resulting\n * `Shape` gains the `As` key as a `ModelArrayField<ModelName>` so\n * `ResolveRow` produces `Array<ForeignRow>` (with concrete leaf\n * types) instead of the legacy `unknown[]`.\n */\n lookup<RootName extends string, ModelName extends string, As extends string>(\n fn: (from: LookupFrom<TContract, Shape, N>) => LookupResult<RootName, ModelName, As>,\n ): PipelineChain<\n TContract,\n Shape & Record<As, ModelArrayField<ModelName>>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n > {\n const fromCallable = createLookupFrom<TContract, Shape, N>(this.#contract);\n const result = fn(fromCallable);\n const extracted = extractLookupResult(result, this.#contract);\n return this.#withStage<\n Shape & Record<As, ModelArrayField<ModelName>>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n >(\n new MongoLookupStage({\n from: extracted.foreignCollection,\n localField: extracted.localField,\n foreignField: extracted.foreignField,\n as: extracted.as,\n }),\n );\n }\n\n // --- Narrowing stages ---\n\n /**\n * `$project`. Preserves `UpdateEnabled` (representable as update-with-pipeline\n * `$project` / `$unset`); clears `FindAndModifyEnabled` (use `.project()` on\n * the result of `.build()` if both projection and find-and-modify are\n * needed — see spec).\n *\n * Resets the nested-path shape to `Record<string, never>` — projection\n * fundamentally rewrites the document, so dot-paths into the *source*\n * document are no longer meaningful downstream.\n */\n project<K extends keyof Shape & string>(\n ...keys: K[]\n ): PipelineChain<\n TContract,\n Pick<Shape, K | ('_id' extends keyof Shape ? '_id' : never)>,\n U,\n 'fam-cleared',\n 'past-leading'\n >;\n project<Spec extends Record<string, 1 | TypedAggExpr<DocField>>>(\n fn: (fields: FieldAccessor<Shape, N>) => Spec,\n ): PipelineChain<TContract, ProjectedShape<Shape, Spec>, U, 'fam-cleared', 'past-leading'>;\n project(\n ...args: unknown[]\n ): PipelineChain<TContract, DocShape, U, 'fam-cleared', 'past-leading'> {\n if (args.length === 1 && typeof args[0] === 'function') {\n const fn = args[0] as (\n fields: FieldAccessor<Shape, N>,\n ) => Record<string, 1 | TypedAggExpr<DocField>>;\n const accessor = createFieldAccessor<Shape, N>();\n const spec = fn(accessor);\n const projection: Record<string, MongoProjectionValue> = {};\n for (const [key, val] of Object.entries(spec)) {\n projection[key] = val === 1 ? 1 : (val as TypedAggExpr<DocField>).node;\n }\n return this.#withStage(new MongoProjectStage(projection));\n }\n const keys = args as string[];\n const projection: Record<string, 1> = {};\n for (const key of keys) {\n projection[key] = 1;\n }\n return this.#withStage(new MongoProjectStage(projection));\n }\n\n /**\n * `$unwind`. Clears both markers — array unrolling produces multiple output\n * documents per input, incompatible with both single-document update and\n * find-and-modify wire commands. The original `N` is preserved: unwind\n * replaces the unwound array slot with its element but leaves the rest\n * of the document structurally intact.\n */\n unwind<K extends keyof Shape & string>(\n field: K,\n options?: { preserveNullAndEmptyArrays?: boolean },\n ): PipelineChain<\n TContract,\n UnwoundShape<Shape, K>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n > {\n return this.#withStage<\n UnwoundShape<Shape, K>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading',\n N\n >(new MongoUnwindStage(`$${field}`, options?.preserveNullAndEmptyArrays ?? false));\n }\n\n // --- Replacement stages ---\n\n /**\n * `$group`. Clears both markers — group output bears no relation to source\n * documents; neither `update` nor `findAndModify` can consume it. Nested\n * path shape is reset (the source document's path tree is gone).\n */\n group<Spec extends GroupSpec>(\n fn: (fields: FieldAccessor<Shape, N>) => Spec,\n ): PipelineChain<\n TContract,\n GroupedDocShape<Spec>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const spec = fn(accessor);\n const { _id: groupIdExpr, ...rest } = spec;\n const groupId = groupIdExpr === null ? null : groupIdExpr.node;\n const accumulators: Record<string, MongoAggAccumulator> = {};\n for (const [key, typed] of Object.entries(rest)) {\n if (typed === null) {\n throw new Error(`group() field \"${key}\" must not be null. Only _id can be null.`);\n }\n if (typed.node.kind !== 'accumulator') {\n throw new Error(\n `group() field \"${key}\" must use an accumulator (e.g. acc.sum(), acc.count()). Got \"${typed.node.kind}\" expression.`,\n );\n }\n accumulators[key] = typed.node as MongoAggAccumulator;\n }\n return this.#withStage<GroupedDocShape<Spec>, 'update-cleared', 'fam-cleared'>(\n new MongoGroupStage(groupId, accumulators),\n );\n }\n\n /**\n * `$replaceRoot`. Preserves `UpdateEnabled` (representable as\n * update-with-pipeline `$replaceRoot`); clears `FindAndModifyEnabled`.\n * Nested path shape is reset — the replaced root has no relation to\n * the original document structure.\n */\n replaceRoot<NewShape extends DocShape>(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>,\n ): PipelineChain<TContract, NewShape, U, 'fam-cleared', 'past-leading'> {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage<NewShape, U, 'fam-cleared'>(new MongoReplaceRootStage(expr.node));\n }\n\n count<Field extends string>(\n field: Field,\n ): PipelineChain<\n TContract,\n Record<Field, { readonly codecId: 'mongo/double@1'; readonly nullable: false }>,\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n return this.#withStage(new MongoCountStage(field));\n }\n\n sortByCount<F2 extends DocField>(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<F2> | TypedAggExpr<F2>,\n ): PipelineChain<\n TContract,\n {\n _id: F2;\n count: { readonly codecId: 'mongo/double@1'; readonly nullable: false };\n },\n 'update-cleared',\n 'fam-cleared',\n 'past-leading'\n > {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage(new MongoSortByCountStage(expr.node));\n }\n\n // --- Filter stages ---\n\n /**\n * `$redact`. Preserves `UpdateEnabled`; clears `FindAndModifyEnabled`.\n * Shape- and nested-path-preserving (the document tree is unchanged).\n */\n redact(\n fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>,\n ): PipelineChain<TContract, Shape, U, 'fam-cleared', 'past-leading', N> {\n const accessor = createFieldAccessor<Shape, N>();\n const expr = fn(accessor);\n return this.#withStage<Shape, U, 'fam-cleared', 'past-leading', N>(\n new MongoRedactStage(expr.node),\n );\n }\n\n // --- Write terminals (output stages) ---\n\n /**\n * `$out` write terminal. Materialises the pipeline output into\n * `collection` (optionally in `db`), replacing any prior contents. Unlike\n * the other pipeline-stage methods, this **terminates** the chain — it\n * returns a `MongoQueryPlan` rather than another `PipelineChain`, since\n * `$out` must be the final stage and there is nothing further to chain.\n *\n * Lane is `mongo-query` (matching all other terminals in this package) so\n * middleware can dispatch on intent without inspecting the command.\n *\n * The result row stream is empty (`unknown` row type) — the data lives\n * in the destination collection, not the response.\n */\n out(collection: string, db?: string): MongoQueryPlan<unknown, AggregateCommand> {\n return this.#writeTerminal(new MongoOutStage(collection, db));\n }\n\n /**\n * `$merge` write terminal. Streams the pipeline output into the target\n * collection per the supplied merge semantics (`whenMatched` /\n * `whenNotMatched`). Like `out()`, terminates the chain — `$merge` must\n * be the final stage.\n */\n merge(options: {\n into: string | { db: string; coll: string };\n on?: string | ReadonlyArray<string>;\n whenMatched?: string | ReadonlyArray<MongoUpdatePipelineStage>;\n whenNotMatched?: string;\n }): MongoQueryPlan<unknown, AggregateCommand> {\n return this.#writeTerminal(new MongoMergeStage(options));\n }\n\n #writeTerminal(stage: MongoPipelineStage): MongoQueryPlan<unknown, AggregateCommand> {\n const pipeline = [...this.#state.stages, stage];\n const command = new AggregateCommand(this.#state.collection, pipeline);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n // --- Union stages ---\n\n unionWith(\n collection: string,\n pipeline?: ReadonlyArray<MongoPipelineStage>,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoUnionWithStage(collection, pipeline),\n );\n }\n\n // --- Bucketing stages ---\n\n bucket(options: {\n groupBy: MongoAggExpr;\n boundaries: ReadonlyArray<unknown>;\n default_?: unknown;\n output?: Record<string, MongoAggAccumulator>;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoBucketStage(options),\n );\n }\n\n bucketAuto(options: {\n groupBy: MongoAggExpr;\n buckets: number;\n output?: Record<string, MongoAggAccumulator>;\n granularity?: string;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoBucketAutoStage(options),\n );\n }\n\n // --- Geo stages ---\n\n geoNear(options: {\n near: unknown;\n distanceField: string;\n spherical?: boolean;\n maxDistance?: number;\n minDistance?: number;\n query?: MongoFilterExpr;\n key?: string;\n distanceMultiplier?: number;\n includeLocs?: string;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoGeoNearStage(options),\n );\n }\n\n // --- Multi-facet stages ---\n\n facet(\n facets: Record<string, ReadonlyArray<MongoPipelineStage>>,\n ): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(new MongoFacetStage(facets));\n }\n\n // --- Graph stages ---\n\n graphLookup(options: {\n from: string;\n startWith: MongoAggExpr;\n connectFromField: string;\n connectToField: string;\n as: string;\n maxDepth?: number;\n depthField?: string;\n restrictSearchWithMatch?: MongoFilterExpr;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoGraphLookupStage(options),\n );\n }\n\n // --- Window stages ---\n\n setWindowFields(options: {\n partitionBy?: MongoAggExpr;\n sortBy?: Record<string, 1 | -1>;\n output: Record<string, MongoWindowField>;\n }): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoSetWindowFieldsStage(options),\n );\n }\n\n densify(options: {\n field: string;\n partitionByFields?: ReadonlyArray<string>;\n range: MongoDensifyRange;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoDensifyStage(options),\n );\n }\n\n fill(options: {\n partitionBy?: MongoAggExpr;\n partitionByFields?: ReadonlyArray<string>;\n sortBy?: Record<string, 1 | -1>;\n output: Record<string, MongoFillOutput>;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoFillStage(options),\n );\n }\n\n // --- Search stages ---\n\n search(\n config: Record<string, unknown>,\n index?: string,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoSearchStage(config, index),\n );\n }\n\n searchMeta(\n config: Record<string, unknown>,\n index?: string,\n ): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<DocShape, 'update-cleared', 'fam-cleared'>(\n new MongoSearchMetaStage(config, index),\n );\n }\n\n vectorSearch(options: {\n index: string;\n path: string;\n queryVector: ReadonlyArray<number>;\n numCandidates: number;\n limit: number;\n filter?: Record<string, unknown>;\n }): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N> {\n return this.#withStage<Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>(\n new MongoVectorSearchStage(options),\n );\n }\n\n // --- Escape hatch ---\n\n pipe(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading'>;\n pipe<NewShape extends DocShape>(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'>;\n pipe<NewShape extends DocShape = Shape>(\n stage: MongoPipelineStage,\n ): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'> {\n return this.#withStage<NewShape, 'update-cleared', 'fam-cleared'>(stage);\n }\n\n // --- Pipeline-style write terminals (UpdateEnabled-gated) ---\n\n /**\n * No-arg `updateMany()`: deconstruct the chain into leading `$match`\n * stages (folded into the filter) and remaining stages (which must all\n * be valid pipeline-update stages). Available only when `U = 'update-ok'`.\n *\n * The optional callback parameter exists for subclass-override\n * compatibility with `FilteredCollection.updateMany(updaterFn)` — TS's\n * strict override check requires the parent's parameter to accept at\n * least what the child's signature does. A runtime guard throws if a\n * callback is actually passed on a bare `PipelineChain`. Note that\n * because nothing in the public surface transitions `U` from\n * `'update-cleared'` (the initial state on `CollectionHandle` /\n * `FilteredCollection`) back to `'update-ok'`, the no-arg form is\n * reachable only via explicit type casts in internal tests — the\n * callback-form \"type hole\" is therefore not reachable from user\n * code. See `docs/architecture docs/adrs/ADR 201 - State-machine\n * pattern for typed DSL builders.md` for the marker-transition table.\n */\n updateMany(\n this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>,\n updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n if (updaterFn !== undefined) {\n throw new Error(\n 'updateMany() on a PipelineChain expects no arguments — the chain itself is the update pipeline. ' +\n 'To update with an operator callback, call .updateMany(fn) on a FilteredCollection (i.e. after .match()).',\n );\n }\n const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);\n const command = new UpdateManyCommand(this.#state.collection, filter, updatePipeline);\n return { collection: this.#state.collection, command, meta: this.#writeMeta() };\n }\n\n /**\n * No-arg `updateOne()`: same as `updateMany()` but maps to a single-doc\n * update. Carries the same optional-callback/subclass-compat caveat\n * documented above — the callback form is reachable only via forced\n * casts in internal tests.\n */\n updateOne(\n this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>,\n updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n if (updaterFn !== undefined) {\n throw new Error(\n 'updateOne() on a PipelineChain expects no arguments — the chain itself is the update pipeline. ' +\n 'To update with an operator callback, call .updateOne(fn) on a FilteredCollection (i.e. after .match()).',\n );\n }\n const { filter, updatePipeline } = deconstructUpdateChain(this.#state.stages);\n const command = new UpdateOneCommand(this.#state.collection, filter, updatePipeline);\n return { collection: this.#state.collection, command, meta: this.#writeMeta() };\n }\n\n // --- Find-and-modify terminals (marker-gated) ---\n\n /**\n * Find a single document matching the accumulated pipeline (which must\n * consist solely of leading `$match` stages followed by at most one\n * `$sort`) and apply `updaterFn`. Available only when\n * `FindAndModifyEnabled` is `'fam-ok'` — stages that clear the marker\n * (including `$skip`, which MongoDB's `findAndModify` has no slot for)\n * make this method invisible at the type level.\n *\n * The pipeline stages are deconstructed into the wire command's `filter`\n * and `sort` slots. If any non-deconstructable stage is present, a\n * runtime error is thrown as a defensive check (the type system should\n * prevent this).\n */\n findOneAndUpdate(\n this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>,\n updaterFn: (fields: FieldAccessor<Shape, N>) => UpdaterResult,\n opts: { readonly upsert?: boolean; readonly returnDocument?: 'before' | 'after' } = {},\n ): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract> | null,\n FindOneAndUpdateCommand\n > {\n const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);\n const accessor = createFieldAccessor<Shape, N>();\n const items = updaterFn(accessor);\n const update = resolveUpdaterResult(items);\n const command = new FindOneAndUpdateCommand(\n this.#state.collection,\n filter,\n update,\n opts.upsert ?? false,\n sort,\n opts.returnDocument ?? 'after',\n );\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n /**\n * Find a single document matching the accumulated pipeline and delete it.\n * Same marker gating and deconstruction as `findOneAndUpdate`.\n */\n findOneAndDelete(\n this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>,\n ): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract> | null,\n FindOneAndDeleteCommand\n > {\n const { filter, sort } = deconstructFindAndModifyChain(this.#state.stages);\n const command = new FindOneAndDeleteCommand(this.#state.collection, filter, sort);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n };\n return { collection: this.#state.collection, command, meta };\n }\n\n // --- Read terminals ---\n\n /**\n * Materialise the chain as a `MongoQueryPlan` wrapping an `AggregateCommand`.\n */\n build(): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract>,\n AggregateCommand\n > {\n const command = new AggregateCommand(this.#state.collection, this.#state.stages);\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: this.#state.storageHash,\n lane: 'mongo-query',\n };\n const modelName = this.#state.modelName;\n const contractNarrow = this.#contract as MongoContract;\n let resultShape: MongoResultShape | undefined;\n if (modelName !== undefined) {\n if (pipelineSupportsFlatResultShape(this.#state.stages)) {\n const model = contractNarrow.models[modelName] as MongoModelDefinition | undefined;\n resultShape = model ? contractModelToMongoResultShape(model) : { kind: 'unknown' as const };\n } else {\n resultShape = { kind: 'unknown' as const };\n }\n }\n return {\n collection: this.#state.collection,\n command,\n meta,\n ...ifDefined('resultShape', resultShape),\n };\n }\n\n /**\n * Alias for `build()` — surfaces the read intent at the call site.\n */\n aggregate(): MongoQueryPlan<\n ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract>,\n AggregateCommand\n > {\n return this.build();\n }\n}\n\ninterface DeconstructedFindAndModify {\n filter: MongoFilterExpr;\n sort: Record<string, 1 | -1> | undefined;\n}\n\n/**\n * Walk the accumulated pipeline stages and extract the `filter` and `sort`\n * slots for a `findOneAndUpdate` / `findOneAndDelete` wire command.\n *\n * The helper accepts exactly the canonical shape `match+ -> sort?` and\n * nothing else:\n *\n * - one or more `$match` stages (AND-folded into a single filter),\n * - optionally followed by a single `$sort` stage.\n *\n * Anything else — a `$sort` before `$match`, multiple `$sort` stages, a\n * `$skip` stage, or any non-`$match`/`$sort` stage — is rejected with a\n * clear error. The type system already prevents most of these at compile\n * time via the `FindAndModifyEnabled` marker, but the runtime check\n * guards the escape hatches (e.g. `.pipe(...)`) and future marker gaps.\n *\n * `$skip` is rejected outright because MongoDB's `findAndModify` command\n * has no skip slot; a silently-dropped skip is a latent correctness bug\n * waiting to happen. (A02 removed skip from the typed AST for the same\n * reason.)\n */\nfunction deconstructFindAndModifyChain(\n stages: ReadonlyArray<MongoPipelineStage>,\n): DeconstructedFindAndModify {\n const matchFilters: MongoFilterExpr[] = [];\n let sort: Record<string, 1 | -1> | undefined;\n let seenNonMatch = false;\n\n for (const stage of stages) {\n if (stage instanceof MongoMatchStage) {\n if (seenNonMatch) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete requires the canonical $match+ -> $sort? shape, ' +\n 'but a $match stage was found after a $sort. Re-order the chain so every .match() ' +\n 'call precedes the .sort() call.',\n );\n }\n matchFilters.push(stage.filter);\n } else if (stage instanceof MongoSortStage) {\n if (sort !== undefined) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete accepts at most one $sort stage; drop the extra ' +\n '.sort() call or combine the keys into a single sort spec.',\n );\n }\n sort = { ...stage.sort };\n seenNonMatch = true;\n } else if (stage instanceof MongoSkipStage) {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete does not support .skip() — MongoDB findAndModify ' +\n 'has no skip slot. Remove the .skip() call, or use .aggregate()/.build() if the ' +\n 'chain needs skip semantics.',\n );\n } else {\n throw new Error(\n 'findOneAndUpdate/findOneAndDelete requires the canonical $match+ -> $sort? shape, ' +\n `but encountered a '${stage.constructor.name}' stage. ` +\n 'This is likely a bug — the type system should have prevented this chain.',\n );\n }\n }\n\n if (matchFilters.length === 0) {\n throw new Error('findOneAndUpdate/findOneAndDelete requires at least one .match() call.');\n }\n const first = matchFilters[0];\n if (first === undefined) {\n throw new Error('Unreachable: matchFilters.length > 0 but first is undefined');\n }\n const filter: MongoFilterExpr = matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters);\n\n return { filter, sort };\n}\n\ninterface DeconstructedUpdate {\n filter: MongoFilterExpr;\n updatePipeline: ReadonlyArray<MongoUpdatePipelineStage>;\n}\n\n/**\n * Walk the accumulated pipeline stages: leading `$match` stages become the\n * filter, remaining stages must all be valid `MongoUpdatePipelineStage`\n * members (currently `$addFields`, `$project`, `$replaceRoot`).\n */\nfunction deconstructUpdateChain(stages: ReadonlyArray<MongoPipelineStage>): DeconstructedUpdate {\n const matchFilters: MongoFilterExpr[] = [];\n let boundary = 0;\n\n for (const stage of stages) {\n if (!(stage instanceof MongoMatchStage)) break;\n matchFilters.push(stage.filter);\n boundary++;\n }\n\n if (matchFilters.length === 0) {\n throw new Error('No-arg updateMany/updateOne requires at least one .match() call.');\n }\n\n const remaining = stages.slice(boundary);\n if (remaining.length === 0) {\n throw new Error(\n 'No-arg updateMany/updateOne requires at least one pipeline-update stage ' +\n '(e.g. .addFields(), .project(), .replaceRoot()) after the .match() stages.',\n );\n }\n\n const updatePipeline: MongoUpdatePipelineStage[] = [];\n for (const stage of remaining) {\n if (\n stage instanceof MongoAddFieldsStage ||\n stage instanceof MongoProjectStage ||\n stage instanceof MongoReplaceRootStage\n ) {\n updatePipeline.push(stage);\n } else {\n throw new Error(\n `No-arg updateMany/updateOne: encountered non-update stage '${stage.constructor.name}' ` +\n 'after the leading $match stages. Only $addFields/$set, $project/$unset, ' +\n 'and $replaceRoot/$replaceWith stages are valid in an update pipeline.',\n );\n }\n }\n\n const first = matchFilters[0];\n if (first === undefined) {\n throw new Error('Unreachable: matchFilters.length > 0 but first is undefined');\n }\n const filter: MongoFilterExpr = matchFilters.length === 1 ? first : MongoAndExpr.of(matchFilters);\n\n return { filter, updatePipeline };\n}\n","import type { MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';\nimport {\n MongoAggCond,\n MongoAggLiteral,\n MongoAggOperator,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type {\n ArrayField,\n BooleanField,\n DateField,\n DocField,\n LiteralValue,\n NullableDocField,\n NumericField,\n StringField,\n TypedAggExpr,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Internal factory helpers\n// ---------------------------------------------------------------------------\n\nfunction numericExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return {\n _field: { codecId: 'mongo/double@1', nullable: false } as NumericField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction numericUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return {\n _field: { codecId: 'mongo/double@1', nullable: false } as NumericField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction stringExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<StringField> {\n return {\n _field: { codecId: 'mongo/string@1', nullable: false } as StringField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction stringUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return {\n _field: { codecId: 'mongo/string@1', nullable: false } as StringField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction booleanExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<BooleanField> {\n return {\n _field: { codecId: 'mongo/bool@1', nullable: false } as BooleanField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction booleanUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return {\n _field: { codecId: 'mongo/bool@1', nullable: false } as BooleanField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction dateUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<DateField> {\n return {\n _field: { codecId: 'mongo/date@1', nullable: false } as DateField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction arrayExpr(op: string, args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return {\n _field: { codecId: 'mongo/array@1', nullable: false } as ArrayField,\n node: MongoAggOperator.of(\n op,\n args.map((a) => a.node),\n ),\n };\n}\n\nfunction arrayUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return {\n _field: { codecId: 'mongo/array@1', nullable: false } as ArrayField,\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction docUnaryExpr(op: string, arg: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return {\n _field: { codecId: arg._field.codecId, nullable: false },\n node: MongoAggOperator.of(op, arg.node),\n };\n}\n\nfunction namedArgsExpr<F extends DocField>(\n op: string,\n args: Readonly<Record<string, TypedAggExpr<DocField> | undefined>>,\n _field: F,\n): TypedAggExpr<F> {\n const nodeArgs: Record<string, MongoAggExpr> = {};\n for (const [key, val] of Object.entries(args)) {\n if (val !== undefined) {\n nodeArgs[key] = val.node;\n }\n }\n return { _field, node: MongoAggOperator.of(op, nodeArgs) };\n}\n\nconst NUMERIC: NumericField = { codecId: 'mongo/double@1', nullable: false } as NumericField;\nconst STRING: StringField = { codecId: 'mongo/string@1', nullable: false } as StringField;\nconst BOOLEAN: BooleanField = { codecId: 'mongo/bool@1', nullable: false } as BooleanField;\nconst DATE: DateField = { codecId: 'mongo/date@1', nullable: false } as DateField;\nconst ARRAY: ArrayField = { codecId: 'mongo/array@1', nullable: false } as ArrayField;\nconst DOC: DocField = { codecId: 'mongo/document@1', nullable: false };\n\nfunction literal(value: string): TypedAggExpr<StringField>;\nfunction literal(value: number): TypedAggExpr<NumericField>;\nfunction literal(value: boolean): TypedAggExpr<BooleanField>;\nfunction literal(value: Date): TypedAggExpr<DateField>;\nfunction literal<F extends DocField>(value: LiteralValue<F>): TypedAggExpr<F>;\nfunction literal(value: unknown): TypedAggExpr<DocField> {\n return { _field: undefined as never, node: MongoAggLiteral.of(value) };\n}\n\n// ---------------------------------------------------------------------------\n// Public helpers\n// ---------------------------------------------------------------------------\n\nexport const fn = {\n // -- Arithmetic (existing) ------------------------------------------------\n\n add(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return numericExpr('$add', args);\n },\n\n subtract(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$subtract', [a, b]);\n },\n\n multiply(...args: TypedAggExpr<DocField>[]): TypedAggExpr<NumericField> {\n return numericExpr('$multiply', args);\n },\n\n divide(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$divide', [a, b]);\n },\n\n // -- String (existing) ----------------------------------------------------\n\n concat(...args: TypedAggExpr<DocField>[]): TypedAggExpr<StringField> {\n return stringExpr('$concat', args);\n },\n\n toLower(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toLower', a);\n },\n\n toUpper(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toUpper', a);\n },\n\n // -- Size (existing) ------------------------------------------------------\n\n size(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$size', a);\n },\n\n // -- Control flow (existing) ----------------------------------------------\n\n cond<F extends DocField>(\n condition: MongoAggExpr,\n thenExpr: TypedAggExpr<F>,\n elseExpr: TypedAggExpr<DocField>,\n ): TypedAggExpr<F> {\n return {\n _field: thenExpr._field,\n node: new MongoAggCond(condition, thenExpr.node, elseExpr.node),\n };\n },\n\n literal,\n\n // -- Date helpers ---------------------------------------------------------\n\n year(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$year', a);\n },\n month(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$month', a);\n },\n dayOfMonth(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$dayOfMonth', a);\n },\n hour(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$hour', a);\n },\n minute(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$minute', a);\n },\n second(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$second', a);\n },\n millisecond(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$millisecond', a);\n },\n dateToString(args: {\n date: TypedAggExpr<DateField>;\n format?: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$dateToString', args, STRING);\n },\n dateFromString(args: {\n dateString: TypedAggExpr<StringField>;\n format?: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n onError?: TypedAggExpr<DocField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateFromString', args, DATE);\n },\n dateDiff(args: {\n startDate: TypedAggExpr<DateField>;\n endDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n timezone?: TypedAggExpr<StringField>;\n startOfWeek?: TypedAggExpr<StringField>;\n }): TypedAggExpr<NumericField> {\n return namedArgsExpr('$dateDiff', args, NUMERIC);\n },\n dateAdd(args: {\n startDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n amount: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateAdd', args, DATE);\n },\n dateSubtract(args: {\n startDate: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n amount: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateSubtract', args, DATE);\n },\n dateTrunc(args: {\n date: TypedAggExpr<DateField>;\n unit: TypedAggExpr<StringField>;\n binSize?: TypedAggExpr<NumericField>;\n timezone?: TypedAggExpr<StringField>;\n startOfWeek?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DateField> {\n return namedArgsExpr('$dateTrunc', args, DATE);\n },\n\n // -- String helpers -------------------------------------------------------\n\n substr(\n str: TypedAggExpr<DocField>,\n start: TypedAggExpr<DocField>,\n length: TypedAggExpr<DocField>,\n ): TypedAggExpr<StringField> {\n return stringExpr('$substr', [str, start, length]);\n },\n substrBytes(\n str: TypedAggExpr<DocField>,\n start: TypedAggExpr<DocField>,\n count: TypedAggExpr<DocField>,\n ): TypedAggExpr<StringField> {\n return stringExpr('$substrBytes', [str, start, count]);\n },\n trim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$trim', args, STRING);\n },\n ltrim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$ltrim', args, STRING);\n },\n rtrim(args: {\n input: TypedAggExpr<StringField>;\n chars?: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$rtrim', args, STRING);\n },\n split(str: TypedAggExpr<DocField>, delimiter: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayExpr('$split', [str, delimiter]);\n },\n strLenCP(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$strLenCP', a);\n },\n strLenBytes(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$strLenBytes', a);\n },\n regexMatch(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<BooleanField> {\n return namedArgsExpr('$regexMatch', args, BOOLEAN);\n },\n regexFind(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$regexFind', args, DOC);\n },\n regexFindAll(args: {\n input: TypedAggExpr<StringField>;\n regex: TypedAggExpr<StringField>;\n options?: TypedAggExpr<StringField>;\n }): TypedAggExpr<ArrayField> {\n return namedArgsExpr('$regexFindAll', args, ARRAY);\n },\n replaceOne(args: {\n input: TypedAggExpr<StringField>;\n find: TypedAggExpr<StringField>;\n replacement: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$replaceOne', args, STRING);\n },\n replaceAll(args: {\n input: TypedAggExpr<StringField>;\n find: TypedAggExpr<StringField>;\n replacement: TypedAggExpr<StringField>;\n }): TypedAggExpr<StringField> {\n return namedArgsExpr('$replaceAll', args, STRING);\n },\n\n // -- Comparison helpers ---------------------------------------------------\n\n cmp(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericExpr('$cmp', [a, b]);\n },\n eq(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$eq', [a, b]);\n },\n ne(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$ne', [a, b]);\n },\n gt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$gt', [a, b]);\n },\n gte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$gte', [a, b]);\n },\n lt(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$lt', [a, b]);\n },\n lte(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$lte', [a, b]);\n },\n\n // -- Array helpers --------------------------------------------------------\n\n arrayElemAt(\n arr: TypedAggExpr<DocField>,\n idx: TypedAggExpr<DocField>,\n ): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$arrayElemAt', [arr.node, idx.node]),\n };\n },\n concatArrays(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$concatArrays', args);\n },\n firstElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$first', a.node),\n };\n },\n lastElem(a: TypedAggExpr<DocField>): TypedAggExpr<NullableDocField> {\n return {\n _field: { codecId: DOC.codecId, nullable: true },\n node: MongoAggOperator.of('$last', a.node),\n };\n },\n isIn(elem: TypedAggExpr<DocField>, arr: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$in', [elem, arr]);\n },\n indexOfArray(\n arr: TypedAggExpr<DocField>,\n value: TypedAggExpr<DocField>,\n ...rest: TypedAggExpr<DocField>[]\n ): TypedAggExpr<NumericField> {\n return numericExpr('$indexOfArray', [arr, value, ...rest]);\n },\n isArray(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$isArray', a);\n },\n reverseArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayUnaryExpr('$reverseArray', a);\n },\n slice(arr: TypedAggExpr<DocField>, ...rest: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$slice', [arr, ...rest]);\n },\n zip(args: {\n inputs: TypedAggExpr<ArrayField>[];\n useLongestLength?: TypedAggExpr<BooleanField>;\n defaults?: TypedAggExpr<ArrayField>;\n }): TypedAggExpr<ArrayField> {\n const nodeArgs: Record<string, MongoAggExpr | ReadonlyArray<MongoAggExpr>> = {\n inputs: args.inputs.map((a) => a.node),\n };\n if (args.useLongestLength) nodeArgs['useLongestLength'] = args.useLongestLength.node;\n if (args.defaults) nodeArgs['defaults'] = args.defaults.node;\n return { _field: ARRAY, node: MongoAggOperator.of('$zip', nodeArgs) };\n },\n range(\n start: TypedAggExpr<DocField>,\n end: TypedAggExpr<DocField>,\n step: TypedAggExpr<DocField>,\n ): TypedAggExpr<ArrayField> {\n return arrayExpr('$range', [start, end, step]);\n },\n\n // -- Set helpers ----------------------------------------------------------\n\n setUnion(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$setUnion', args);\n },\n setIntersection(...args: TypedAggExpr<DocField>[]): TypedAggExpr<ArrayField> {\n return arrayExpr('$setIntersection', args);\n },\n setDifference(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayExpr('$setDifference', [a, b]);\n },\n setEquals(...args: TypedAggExpr<DocField>[]): TypedAggExpr<BooleanField> {\n return booleanExpr('$setEquals', args);\n },\n setIsSubset(a: TypedAggExpr<DocField>, b: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanExpr('$setIsSubset', [a, b]);\n },\n anyElementTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$anyElementTrue', a);\n },\n allElementsTrue(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$allElementsTrue', a);\n },\n\n // -- Type helpers ---------------------------------------------------------\n\n typeOf(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$type', a);\n },\n convert(args: {\n input: TypedAggExpr<DocField>;\n to: TypedAggExpr<StringField | NumericField>;\n onError?: TypedAggExpr<DocField>;\n onNull?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$convert', args, DOC);\n },\n toInt(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toInt', a);\n },\n toLong(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toLong', a);\n },\n toDouble(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toDouble', a);\n },\n toDecimal(a: TypedAggExpr<DocField>): TypedAggExpr<NumericField> {\n return numericUnaryExpr('$toDecimal', a);\n },\n toString_(a: TypedAggExpr<DocField>): TypedAggExpr<StringField> {\n return stringUnaryExpr('$toString', a);\n },\n toObjectId(a: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return docUnaryExpr('$toObjectId', a);\n },\n toBool(a: TypedAggExpr<DocField>): TypedAggExpr<BooleanField> {\n return booleanUnaryExpr('$toBool', a);\n },\n toDate(a: TypedAggExpr<DocField>): TypedAggExpr<DateField> {\n return dateUnaryExpr('$toDate', a);\n },\n\n // -- Object helpers -------------------------------------------------------\n\n objectToArray(a: TypedAggExpr<DocField>): TypedAggExpr<ArrayField> {\n return arrayUnaryExpr('$objectToArray', a);\n },\n arrayToObject(a: TypedAggExpr<DocField>): TypedAggExpr<DocField> {\n return { _field: DOC, node: MongoAggOperator.of('$arrayToObject', a.node) };\n },\n getField(args: {\n field: TypedAggExpr<StringField>;\n input?: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$getField', args, DOC);\n },\n setField(args: {\n field: TypedAggExpr<StringField>;\n input: TypedAggExpr<DocField>;\n value: TypedAggExpr<DocField>;\n }): TypedAggExpr<DocField> {\n return namedArgsExpr('$setField', args, DOC);\n },\n};\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n ExtractMongoCodecTypes,\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type {\n DeleteResult,\n InsertManyResult,\n InsertOneResult,\n MongoFilterExpr,\n MongoQueryPlan,\n MongoUpdateSpec,\n UpdateResult,\n} from '@prisma-next/mongo-query-ast/execution';\nimport {\n DeleteManyCommand,\n DeleteOneCommand,\n FindOneAndDeleteCommand,\n FindOneAndUpdateCommand,\n InsertManyCommand,\n InsertOneCommand,\n MongoAndExpr,\n MongoExistsExpr,\n MongoMatchStage,\n UpdateManyCommand,\n UpdateOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport { PipelineChain } from './builder';\nimport { createFieldAccessor, type FieldAccessor } from './field-accessor';\nimport type { ModelNestedShape, NestedDocShape } from './resolve-path';\nimport type { ModelToDocShape, ResolveRow } from './types';\nimport { resolveUpdaterResult, type UpdaterResult } from './update-ops';\n\n/**\n * \"Match-all\" filter used by the unqualified-write terminals\n * (`updateAll`/`deleteAll`). The canonical representation is still\n * undecided — `MongoAndExpr` with an empty conjunction and a dedicated\n * `MongoMatchAllExpr` node are both candidates. For now we use\n * `_id $exists: true`, which is trivially true on every document and\n * avoids introducing a new AST node before the wider question is\n * resolved. Centralised so the eventual switch is a one-line change.\n */\nfunction matchAllFilter(): MongoFilterExpr {\n return MongoExistsExpr.exists('_id');\n}\n\n/**\n * Resolve an updater callback into a `MongoUpdateSpec` (either the folded\n * operator object or a pipeline-stage array). Centralised so all write\n * terminals share the same fold / dispatch semantics.\n */\nfunction resolveUpdaterCallback<\n Shape extends ModelToDocShape<MongoContract, string>,\n Nested extends NestedDocShape,\n>(updaterFn: (fields: FieldAccessor<Shape, Nested>) => UpdaterResult): MongoUpdateSpec {\n const accessor = createFieldAccessor<Shape, Nested>();\n const items = updaterFn(accessor);\n return resolveUpdaterResult(items);\n}\n\n/**\n * Build the `PlanMeta` envelope shared by every write terminal in this\n * package. Lane is `mongo-query` (single lane for all query-builder terminals)\n * so middleware can dispatch on intent without inspecting the command.\n */\nfunction writeMeta(storageHash: string): PlanMeta {\n return {\n target: 'mongo',\n storageHash,\n lane: 'mongo-query',\n };\n}\n\n/**\n * Root state of the query-builder state machine. Returned from\n * `mongoQuery(...).from(name)` and bound to a single collection.\n *\n * Inherits the entire pipeline-stage surface from `PipelineChain` (since an\n * empty `CollectionHandle` is observably an empty pipeline). Adds:\n *\n * - `match(...)` — overridden to transition to `FilteredCollection`, which\n * accumulates filters for eventual splatting into write/find-and-modify\n * wire commands.\n * - **Insert / unqualified-write methods** (M2): `insertOne`, `insertMany`,\n * `updateAll`, `deleteAll`. These live *only* here — the corresponding\n * methods are absent from `FilteredCollection`, so a caller cannot\n * accidentally produce an unqualified write by forgetting to `.match(...)`\n * later in the chain. Bodies land in M2.\n */\nexport class CollectionHandle<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n ModelName extends keyof TContract['models'] & string,\n> extends PipelineChain<\n TContract,\n ModelToDocShape<TContract, ModelName>,\n 'update-cleared',\n 'fam-cleared',\n 'leading',\n ModelNestedShape<TContract, ModelName>\n> {\n readonly #ctx: BindingContext<TContract>;\n readonly #modelName: ModelName;\n\n constructor(ctx: BindingContext<TContract>, modelName: ModelName) {\n super(ctx.contract, {\n collection: ctx.collection,\n stages: [],\n storageHash: ctx.storageHash,\n modelName: modelName as string,\n });\n this.#ctx = ctx;\n this.#modelName = modelName;\n }\n\n /**\n * Bound model name. Exposed so type tests can assert the binding without\n * flipping into a pipeline. Not part of the public-API contract.\n */\n get _modelName(): ModelName {\n return this.#modelName;\n }\n\n /**\n * Begin accumulating a filter. Transitions to `FilteredCollection`.\n *\n * Overrides `PipelineChain.match` (which appends another `$match` stage\n * and stays in the chain). The two implementations are semantically\n * equivalent for the read terminal — multiple `$match` stages AND-fold in\n * Mongo — but `FilteredCollection` makes the accumulated filter\n * addressable for the write/find-and-modify terminals landing in M2/M3.\n */\n override match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;\n override match(\n fn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n ): FilteredCollection<TContract, ModelName>;\n override match(\n filterOrFn:\n | MongoFilterExpr\n | ((\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr),\n ): FilteredCollection<TContract, ModelName> {\n const resolved =\n typeof filterOrFn === 'function'\n ? filterOrFn(\n createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(),\n )\n : filterOrFn;\n return new FilteredCollection<TContract, ModelName>(this.#ctx, this.#modelName, [resolved]);\n }\n\n // --- Inserts ---\n\n /**\n * Insert a single document. Document fields are passed straight through to\n * the wire `InsertOneCommand` — codec normalisation happens at the\n * adapter/driver boundary, identically to the SQL builder (see Open Item\n * #14 confirmation in the design conversation).\n *\n * Returns a `MongoQueryPlan<InsertOneResult>` whose row stream yields a\n * single result document with the server-assigned `insertedId`.\n */\n insertOne(\n document: Record<string, MongoValue>,\n ): MongoQueryPlan<InsertOneResult, InsertOneCommand> {\n const command = new InsertOneCommand(this.#ctx.collection, document);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Insert a batch of documents. Order is preserved in the returned\n * `insertedIds` array.\n */\n insertMany(\n documents: ReadonlyArray<Record<string, MongoValue>>,\n ): MongoQueryPlan<InsertManyResult, InsertManyCommand> {\n if (documents.length === 0) {\n throw new Error('insertMany() requires at least one document.');\n }\n const command = new InsertManyCommand(this.#ctx.collection, documents);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Unqualified writes ---\n\n /**\n * Update *every* document in the collection. Lives only on\n * `CollectionHandle` — the corresponding method is intentionally absent\n * from `FilteredCollection` so a caller cannot accidentally produce an\n * unqualified write by forgetting to `.match(...)` first. Pair with\n * `.match(...).updateMany(...)` for the filtered case.\n */\n updateAll(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateManyCommand(this.#ctx.collection, matchAllFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete *every* document in the collection. See `updateAll` for the\n * rationale around the unqualified-write surface being limited to this\n * state class.\n */\n deleteAll(): MongoQueryPlan<DeleteResult, DeleteManyCommand> {\n const command = new DeleteManyCommand(this.#ctx.collection, matchAllFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Upserts ---\n\n /**\n * Insert-or-update the document matching `filterFn`. The filter is\n * mandatory (vs. `updateAll`'s tautological match) because an upsert\n * without a discriminating predicate would either match every existing\n * document or insert an indistinguishable new one.\n *\n * Maps to `UpdateOneCommand` with `upsert: true`. The driver inserts a\n * new document derived from the filter equality fields plus the update\n * spec when no match is found; otherwise updates the matched document.\n */\n upsertOne(\n filterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const accessor = createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >();\n const filter = filterFn(accessor);\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, filter, update, true);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n}\n\n/**\n * State reached after one or more `.match(...)` calls on `CollectionHandle`.\n *\n * Inherits the pipeline-stage surface from `PipelineChain`, with the\n * accumulated filters baked in as a leading `$match` stage on the underlying\n * pipeline state. This means read-terminal output (`.aggregate()` /\n * `.build()`) and any subsequent pipeline-stage chain see the filtered\n * collection as input — the read story works through pure inheritance.\n *\n * Adds:\n *\n * - `match(...)` — pushes another `$match` stage *and* records the filter in\n * the accumulator, so the eventual write/find-and-modify terminal can\n * splat the AND-folded filter into the wire command's `filter` slot.\n * - **Filtered writes** (M2): `updateMany`, `updateOne`, `deleteMany`,\n * `deleteOne`, `upsertOne`. Stubbed in M1. (Upsert-many is an open\n * question in the spec — see TML-2267 — and is intentionally absent.)\n * - **Find-and-modify** (M3): `findOneAndUpdate`, `findOneAndDelete`.\n * Stubbed in M1.\n *\n * Notably *does not* expose `insertOne`/`insertMany`/`updateAll`/`deleteAll`\n * — those are insert or unqualified-write operations that are nonsense\n * after a filter has been applied.\n */\nexport class FilteredCollection<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n ModelName extends keyof TContract['models'] & string,\n> extends PipelineChain<\n TContract,\n ModelToDocShape<TContract, ModelName>,\n 'update-cleared',\n 'fam-cleared',\n 'leading',\n ModelNestedShape<TContract, ModelName>\n> {\n readonly #ctx: BindingContext<TContract>;\n readonly #modelName: ModelName;\n readonly #filters: ReadonlyArray<MongoFilterExpr>;\n\n constructor(\n ctx: BindingContext<TContract>,\n modelName: ModelName,\n filters: ReadonlyArray<MongoFilterExpr>,\n ) {\n if (filters.length === 0) {\n throw new Error('FilteredCollection requires at least one accumulated filter');\n }\n const first = filters[0];\n if (first === undefined) {\n throw new Error('FilteredCollection: unreachable empty-filters branch');\n }\n const leading = filters.length === 1 ? first : foldAnd(filters);\n super(ctx.contract, {\n collection: ctx.collection,\n stages: [new MongoMatchStage(leading)],\n storageHash: ctx.storageHash,\n modelName: modelName as string,\n });\n this.#ctx = ctx;\n this.#modelName = modelName;\n this.#filters = filters;\n }\n\n get _modelName(): ModelName {\n return this.#modelName;\n }\n\n /**\n * Accumulated filter list. Exposed for the M2/M3 write/find-and-modify\n * terminals to splat into wire-command `filter` slots; not part of the\n * public-API contract.\n */\n get _filters(): ReadonlyArray<MongoFilterExpr> {\n return this.#filters;\n }\n\n /**\n * Append another filter to the accumulator. Returns a new\n * `FilteredCollection` whose underlying pipeline rebuilds the leading\n * `$match` from the AND-folded accumulator (rather than appending a\n * second `$match` stage), so the write/find-and-modify terminals see a\n * single authoritative filter expression.\n */\n override match(filter: MongoFilterExpr): FilteredCollection<TContract, ModelName>;\n override match(\n fn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr,\n ): FilteredCollection<TContract, ModelName>;\n override match(\n filterOrFn:\n | MongoFilterExpr\n | ((\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => MongoFilterExpr),\n ): FilteredCollection<TContract, ModelName> {\n const resolved =\n typeof filterOrFn === 'function'\n ? filterOrFn(\n createFieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(),\n )\n : filterOrFn;\n return new FilteredCollection<TContract, ModelName>(this.#ctx, this.#modelName, [\n ...this.#filters,\n resolved,\n ]);\n }\n\n // --- Filtered writes ---\n\n /**\n * AND-fold the accumulated filters into a single `MongoFilterExpr` for\n * splatting into a write/find-and-modify wire command's `filter` slot.\n * Length-1 short-circuits to avoid a redundant `$and` wrapper.\n */\n #foldedFilter(): MongoFilterExpr {\n const first = this.#filters[0];\n if (first === undefined) {\n throw new Error('FilteredCollection: invariant violated — empty filter accumulator');\n }\n return this.#filters.length === 1 ? first : foldAnd(this.#filters);\n }\n\n /**\n * Update every matching document. `updaterFn` receives a `FieldAccessor`\n * and returns an array of `TypedUpdateOp` (e.g. `[f.amount.inc(1),\n * f.status.set('done')]`). Operators are folded into the wire-format\n * update spec by `foldUpdateOps`, which throws on operator+path\n * collisions.\n */\n override updateMany(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateManyCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateManyCommand(this.#ctx.collection, this.#foldedFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Update at most one matching document. The driver picks the document\n * (typically the first one matched by the underlying scan); no ordering\n * guarantee is implied — chain `.sort(...)` and use the M3\n * `.findOneAndUpdate(...)` terminal when ordering matters.\n */\n override updateOne(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete every matching document.\n */\n deleteMany(): MongoQueryPlan<DeleteResult, DeleteManyCommand> {\n const command = new DeleteManyCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Delete at most one matching document. See the `updateOne` note about\n * driver-chosen victim selection.\n */\n deleteOne(): MongoQueryPlan<DeleteResult, DeleteOneCommand> {\n const command = new DeleteOneCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Upserts ---\n\n /**\n * Insert-or-update against the accumulated filter. Maps to\n * `UpdateOneCommand` with `upsert: true`. Equivalent to\n * `CollectionHandle.upsertOne(f => filter, updaterFn)` but reuses the\n * already-accumulated `.match(...)` filter chain.\n */\n upsertOne(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n ): MongoQueryPlan<UpdateResult, UpdateOneCommand> {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new UpdateOneCommand(this.#ctx.collection, this.#foldedFilter(), update, true);\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n // --- Find-and-modify ---\n\n /**\n * Find a single matching document and apply `updaterFn` to it.\n *\n * `opts.upsert` (default `false`) toggles insert-on-miss behaviour.\n * `opts.returnDocument` (default `'after'`) controls whether the row\n * stream yields the document as it was before or after the update.\n */\n override findOneAndUpdate(\n updaterFn: (\n fields: FieldAccessor<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >,\n ) => UpdaterResult,\n opts: { readonly upsert?: boolean; readonly returnDocument?: 'before' | 'after' } = {},\n ): MongoQueryPlan<\n ResolveRow<\n ModelToDocShape<TContract, ModelName>,\n ExtractMongoCodecTypes<TContract>,\n TContract\n > | null,\n FindOneAndUpdateCommand\n > {\n const update = resolveUpdaterCallback<\n ModelToDocShape<TContract, ModelName>,\n ModelNestedShape<TContract, ModelName>\n >(updaterFn);\n const command = new FindOneAndUpdateCommand(\n this.#ctx.collection,\n this.#foldedFilter(),\n update,\n opts.upsert ?? false,\n undefined,\n opts.returnDocument ?? 'after',\n );\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n\n /**\n * Find a single matching document and delete it. Returns the deleted\n * document via the row stream.\n */\n override findOneAndDelete(): MongoQueryPlan<\n ResolveRow<\n ModelToDocShape<TContract, ModelName>,\n ExtractMongoCodecTypes<TContract>,\n TContract\n > | null,\n FindOneAndDeleteCommand\n > {\n const command = new FindOneAndDeleteCommand(this.#ctx.collection, this.#foldedFilter());\n return {\n collection: this.#ctx.collection,\n command,\n meta: writeMeta(this.#ctx.storageHash),\n };\n }\n}\n\nfunction foldAnd(filters: ReadonlyArray<MongoFilterExpr>): MongoFilterExpr {\n return MongoAndExpr.of(filters);\n}\n\n/**\n * Narrow a `MongoContractWithTypeMaps`-shaped value down to its underlying\n * `MongoContract` view. `MongoContractWithTypeMaps<C, ...>` is defined as\n * `C & { readonly [phantom]?: TTypeMaps }`, so every contract we accept is\n * structurally a `MongoContract` — the phantom is type-only. This helper\n * centralises that narrowing so callers don't reach for `as unknown as\n * MongoContract` double-casts.\n */\nexport function asMongoContract(\n contract: MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n): MongoContract {\n return contract;\n}\n\n/**\n * Bound execution context shared across the three state classes.\n */\nexport interface BindingContext<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n readonly contract: TContract;\n readonly collection: string;\n readonly storageHash: string;\n}\n\n/**\n * Construct a `CollectionHandle` from a validated contract + root name.\n * Used by `mongoQuery(...).from(name)` to enter the state machine.\n */\nexport function createCollectionHandle<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n RootName extends keyof TContract['roots'] & string,\n>(\n contract: TContract,\n rootName: RootName,\n): CollectionHandle<TContract, TContract['roots'][RootName] & string & keyof TContract['models']> {\n const c = asMongoContract(contract);\n const modelName = c.roots[rootName];\n if (!modelName) {\n const validRoots = Object.keys(c.roots).join(', ');\n throw new Error(`Unknown root: \"${rootName}\". Valid roots: ${validRoots}`);\n }\n const model = c.models[modelName];\n if (!model) {\n throw new Error(`Unknown model: \"${modelName}\" referenced by root \"${rootName}\".`);\n }\n const collectionName = model.storage?.collection ?? rootName;\n if (!c.storage?.storageHash) {\n throw new Error(\n 'Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().',\n );\n }\n return new CollectionHandle(\n {\n contract,\n collection: collectionName,\n storageHash: String(c.storage.storageHash),\n },\n modelName as TContract['roots'][RootName] & string & keyof TContract['models'],\n );\n}\n","import type { PlanMeta } from '@prisma-next/contract/types';\nimport type {\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type { AnyMongoCommand, MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { asMongoContract, type CollectionHandle, createCollectionHandle } from './state-classes';\n\n/**\n * Public entry point of the query builder. `mongoQuery(...).from(rootName)`\n * yields the root state of the three-state machine\n * (`CollectionHandle` → `FilteredCollection` → `PipelineChain`).\n *\n * `rawCommand(cmd)` is the escape hatch for cases the typed surface does\n * not cover (yet) — it accepts any `AnyMongoCommand` (typed CRUD or a\n * `RawMongoCommand` of `Document`s) and packages it into a `MongoQueryPlan`\n * with `lane: 'mongo-query'`. Row type is `unknown` because the runtime\n * cannot know what the caller's command yields.\n */\nexport interface QueryRoot<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n from<K extends keyof TContract['roots'] & string>(\n rootName: K,\n ): CollectionHandle<TContract, TContract['roots'][K] & string & keyof TContract['models']>;\n rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C>;\n}\n\nexport function mongoQuery<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: { contractJson: unknown }): QueryRoot<TContract> {\n const contract = options.contractJson as TContract;\n return {\n from<K extends keyof TContract['roots'] & string>(rootName: K) {\n return createCollectionHandle(contract, rootName);\n },\n rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C> {\n const c = asMongoContract(contract);\n const storageHash = c.storage?.storageHash;\n if (!storageHash) {\n throw new Error(\n 'Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().',\n );\n }\n const meta: PlanMeta = {\n target: 'mongo',\n storageHash: String(storageHash),\n lane: 'mongo-query',\n };\n return { collection: command.collection, command, meta };\n },\n };\n}\n"],"mappings":"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"}