@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.
- package/README.md +28 -0
- package/dist/index.d.mts +398 -192
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +189 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -9
- package/src/builder.ts +56 -31
- package/src/exports/index.ts +13 -0
- package/src/lookup-builder.ts +272 -0
- package/src/pipeline-result-shape.ts +15 -0
- package/src/query.ts +0 -1
- package/src/resolve-path.ts +54 -0
- package/src/result-shape.ts +63 -0
- package/src/state-classes.ts +12 -3
- package/src/types.ts +110 -9
package/dist/index.d.mts
CHANGED
|
@@ -1,145 +1,8 @@
|
|
|
1
|
-
import { AggregateCommand, AnyMongoCommand, DeleteManyCommand, DeleteOneCommand, DeleteResult, DeleteResult as DeleteResult$1, FindOneAndDeleteCommand, FindOneAndUpdateCommand, InsertManyCommand, InsertManyResult, InsertManyResult as InsertManyResult$1, InsertOneCommand, InsertOneResult, InsertOneResult as InsertOneResult$1, MongoAggAccumulator, MongoAggExpr, MongoDensifyRange, MongoFillOutput, MongoFilterExpr, MongoPipelineStage, MongoQueryPlan, MongoUpdatePipelineStage, MongoWindowField, UpdateManyCommand, UpdateOneCommand, UpdateResult, UpdateResult as UpdateResult$1 } from "@prisma-next/mongo-query-ast/execution";
|
|
2
|
-
import { ExtractMongoCodecTypes, MongoContract, MongoContractWithTypeMaps, MongoTypeMaps } from "@prisma-next/mongo-contract";
|
|
1
|
+
import { AggregateCommand, AnyMongoCommand, DeleteManyCommand, DeleteOneCommand, DeleteResult, DeleteResult as DeleteResult$1, FindOneAndDeleteCommand, FindOneAndUpdateCommand, InsertManyCommand, InsertManyResult, InsertManyResult as InsertManyResult$1, InsertOneCommand, InsertOneResult, InsertOneResult as InsertOneResult$1, MongoAggAccumulator, MongoAggExpr, MongoDensifyRange, MongoFieldShape, MongoFillOutput, MongoFilterExpr, MongoPipelineStage, MongoQueryPlan, MongoResultShape, MongoUpdatePipelineStage, MongoWindowField, UpdateManyCommand, UpdateOneCommand, UpdateResult, UpdateResult as UpdateResult$1 } from "@prisma-next/mongo-query-ast/execution";
|
|
2
|
+
import { ExtractMongoCodecTypes, ExtractMongoTypeMaps, InferModelRow, MongoContract, MongoContractWithTypeMaps, MongoModelDefinition, MongoTypeMaps } from "@prisma-next/mongo-contract";
|
|
3
3
|
import { MongoValue } from "@prisma-next/mongo-value";
|
|
4
|
+
import { ContractField } from "@prisma-next/contract/types";
|
|
4
5
|
|
|
5
|
-
//#region src/types.d.ts
|
|
6
|
-
interface DocField {
|
|
7
|
-
readonly codecId: string;
|
|
8
|
-
readonly nullable: boolean;
|
|
9
|
-
}
|
|
10
|
-
type NumericField = {
|
|
11
|
-
readonly codecId: 'mongo/double@1';
|
|
12
|
-
readonly nullable: false;
|
|
13
|
-
};
|
|
14
|
-
type NullableNumericField = {
|
|
15
|
-
readonly codecId: 'mongo/double@1';
|
|
16
|
-
readonly nullable: true;
|
|
17
|
-
};
|
|
18
|
-
type StringField = {
|
|
19
|
-
readonly codecId: 'mongo/string@1';
|
|
20
|
-
readonly nullable: false;
|
|
21
|
-
};
|
|
22
|
-
type ArrayField = {
|
|
23
|
-
readonly codecId: 'mongo/array@1';
|
|
24
|
-
readonly nullable: false;
|
|
25
|
-
};
|
|
26
|
-
type BooleanField = {
|
|
27
|
-
readonly codecId: 'mongo/bool@1';
|
|
28
|
-
readonly nullable: false;
|
|
29
|
-
};
|
|
30
|
-
type DateField = {
|
|
31
|
-
readonly codecId: 'mongo/date@1';
|
|
32
|
-
readonly nullable: false;
|
|
33
|
-
};
|
|
34
|
-
type NullableDocField = {
|
|
35
|
-
readonly codecId: string;
|
|
36
|
-
readonly nullable: true;
|
|
37
|
-
};
|
|
38
|
-
type LiteralValue<F extends DocField> = F extends StringField ? string : F extends NumericField ? number : F extends BooleanField ? boolean : F extends DateField ? Date : unknown;
|
|
39
|
-
type DocShape = Record<string, DocField>;
|
|
40
|
-
type ExtractCodecId<F> = F extends {
|
|
41
|
-
type: {
|
|
42
|
-
kind: 'scalar';
|
|
43
|
-
codecId: infer C;
|
|
44
|
-
};
|
|
45
|
-
} ? C : F extends {
|
|
46
|
-
codecId: infer C extends string;
|
|
47
|
-
} ? C : string;
|
|
48
|
-
type ModelToDocShape<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { [K in keyof TContract['models'][ModelName]['fields'] & string]: {
|
|
49
|
-
readonly codecId: ExtractCodecId<TContract['models'][ModelName]['fields'][K]>;
|
|
50
|
-
readonly nullable: TContract['models'][ModelName]['fields'][K]['nullable'];
|
|
51
|
-
} };
|
|
52
|
-
type ResolveRow<Shape extends DocShape, CodecTypes extends Record<string, {
|
|
53
|
-
readonly output: unknown;
|
|
54
|
-
}>> = { -readonly [K in keyof Shape & string]: Shape[K]['codecId'] extends keyof CodecTypes ? Shape[K]['nullable'] extends true ? CodecTypes[Shape[K]['codecId']]['output'] | null : CodecTypes[Shape[K]['codecId']]['output'] : unknown };
|
|
55
|
-
interface TypedAggExpr<F extends DocField> {
|
|
56
|
-
readonly _field: F;
|
|
57
|
-
readonly node: MongoAggExpr;
|
|
58
|
-
}
|
|
59
|
-
interface TypedAccumulatorExpr<F extends DocField> {
|
|
60
|
-
readonly _field: F;
|
|
61
|
-
readonly node: MongoAggAccumulator;
|
|
62
|
-
}
|
|
63
|
-
type ExtractDocShape<T extends Record<string, TypedAggExpr<DocField>>> = { [K in keyof T & string]: T[K]['_field'] };
|
|
64
|
-
type SortSpec<S extends DocShape> = Partial<Record<keyof S & string, 1 | -1>>;
|
|
65
|
-
type ProjectedShape<Shape extends DocShape, Spec extends Record<string, 1 | TypedAggExpr<DocField>>> = { [K in keyof Spec & string]: Spec[K] extends 1 ? K extends keyof Shape ? Shape[K] : DocField : Spec[K] extends TypedAggExpr<infer F> ? F : DocField } & ('_id' extends keyof Shape ? '_id' extends keyof Spec ? Record<keyof never, never> : Pick<Shape, '_id'> : Record<keyof never, never>);
|
|
66
|
-
type GroupSpec = {
|
|
67
|
-
_id: TypedAggExpr<DocField> | null;
|
|
68
|
-
[key: string]: TypedAggExpr<DocField> | TypedAccumulatorExpr<DocField> | null;
|
|
69
|
-
};
|
|
70
|
-
type GroupedDocShape<Spec extends GroupSpec> = { [K in keyof Spec & string]: Spec[K] extends TypedAggExpr<infer F> ? F : Spec[K] extends TypedAccumulatorExpr<infer F> ? F : Spec[K] extends null ? {
|
|
71
|
-
readonly codecId: 'mongo/null@1';
|
|
72
|
-
readonly nullable: true;
|
|
73
|
-
} : DocField };
|
|
74
|
-
/**
|
|
75
|
-
* Intentionally identity — full array element type extraction is deferred.
|
|
76
|
-
* Used by `UnwoundShape` so the unwind result shape can be refined later
|
|
77
|
-
* without changing the public API.
|
|
78
|
-
*/
|
|
79
|
-
type UnwrapArrayDocField<F extends DocField> = F;
|
|
80
|
-
type UnwoundShape<S extends DocShape, K$1 extends keyof S & string> = { [P in keyof S & string]: P extends K$1 ? UnwrapArrayDocField<S[P]> : S[P] };
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region src/accumulator-helpers.d.ts
|
|
83
|
-
declare const acc: {
|
|
84
|
-
sum<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<F>;
|
|
85
|
-
avg(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
86
|
-
min<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
87
|
-
readonly codecId: F["codecId"];
|
|
88
|
-
readonly nullable: true;
|
|
89
|
-
}>;
|
|
90
|
-
max<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
91
|
-
readonly codecId: F["codecId"];
|
|
92
|
-
readonly nullable: true;
|
|
93
|
-
}>;
|
|
94
|
-
first<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
95
|
-
readonly codecId: F["codecId"];
|
|
96
|
-
readonly nullable: true;
|
|
97
|
-
}>;
|
|
98
|
-
last<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
99
|
-
readonly codecId: F["codecId"];
|
|
100
|
-
readonly nullable: true;
|
|
101
|
-
}>;
|
|
102
|
-
push(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
|
|
103
|
-
addToSet(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
|
|
104
|
-
count(): TypedAccumulatorExpr<NumericField>;
|
|
105
|
-
stdDevPop(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
106
|
-
stdDevSamp(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
107
|
-
firstN(args: {
|
|
108
|
-
input: TypedAggExpr<DocField>;
|
|
109
|
-
n: TypedAggExpr<NumericField>;
|
|
110
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
111
|
-
lastN(args: {
|
|
112
|
-
input: TypedAggExpr<DocField>;
|
|
113
|
-
n: TypedAggExpr<NumericField>;
|
|
114
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
115
|
-
maxN(args: {
|
|
116
|
-
input: TypedAggExpr<DocField>;
|
|
117
|
-
n: TypedAggExpr<NumericField>;
|
|
118
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
119
|
-
minN(args: {
|
|
120
|
-
input: TypedAggExpr<DocField>;
|
|
121
|
-
n: TypedAggExpr<NumericField>;
|
|
122
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
123
|
-
top(args: {
|
|
124
|
-
output: TypedAggExpr<DocField>;
|
|
125
|
-
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
126
|
-
}): TypedAccumulatorExpr<DocField>;
|
|
127
|
-
bottom(args: {
|
|
128
|
-
output: TypedAggExpr<DocField>;
|
|
129
|
-
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
130
|
-
}): TypedAccumulatorExpr<DocField>;
|
|
131
|
-
topN(args: {
|
|
132
|
-
output: TypedAggExpr<DocField>;
|
|
133
|
-
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
134
|
-
n: TypedAggExpr<NumericField>;
|
|
135
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
136
|
-
bottomN(args: {
|
|
137
|
-
output: TypedAggExpr<DocField>;
|
|
138
|
-
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
139
|
-
n: TypedAggExpr<NumericField>;
|
|
140
|
-
}): TypedAccumulatorExpr<ArrayField>;
|
|
141
|
-
};
|
|
142
|
-
//#endregion
|
|
143
6
|
//#region src/resolve-path.d.ts
|
|
144
7
|
/**
|
|
145
8
|
* Marker `DocField` variant representing a non-leaf (value-object) path in
|
|
@@ -157,11 +20,62 @@ declare const acc: {
|
|
|
157
20
|
* nullable parent resolves to the leaf's own `nullable` — matching how
|
|
158
21
|
* MongoDB treats missing intermediate documents).
|
|
159
22
|
*/
|
|
160
|
-
interface ObjectField<N
|
|
23
|
+
interface ObjectField<N extends NestedDocShape> extends DocField {
|
|
161
24
|
readonly codecId: 'prisma/object@1';
|
|
162
25
|
readonly nullable: boolean;
|
|
163
|
-
readonly fields: N
|
|
26
|
+
readonly fields: N;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Marker `DocField` variant representing "an array of foreign-model rows"
|
|
30
|
+
* — the result of a `$lookup` whose foreign side was selected via the
|
|
31
|
+
* typed `col` accessor. `ModelName` is the literal foreign model name
|
|
32
|
+
* (e.g. `'User'`), preserved in the type so `ResolveRow` can resolve the
|
|
33
|
+
* field to `ResolveRow<ModelToDocShape<TC, ModelName>, …>[]` rather than
|
|
34
|
+
* the opaque `unknown[]` produced by the legacy `mongo/array@1` sentinel.
|
|
35
|
+
*
|
|
36
|
+
* Like `ObjectField`, the codec id is a purely type-level sentinel —
|
|
37
|
+
* there is no runtime codec entry for `'prisma/modelArray@1'`. The
|
|
38
|
+
* surrounding pipeline emits the standard `MongoLookupStage` whose
|
|
39
|
+
* runtime shape is unchanged; the marker exists solely to thread the
|
|
40
|
+
* foreign element type through the result-row resolver.
|
|
41
|
+
*/
|
|
42
|
+
interface ModelArrayField<ModelName extends string> extends DocField {
|
|
43
|
+
readonly codecId: 'prisma/modelArray@1';
|
|
44
|
+
readonly nullable: false;
|
|
45
|
+
readonly model: ModelName;
|
|
164
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Phantom-symbol brand placed on `ModelToDocShape`'s output (and inherited
|
|
49
|
+
* through shape-extending stages like `addFields`, `match`, `lookup`) so
|
|
50
|
+
* `ResolveRow` can route value-object resolution through `InferModelRow`
|
|
51
|
+
* — which walks the contract's `valueObjects` registry and resolves
|
|
52
|
+
* nested types — instead of falling through the codec-lookup branch to
|
|
53
|
+
* `unknown`.
|
|
54
|
+
*
|
|
55
|
+
* The brand is keyed on a `unique symbol` rather than a string so it is
|
|
56
|
+
* invisible to every `keyof Shape & string` walk in the package
|
|
57
|
+
* (`SortSpec`, `ProjectedShape`, `GroupedDocShape`, the field accessor's
|
|
58
|
+
* `Object.keys` iteration, etc.). Field accessors do not surface a
|
|
59
|
+
* `__modelOrigin` autocomplete entry; sorts cannot key on it; projections
|
|
60
|
+
* cannot reference it.
|
|
61
|
+
*
|
|
62
|
+
* Shape-extending stages preserve the brand because intersection types
|
|
63
|
+
* (`Shape & NewFields`) carry through symbol-keyed properties. Shape-
|
|
64
|
+
* replacing stages (`replaceRoot`, `group`, `project`) construct fresh
|
|
65
|
+
* `DocShape`s from scratch, naturally dropping the brand — which is the
|
|
66
|
+
* intended behaviour, since those stages legitimately leave model
|
|
67
|
+
* territory.
|
|
68
|
+
*/
|
|
69
|
+
declare const ModelOriginBrand: unique symbol;
|
|
70
|
+
type ModelOriginBrand = typeof ModelOriginBrand;
|
|
71
|
+
/**
|
|
72
|
+
* Brand carrier — a Shape whose row type should be resolved via
|
|
73
|
+
* `InferModelRow<TContract, ModelName>` rather than the per-field codec
|
|
74
|
+
* walk. Use as `ModelToDocShape<TC, ModelName> & ModelOriginBranded<ModelName>`.
|
|
75
|
+
*/
|
|
76
|
+
type ModelOriginBranded<ModelName extends string> = {
|
|
77
|
+
readonly [ModelOriginBrand]?: ModelName;
|
|
78
|
+
};
|
|
165
79
|
/**
|
|
166
80
|
* Document shape that carries nested value-object sub-shapes.
|
|
167
81
|
*
|
|
@@ -235,11 +149,11 @@ type TranslateField<TContract extends ContractHasValueObjects, F> = F extends {
|
|
|
235
149
|
* `VOs[VOName]['fields']` is preserved and the hover / indexed-access
|
|
236
150
|
* surface stays concrete at instantiation time.
|
|
237
151
|
*/
|
|
238
|
-
type VONestedShape<TContract extends ContractHasValueObjects, VOName
|
|
152
|
+
type VONestedShape<TContract extends ContractHasValueObjects, VOName extends string> = TContract extends {
|
|
239
153
|
readonly valueObjects: infer VOs extends Record<string, {
|
|
240
154
|
readonly fields: Record<string, unknown>;
|
|
241
155
|
}>;
|
|
242
|
-
} ? VOName
|
|
156
|
+
} ? VOName extends keyof VOs ? { readonly [K in keyof VOs[VOName]['fields'] & string]: TranslateField<TContract, VOs[VOName]['fields'][K]> } : never : never;
|
|
243
157
|
/**
|
|
244
158
|
* Build the `NestedDocShape` for a model. Scalar leaves resolve to their
|
|
245
159
|
* concrete codec id; value-object fields recurse into the referenced
|
|
@@ -268,7 +182,7 @@ type ModelNestedShape<TContract extends MongoContract, ModelName extends string
|
|
|
268
182
|
* rejects bad paths with a clear error instead of silently resolving to
|
|
269
183
|
* `never`.
|
|
270
184
|
*/
|
|
271
|
-
type ResolvePath<N
|
|
185
|
+
type ResolvePath<N extends NestedDocShape, Path extends string> = Path extends `${infer Head}.${infer Rest}` ? Head extends keyof N & string ? N[Head] extends ObjectField<infer Sub> ? ResolvePath<Sub, Rest> : never : never : Path extends keyof N & string ? N[Path] : never;
|
|
272
186
|
/**
|
|
273
187
|
* Union of every valid dot-path within a `NestedDocShape`. Includes
|
|
274
188
|
* top-level keys (scalar leaves *and* value-object roots) and every
|
|
@@ -287,14 +201,216 @@ type ResolvePath<N$1 extends NestedDocShape, Path extends string> = Path extends
|
|
|
287
201
|
* open-ended `keyof` cannot resolve a specific literal path, so the
|
|
288
202
|
* callable form must be disabled at the type level.
|
|
289
203
|
*/
|
|
290
|
-
type ValidPaths<N
|
|
204
|
+
type ValidPaths<N extends NestedDocShape> = string extends keyof N ? never : { [K in keyof N & string]: N[K] extends ObjectField<infer Sub> ? K | `${K}.${ValidPaths<Sub>}` : K }[keyof N & string];
|
|
291
205
|
/**
|
|
292
206
|
* IDE-oriented alias for `ValidPaths`. Kept as a separate export so future
|
|
293
207
|
* refinements (e.g. ArkType-style lazy expansion for very deep shapes) can
|
|
294
208
|
* diverge from the strict `ValidPaths` constraint without breaking
|
|
295
209
|
* downstream consumers. For now the two are intentionally equivalent.
|
|
296
210
|
*/
|
|
297
|
-
type PathCompletions<N
|
|
211
|
+
type PathCompletions<N extends NestedDocShape> = ValidPaths<N>;
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/types.d.ts
|
|
214
|
+
interface DocField {
|
|
215
|
+
readonly codecId: string;
|
|
216
|
+
readonly nullable: boolean;
|
|
217
|
+
}
|
|
218
|
+
type NumericField = {
|
|
219
|
+
readonly codecId: 'mongo/double@1';
|
|
220
|
+
readonly nullable: false;
|
|
221
|
+
};
|
|
222
|
+
type NullableNumericField = {
|
|
223
|
+
readonly codecId: 'mongo/double@1';
|
|
224
|
+
readonly nullable: true;
|
|
225
|
+
};
|
|
226
|
+
type StringField = {
|
|
227
|
+
readonly codecId: 'mongo/string@1';
|
|
228
|
+
readonly nullable: false;
|
|
229
|
+
};
|
|
230
|
+
type ArrayField = {
|
|
231
|
+
readonly codecId: 'mongo/array@1';
|
|
232
|
+
readonly nullable: false;
|
|
233
|
+
};
|
|
234
|
+
type BooleanField = {
|
|
235
|
+
readonly codecId: 'mongo/bool@1';
|
|
236
|
+
readonly nullable: false;
|
|
237
|
+
};
|
|
238
|
+
type DateField = {
|
|
239
|
+
readonly codecId: 'mongo/date@1';
|
|
240
|
+
readonly nullable: false;
|
|
241
|
+
};
|
|
242
|
+
type NullableDocField = {
|
|
243
|
+
readonly codecId: string;
|
|
244
|
+
readonly nullable: true;
|
|
245
|
+
};
|
|
246
|
+
type LiteralValue<F extends DocField> = F extends StringField ? string : F extends NumericField ? number : F extends BooleanField ? boolean : F extends DateField ? Date : unknown;
|
|
247
|
+
type DocShape = Record<string, DocField>;
|
|
248
|
+
type ExtractCodecId<F> = F extends {
|
|
249
|
+
type: {
|
|
250
|
+
kind: 'scalar';
|
|
251
|
+
codecId: infer C;
|
|
252
|
+
};
|
|
253
|
+
} ? C : F extends {
|
|
254
|
+
codecId: infer C extends string;
|
|
255
|
+
} ? C : string;
|
|
256
|
+
type ModelToDocShape<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { [K in keyof TContract['models'][ModelName]['fields'] & string]: {
|
|
257
|
+
readonly codecId: ExtractCodecId<TContract['models'][ModelName]['fields'][K]>;
|
|
258
|
+
readonly nullable: TContract['models'][ModelName]['fields'][K]['nullable'];
|
|
259
|
+
} } & ModelOriginBranded<ModelName>;
|
|
260
|
+
/**
|
|
261
|
+
* Per-field resolver. Walks `Shape`'s string keys, routing
|
|
262
|
+
* `ModelArrayField` (the lookup marker) through `InferModelRow` and
|
|
263
|
+
* everything else through the codec-lookup branch.
|
|
264
|
+
*
|
|
265
|
+
* Internal helper — public callers should use `ResolveRow`, which adds
|
|
266
|
+
* the model-origin brand detection on top.
|
|
267
|
+
*/
|
|
268
|
+
type ResolveFields<Shape extends DocShape, CodecTypes extends Record<string, {
|
|
269
|
+
readonly output: unknown;
|
|
270
|
+
}>, TContract extends MongoContract> = { -readonly [K in keyof Shape & string]: Shape[K] extends ModelArrayField<infer ModelName> ? IsConcreteContract<TContract> extends true ? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps> ? ModelName extends string & keyof TContract['models'] ? Array<InferModelRow<TContract, ModelName>> : unknown[] : unknown[] : unknown[] : Shape[K]['codecId'] extends keyof CodecTypes ? Shape[K]['nullable'] extends true ? CodecTypes[Shape[K]['codecId']]['output'] | null : CodecTypes[Shape[K]['codecId']]['output'] : unknown };
|
|
271
|
+
/**
|
|
272
|
+
* Resolve a `DocShape` to a concrete row object type.
|
|
273
|
+
*
|
|
274
|
+
* The optional `TContract` parameter exists so the resolver can:
|
|
275
|
+
*
|
|
276
|
+
* 1. Detect the `ModelOriginBrand` on `Shape` — the phantom symbol
|
|
277
|
+
* placed by `ModelToDocShape`. When present (and the contract has
|
|
278
|
+
* type maps), the row is resolved via `InferModelRow<TC, M>` from
|
|
279
|
+
* `@prisma-next/mongo-contract`, which walks scalar / valueObject /
|
|
280
|
+
* union field kinds (handling nested value-objects and `many: true`).
|
|
281
|
+
* This makes entry-point reads (`q.from('users').build()`) and
|
|
282
|
+
* shape-extending stages (`match`, `addFields`) resolve value-object
|
|
283
|
+
* fields to their concrete nested types instead of `unknown`.
|
|
284
|
+
*
|
|
285
|
+
* 2. Detect the per-field `ModelArrayField<ModelName>` marker produced
|
|
286
|
+
* by `lookup()` and resolve it to `Array<InferModelRow<TC, M>>` so
|
|
287
|
+
* lookup rows carry the same fully-typed foreign rows.
|
|
288
|
+
*
|
|
289
|
+
* When the contract is not threaded through (or lacks the type-map
|
|
290
|
+
* phantom), both branches fall back to `unknown` / `unknown[]` —
|
|
291
|
+
* preserving the legacy resolver shape for call sites that do not need
|
|
292
|
+
* model-row resolution.
|
|
293
|
+
*/
|
|
294
|
+
/**
|
|
295
|
+
* Flatten an intersection `A & B` into a single object literal so callers
|
|
296
|
+
* (and `expectTypeOf().toEqualTypeOf<…>()`) see one homogeneous record
|
|
297
|
+
* rather than the intersection form. Vitest's strict equality check
|
|
298
|
+
* treats `A & B` as distinct from the structurally-equivalent flat
|
|
299
|
+
* record, even when assignability is bidirectional, so the
|
|
300
|
+
* `ResolveRow` brand-positive branch normalises its result through this.
|
|
301
|
+
*/
|
|
302
|
+
type Flatten<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
|
|
303
|
+
/**
|
|
304
|
+
* Decide whether to route a brand-positive `ResolveRow` through
|
|
305
|
+
* `InferModelRow`. The default `MongoContract` (no concrete models)
|
|
306
|
+
* still satisfies `MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>`
|
|
307
|
+
* because the phantom key is optional, but `InferModelRow<MongoContract, …>`
|
|
308
|
+
* collapses to an empty/unknown row. Gate on the presence of the
|
|
309
|
+
* type-maps phantom: a concrete contract attaches concrete `TestTypeMaps`-
|
|
310
|
+
* shaped maps, while the default `MongoContract` has no phantom and
|
|
311
|
+
* `ExtractMongoTypeMaps` resolves to `never`.
|
|
312
|
+
*/
|
|
313
|
+
type IsConcreteContract<TContract> = [ExtractMongoTypeMaps<TContract>] extends [never] ? false : true;
|
|
314
|
+
type ResolveRow<Shape extends DocShape, CodecTypes extends Record<string, {
|
|
315
|
+
readonly output: unknown;
|
|
316
|
+
}>, TContract extends MongoContract = MongoContract> = Shape extends {
|
|
317
|
+
readonly [ModelOriginBrand]?: infer ModelName extends string;
|
|
318
|
+
} ? IsConcreteContract<TContract> extends true ? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps> ? ModelName extends string & keyof TContract['models'] ? Flatten<InferModelRow<TContract, ModelName> & Omit<ResolveFields<Shape, CodecTypes, TContract>, keyof InferModelRow<TContract, ModelName>>> : ResolveFields<Shape, CodecTypes, TContract> : ResolveFields<Shape, CodecTypes, TContract> : ResolveFields<Shape, CodecTypes, TContract> : ResolveFields<Shape, CodecTypes, TContract>;
|
|
319
|
+
interface TypedAggExpr<F extends DocField> {
|
|
320
|
+
readonly _field: F;
|
|
321
|
+
readonly node: MongoAggExpr;
|
|
322
|
+
}
|
|
323
|
+
interface TypedAccumulatorExpr<F extends DocField> {
|
|
324
|
+
readonly _field: F;
|
|
325
|
+
readonly node: MongoAggAccumulator;
|
|
326
|
+
}
|
|
327
|
+
type ExtractDocShape<T extends Record<string, TypedAggExpr<DocField>>> = { [K in keyof T & string]: T[K]['_field'] };
|
|
328
|
+
type SortSpec<S extends DocShape> = Partial<Record<keyof S & string, 1 | -1>>;
|
|
329
|
+
type ProjectedShape<Shape extends DocShape, Spec extends Record<string, 1 | TypedAggExpr<DocField>>> = { [K in keyof Spec & string]: Spec[K] extends 1 ? K extends keyof Shape ? Shape[K] : DocField : Spec[K] extends TypedAggExpr<infer F> ? F : DocField } & ('_id' extends keyof Shape ? '_id' extends keyof Spec ? Record<keyof never, never> : Pick<Shape, '_id'> : Record<keyof never, never>);
|
|
330
|
+
type GroupSpec = {
|
|
331
|
+
_id: TypedAggExpr<DocField> | null;
|
|
332
|
+
[key: string]: TypedAggExpr<DocField> | TypedAccumulatorExpr<DocField> | null;
|
|
333
|
+
};
|
|
334
|
+
type GroupedDocShape<Spec extends GroupSpec> = { [K in keyof Spec & string]: Spec[K] extends TypedAggExpr<infer F> ? F : Spec[K] extends TypedAccumulatorExpr<infer F> ? F : Spec[K] extends null ? {
|
|
335
|
+
readonly codecId: 'mongo/null@1';
|
|
336
|
+
readonly nullable: true;
|
|
337
|
+
} : DocField };
|
|
338
|
+
/**
|
|
339
|
+
* Intentionally identity — full array element type extraction is deferred.
|
|
340
|
+
* Used by `UnwoundShape` so the unwind result shape can be refined later
|
|
341
|
+
* without changing the public API.
|
|
342
|
+
*/
|
|
343
|
+
type UnwrapArrayDocField<F extends DocField> = F;
|
|
344
|
+
/**
|
|
345
|
+
* `$unwind` reshapes the array slot but leaves the rest of the document
|
|
346
|
+
* structurally intact. The mapped iteration is keyed on `keyof S & string`,
|
|
347
|
+
* which discards the symbol-keyed `ModelOriginBrand` carried by
|
|
348
|
+
* model-rooted shapes. Preserve the brand explicitly so post-unwind
|
|
349
|
+
* `ResolveRow` still routes through `InferModelRow` and value-object
|
|
350
|
+
* fields keep their concrete nested types.
|
|
351
|
+
*/
|
|
352
|
+
type UnwoundShape<S extends DocShape, K extends keyof S & string> = { [P in keyof S & string]: P extends K ? UnwrapArrayDocField<S[P]> : S[P] } & (S extends ModelOriginBranded<infer ModelName extends string> ? ModelOriginBranded<ModelName> : unknown);
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/accumulator-helpers.d.ts
|
|
355
|
+
declare const acc: {
|
|
356
|
+
sum<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<F>;
|
|
357
|
+
avg(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
358
|
+
min<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
359
|
+
readonly codecId: F["codecId"];
|
|
360
|
+
readonly nullable: true;
|
|
361
|
+
}>;
|
|
362
|
+
max<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
363
|
+
readonly codecId: F["codecId"];
|
|
364
|
+
readonly nullable: true;
|
|
365
|
+
}>;
|
|
366
|
+
first<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
367
|
+
readonly codecId: F["codecId"];
|
|
368
|
+
readonly nullable: true;
|
|
369
|
+
}>;
|
|
370
|
+
last<F extends DocField>(expr: TypedAggExpr<F>): TypedAccumulatorExpr<{
|
|
371
|
+
readonly codecId: F["codecId"];
|
|
372
|
+
readonly nullable: true;
|
|
373
|
+
}>;
|
|
374
|
+
push(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
|
|
375
|
+
addToSet(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<ArrayField>;
|
|
376
|
+
count(): TypedAccumulatorExpr<NumericField>;
|
|
377
|
+
stdDevPop(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
378
|
+
stdDevSamp(expr: TypedAggExpr<DocField>): TypedAccumulatorExpr<NullableNumericField>;
|
|
379
|
+
firstN(args: {
|
|
380
|
+
input: TypedAggExpr<DocField>;
|
|
381
|
+
n: TypedAggExpr<NumericField>;
|
|
382
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
383
|
+
lastN(args: {
|
|
384
|
+
input: TypedAggExpr<DocField>;
|
|
385
|
+
n: TypedAggExpr<NumericField>;
|
|
386
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
387
|
+
maxN(args: {
|
|
388
|
+
input: TypedAggExpr<DocField>;
|
|
389
|
+
n: TypedAggExpr<NumericField>;
|
|
390
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
391
|
+
minN(args: {
|
|
392
|
+
input: TypedAggExpr<DocField>;
|
|
393
|
+
n: TypedAggExpr<NumericField>;
|
|
394
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
395
|
+
top(args: {
|
|
396
|
+
output: TypedAggExpr<DocField>;
|
|
397
|
+
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
398
|
+
}): TypedAccumulatorExpr<DocField>;
|
|
399
|
+
bottom(args: {
|
|
400
|
+
output: TypedAggExpr<DocField>;
|
|
401
|
+
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
402
|
+
}): TypedAccumulatorExpr<DocField>;
|
|
403
|
+
topN(args: {
|
|
404
|
+
output: TypedAggExpr<DocField>;
|
|
405
|
+
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
406
|
+
n: TypedAggExpr<NumericField>;
|
|
407
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
408
|
+
bottomN(args: {
|
|
409
|
+
output: TypedAggExpr<DocField>;
|
|
410
|
+
sortBy: Readonly<Record<string, 1 | -1>>;
|
|
411
|
+
n: TypedAggExpr<NumericField>;
|
|
412
|
+
}): TypedAccumulatorExpr<ArrayField>;
|
|
413
|
+
};
|
|
298
414
|
//#endregion
|
|
299
415
|
//#region src/update-ops.d.ts
|
|
300
416
|
/**
|
|
@@ -420,7 +536,7 @@ interface LeafExpression<F extends DocField> extends TypedAggExpr<F> {
|
|
|
420
536
|
* so the value object can be piped through `$addFields` /
|
|
421
537
|
* `$replaceRoot` / etc. as-is.
|
|
422
538
|
*/
|
|
423
|
-
interface ObjectExpression<N
|
|
539
|
+
interface ObjectExpression<N extends NestedDocShape> extends TypedAggExpr<ObjectField<N>> {
|
|
424
540
|
readonly _path: string;
|
|
425
541
|
exists(flag?: boolean): MongoFilterExpr;
|
|
426
542
|
eq(value: null): MongoFilterExpr;
|
|
@@ -489,7 +605,7 @@ interface StageEmitters {
|
|
|
489
605
|
* `f.rawPath(...)` remains available in that state for callers that need
|
|
490
606
|
* an explicit unvalidated path.
|
|
491
607
|
*/
|
|
492
|
-
type FieldAccessor<S extends DocShape, N
|
|
608
|
+
type FieldAccessor<S extends DocShape, N extends NestedDocShape = Record<string, never>> = { readonly [K in keyof S & string]: Expression<S[K]> } & (<P extends ValidPaths<N>>(path: P) => Expression<ResolvePath<N, P>>) & {
|
|
493
609
|
readonly stage: StageEmitters;
|
|
494
610
|
/**
|
|
495
611
|
* Escape hatch: build a `LeafExpression<F>` for an unvalidated string
|
|
@@ -517,7 +633,90 @@ type FieldAccessor<S extends DocShape, N$1 extends NestedDocShape = Record<strin
|
|
|
517
633
|
* `undefined` to keep accidental coercion behaviour unsurprising —
|
|
518
634
|
* matching the previous `FieldProxy` / `FilterProxy` semantics.
|
|
519
635
|
*/
|
|
520
|
-
declare function createFieldAccessor<S extends DocShape, N
|
|
636
|
+
declare function createFieldAccessor<S extends DocShape, N extends NestedDocShape = Record<string, never>>(): FieldAccessor<S, N>;
|
|
637
|
+
//#endregion
|
|
638
|
+
//#region src/lookup-builder.d.ts
|
|
639
|
+
/**
|
|
640
|
+
* Resolved foreign-model name for a contract root. Looks `RootName` up
|
|
641
|
+
* through `TContract['roots']` and intersects the result back with
|
|
642
|
+
* `keyof TContract['models']` so it can be used as a `ModelName` index
|
|
643
|
+
* into `models`. Resolves to `never` when the root is not present (this
|
|
644
|
+
* surface should never be reachable through normal use because `from()`
|
|
645
|
+
* constrains its `R` parameter to `keyof TContract['roots']`).
|
|
646
|
+
*/
|
|
647
|
+
type ModelOf<TContract extends MongoContract, RootName extends keyof TContract['roots'] & string> = TContract['roots'][RootName] & string & keyof TContract['models'];
|
|
648
|
+
/**
|
|
649
|
+
* Object returned by the user from the `on(...)` callback. Each side is
|
|
650
|
+
* a `LeafExpression` produced by property access on the corresponding
|
|
651
|
+
* `FieldAccessor` (`local._id`, `foreign.customerId`, etc.). Carrying
|
|
652
|
+
* `LeafExpression` rather than the broader `TypedAggExpr` is what makes
|
|
653
|
+
* non-leaf returns (e.g. `fn.toUpper(local._id)`) a compile-time error
|
|
654
|
+
* without per-field operator gating — `LeafExpression` carries `_path`,
|
|
655
|
+
* `TypedAggExpr` does not (see field-accessor.ts L47–L82).
|
|
656
|
+
*/
|
|
657
|
+
interface LookupOnResult {
|
|
658
|
+
readonly local: LeafExpression<DocField>;
|
|
659
|
+
readonly foreign: LeafExpression<DocField>;
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Marker brand on the captured spec returned by the `lookup(...)`
|
|
663
|
+
* callback. The phantom `_brand` literal lets `PipelineChain.lookup`
|
|
664
|
+
* accept the result of `from(...).on(...).as(...)` without exposing the
|
|
665
|
+
* internal field shape to user code, and prevents accidental
|
|
666
|
+
* construction of a malformed spec by hand.
|
|
667
|
+
*/
|
|
668
|
+
type LookupResultBrand = 'mongo-query-builder/lookup-result@1';
|
|
669
|
+
/**
|
|
670
|
+
* Captured output of the inner `from(name).on(cb).as(name)` chain. The
|
|
671
|
+
* contract is consumed by `PipelineChain.lookup` to construct the
|
|
672
|
+
* `MongoLookupStage` (collection name comes from `models[ModelName]
|
|
673
|
+
* .storage.collection`) and to thread `ModelArrayField<ModelName>` into
|
|
674
|
+
* the resulting `Shape` so the resolver yields `Array<ForeignRow>`.
|
|
675
|
+
*
|
|
676
|
+
* Type parameters carry the foreign-root literal `RootName`, the
|
|
677
|
+
* resolved foreign model name `ModelName`, and the `As` literal so
|
|
678
|
+
* `PipelineChain.lookup`'s return type can encode the result-row
|
|
679
|
+
* promotion precisely.
|
|
680
|
+
*/
|
|
681
|
+
interface LookupResult<RootName extends string, ModelName extends string, As extends string> {
|
|
682
|
+
readonly _brand: LookupResultBrand;
|
|
683
|
+
readonly _root: RootName;
|
|
684
|
+
readonly _model: ModelName;
|
|
685
|
+
readonly _localField: string;
|
|
686
|
+
readonly _foreignField: string;
|
|
687
|
+
readonly _as: As;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Builder returned by `from(name).on(cb)`. Carries the foreign root /
|
|
691
|
+
* model literals plus the captured local / foreign paths, and exposes
|
|
692
|
+
* `.as(name)` to finalise the spec with the user-chosen field name.
|
|
693
|
+
*/
|
|
694
|
+
interface LookupBuilderWithKey<RootName extends string, ModelName extends string> {
|
|
695
|
+
as<As extends string>(name: As): LookupResult<RootName, ModelName, As>;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Builder returned by `from(name)`. Carries the foreign root / model
|
|
699
|
+
* literals and the local pipeline's `Shape` / nested shape so the
|
|
700
|
+
* `on(...)` callback's `local` and `foreign` accessors are typed
|
|
701
|
+
* narrowly.
|
|
702
|
+
*
|
|
703
|
+
* `on(cb)` runs the user's callback to capture the leaf paths and
|
|
704
|
+
* returns a `LookupBuilderWithKey` that exposes `.as(name)`.
|
|
705
|
+
*/
|
|
706
|
+
interface LookupBuilder<TContract extends MongoContract, Shape extends DocShape, Nested extends Record<string, DocField>, RootName extends string, ModelName extends string> {
|
|
707
|
+
on(cb: (local: FieldAccessor<Shape, Nested>, foreign: ModelName extends keyof TContract['models'] & string ? FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>> : never) => LookupOnResult): LookupBuilderWithKey<RootName, ModelName>;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Type of the `from` callable passed to `PipelineChain.lookup`'s outer
|
|
711
|
+
* callback. The generic argument is inferred from a string-literal
|
|
712
|
+
* argument (the same pattern as `mongoQuery<TC>(...).from('orders')`),
|
|
713
|
+
* which grounds `RootName` into the returned `LookupBuilder` *before*
|
|
714
|
+
* the inner `on(...)` callback is type-checked. This sequential
|
|
715
|
+
* inference is what makes `foreign` resolve narrowly to the foreign
|
|
716
|
+
* model's `FieldAccessor` (verified in the R1.5 spike — see spec § Open
|
|
717
|
+
* Questions / Resolved decisions).
|
|
718
|
+
*/
|
|
719
|
+
type LookupFrom<TContract extends MongoContract, Shape extends DocShape, Nested extends Record<string, DocField>> = <RootName extends keyof TContract['roots'] & string>(name: RootName) => LookupBuilder<TContract, Shape, Nested, RootName, ModelOf<TContract, RootName>>;
|
|
521
720
|
//#endregion
|
|
522
721
|
//#region src/markers.d.ts
|
|
523
722
|
/**
|
|
@@ -551,6 +750,7 @@ interface PipelineChainState {
|
|
|
551
750
|
readonly collection: string;
|
|
552
751
|
readonly stages: ReadonlyArray<MongoPipelineStage>;
|
|
553
752
|
readonly storageHash: string;
|
|
753
|
+
readonly modelName?: string;
|
|
554
754
|
}
|
|
555
755
|
/**
|
|
556
756
|
* The pipeline state in the query-builder state machine.
|
|
@@ -576,7 +776,7 @@ interface PipelineChainState {
|
|
|
576
776
|
* marker table (and rationale per row) in
|
|
577
777
|
* `docs/architecture docs/adrs/ADR 201 - State-machine pattern for typed DSL builders.md`.
|
|
578
778
|
*/
|
|
579
|
-
declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, Shape extends DocShape, U extends UpdateEnabled = 'update-ok', F extends FindAndModifyEnabled = 'fam-ok', L extends LeadingMatch = 'leading', N
|
|
779
|
+
declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, Shape extends DocShape, U extends UpdateEnabled = 'update-ok', F extends FindAndModifyEnabled = 'fam-ok', L extends LeadingMatch = 'leading', N extends NestedDocShape = Record<string, never>> {
|
|
580
780
|
#private;
|
|
581
781
|
readonly __updateCompat: U;
|
|
582
782
|
readonly __findAndModifyCompat: F;
|
|
@@ -590,27 +790,27 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
590
790
|
* `deconstructUpdateChain` can only peel leading `$match` stages into the
|
|
591
791
|
* wire-command filter.
|
|
592
792
|
*/
|
|
593
|
-
match(filter: MongoFilterExpr): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N
|
|
594
|
-
match(fn: (fields: FieldAccessor<Shape, N
|
|
793
|
+
match(filter: MongoFilterExpr): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;
|
|
794
|
+
match(fn: (fields: FieldAccessor<Shape, N>) => MongoFilterExpr): PipelineChain<TContract, Shape, L extends 'leading' ? U : 'update-cleared', F, L, N>;
|
|
595
795
|
/**
|
|
596
796
|
* `$sort`. Clears `UpdateEnabled` (`update` has no per-document sort) but
|
|
597
797
|
* preserves `FindAndModifyEnabled` (`findAndModify` has a `sort` slot).
|
|
598
798
|
*/
|
|
599
|
-
sort(spec: SortSpec<Shape>): PipelineChain<TContract, Shape, 'update-cleared', F, 'past-leading', N
|
|
799
|
+
sort(spec: SortSpec<Shape>): PipelineChain<TContract, Shape, 'update-cleared', F, 'past-leading', N>;
|
|
600
800
|
/**
|
|
601
801
|
* `$limit`. Clears both markers — `limit` is incompatible with the `update`
|
|
602
802
|
* wire command, and `findAndModify` already implies single-document
|
|
603
803
|
* semantics (so `.limit(...)` adds no meaning, only ambiguity).
|
|
604
804
|
*/
|
|
605
|
-
limit(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
805
|
+
limit(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
606
806
|
/**
|
|
607
807
|
* `$skip`. Clears both markers — MongoDB's `findAndModify` wire command
|
|
608
808
|
* has no `skip` slot, so `deconstructFindAndModifyChain` rejects any
|
|
609
809
|
* `$skip` at runtime; keeping the marker `fam-cleared` makes the type
|
|
610
810
|
* system reflect the same constraint (see ADR 201 marker table).
|
|
611
811
|
*/
|
|
612
|
-
skip(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
613
|
-
sample(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
812
|
+
skip(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
813
|
+
sample(n: number): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
614
814
|
/**
|
|
615
815
|
* `$addFields`. Preserves `UpdateEnabled` (representable as
|
|
616
816
|
* update-with-pipeline `$set`); clears `FindAndModifyEnabled` (no analogue
|
|
@@ -618,22 +818,21 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
618
818
|
* preserved — newly added flat fields are reachable via property access
|
|
619
819
|
* (`f.newField`) but do not themselves carry nested structure.
|
|
620
820
|
*/
|
|
621
|
-
addFields<NewFields extends Record<string, TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N
|
|
821
|
+
addFields<NewFields extends Record<string, TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N>) => NewFields): PipelineChain<TContract, Shape & ExtractDocShape<NewFields>, U, 'fam-cleared', 'past-leading', N>;
|
|
622
822
|
/**
|
|
623
823
|
* `$lookup`. Clears both markers — joins are not representable in either
|
|
624
824
|
* the `update` or `findAndModify` wire commands. The original document's
|
|
625
825
|
* nested-path shape `N` is preserved (the lookup adds a sidecar array
|
|
626
826
|
* field; existing keys are untouched).
|
|
827
|
+
*
|
|
828
|
+
* The single callback receives a `from` callable that grounds the
|
|
829
|
+
* foreign-root literal sequentially before the inner `on(...)`
|
|
830
|
+
* callback is type-checked — see `lookup-builder.ts`. The resulting
|
|
831
|
+
* `Shape` gains the `As` key as a `ModelArrayField<ModelName>` so
|
|
832
|
+
* `ResolveRow` produces `Array<ForeignRow>` (with concrete leaf
|
|
833
|
+
* types) instead of the legacy `unknown[]`.
|
|
627
834
|
*/
|
|
628
|
-
lookup<
|
|
629
|
-
from: ForeignRoot;
|
|
630
|
-
localField: keyof Shape & string;
|
|
631
|
-
foreignField: string;
|
|
632
|
-
as: As;
|
|
633
|
-
}): PipelineChain<TContract, Shape & Record<As, {
|
|
634
|
-
readonly codecId: 'mongo/array@1';
|
|
635
|
-
readonly nullable: false;
|
|
636
|
-
}>, 'update-cleared', 'fam-cleared', 'past-leading', N$1>;
|
|
835
|
+
lookup<RootName extends string, ModelName extends string, As extends string>(fn: (from: LookupFrom<TContract, Shape, N>) => LookupResult<RootName, ModelName, As>): PipelineChain<TContract, Shape & Record<As, ModelArrayField<ModelName>>, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
637
836
|
/**
|
|
638
837
|
* `$project`. Preserves `UpdateEnabled` (representable as update-with-pipeline
|
|
639
838
|
* `$project` / `$unset`); clears `FindAndModifyEnabled` (use `.project()` on
|
|
@@ -644,8 +843,8 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
644
843
|
* fundamentally rewrites the document, so dot-paths into the *source*
|
|
645
844
|
* document are no longer meaningful downstream.
|
|
646
845
|
*/
|
|
647
|
-
project<K
|
|
648
|
-
project<Spec extends Record<string, 1 | TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N
|
|
846
|
+
project<K extends keyof Shape & string>(...keys: K[]): PipelineChain<TContract, Pick<Shape, K | ('_id' extends keyof Shape ? '_id' : never)>, U, 'fam-cleared', 'past-leading'>;
|
|
847
|
+
project<Spec extends Record<string, 1 | TypedAggExpr<DocField>>>(fn: (fields: FieldAccessor<Shape, N>) => Spec): PipelineChain<TContract, ProjectedShape<Shape, Spec>, U, 'fam-cleared', 'past-leading'>;
|
|
649
848
|
/**
|
|
650
849
|
* `$unwind`. Clears both markers — array unrolling produces multiple output
|
|
651
850
|
* documents per input, incompatible with both single-document update and
|
|
@@ -653,27 +852,27 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
653
852
|
* replaces the unwound array slot with its element but leaves the rest
|
|
654
853
|
* of the document structurally intact.
|
|
655
854
|
*/
|
|
656
|
-
unwind<K
|
|
855
|
+
unwind<K extends keyof Shape & string>(field: K, options?: {
|
|
657
856
|
preserveNullAndEmptyArrays?: boolean;
|
|
658
|
-
}): PipelineChain<TContract, UnwoundShape<Shape, K
|
|
857
|
+
}): PipelineChain<TContract, UnwoundShape<Shape, K>, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
659
858
|
/**
|
|
660
859
|
* `$group`. Clears both markers — group output bears no relation to source
|
|
661
860
|
* documents; neither `update` nor `findAndModify` can consume it. Nested
|
|
662
861
|
* path shape is reset (the source document's path tree is gone).
|
|
663
862
|
*/
|
|
664
|
-
group<Spec extends GroupSpec>(fn: (fields: FieldAccessor<Shape, N
|
|
863
|
+
group<Spec extends GroupSpec>(fn: (fields: FieldAccessor<Shape, N>) => Spec): PipelineChain<TContract, GroupedDocShape<Spec>, 'update-cleared', 'fam-cleared', 'past-leading'>;
|
|
665
864
|
/**
|
|
666
865
|
* `$replaceRoot`. Preserves `UpdateEnabled` (representable as
|
|
667
866
|
* update-with-pipeline `$replaceRoot`); clears `FindAndModifyEnabled`.
|
|
668
867
|
* Nested path shape is reset — the replaced root has no relation to
|
|
669
868
|
* the original document structure.
|
|
670
869
|
*/
|
|
671
|
-
replaceRoot<NewShape extends DocShape>(fn: (fields: FieldAccessor<Shape, N
|
|
870
|
+
replaceRoot<NewShape extends DocShape>(fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>): PipelineChain<TContract, NewShape, U, 'fam-cleared', 'past-leading'>;
|
|
672
871
|
count<Field extends string>(field: Field): PipelineChain<TContract, Record<Field, {
|
|
673
872
|
readonly codecId: 'mongo/double@1';
|
|
674
873
|
readonly nullable: false;
|
|
675
874
|
}>, 'update-cleared', 'fam-cleared', 'past-leading'>;
|
|
676
|
-
sortByCount<F2 extends DocField>(fn: (fields: FieldAccessor<Shape, N
|
|
875
|
+
sortByCount<F2 extends DocField>(fn: (fields: FieldAccessor<Shape, N>) => Expression<F2> | TypedAggExpr<F2>): PipelineChain<TContract, {
|
|
677
876
|
_id: F2;
|
|
678
877
|
count: {
|
|
679
878
|
readonly codecId: 'mongo/double@1';
|
|
@@ -684,7 +883,7 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
684
883
|
* `$redact`. Preserves `UpdateEnabled`; clears `FindAndModifyEnabled`.
|
|
685
884
|
* Shape- and nested-path-preserving (the document tree is unchanged).
|
|
686
885
|
*/
|
|
687
|
-
redact(fn: (fields: FieldAccessor<Shape, N
|
|
886
|
+
redact(fn: (fields: FieldAccessor<Shape, N>) => Expression<DocField> | TypedAggExpr<DocField>): PipelineChain<TContract, Shape, U, 'fam-cleared', 'past-leading', N>;
|
|
688
887
|
/**
|
|
689
888
|
* `$out` write terminal. Materialises the pipeline output into
|
|
690
889
|
* `collection` (optionally in `db`), replacing any prior contents. Unlike
|
|
@@ -714,7 +913,7 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
714
913
|
whenMatched?: string | ReadonlyArray<MongoUpdatePipelineStage>;
|
|
715
914
|
whenNotMatched?: string;
|
|
716
915
|
}): MongoQueryPlan<unknown, AggregateCommand>;
|
|
717
|
-
unionWith(collection: string, pipeline?: ReadonlyArray<MongoPipelineStage>): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
916
|
+
unionWith(collection: string, pipeline?: ReadonlyArray<MongoPipelineStage>): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
718
917
|
bucket(options: {
|
|
719
918
|
groupBy: MongoAggExpr;
|
|
720
919
|
boundaries: ReadonlyArray<unknown>;
|
|
@@ -758,14 +957,14 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
758
957
|
field: string;
|
|
759
958
|
partitionByFields?: ReadonlyArray<string>;
|
|
760
959
|
range: MongoDensifyRange;
|
|
761
|
-
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
960
|
+
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
762
961
|
fill(options: {
|
|
763
962
|
partitionBy?: MongoAggExpr;
|
|
764
963
|
partitionByFields?: ReadonlyArray<string>;
|
|
765
964
|
sortBy?: Record<string, 1 | -1>;
|
|
766
965
|
output: Record<string, MongoFillOutput>;
|
|
767
|
-
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
768
|
-
search(config: Record<string, unknown>, index?: string): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
966
|
+
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
967
|
+
search(config: Record<string, unknown>, index?: string): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
769
968
|
searchMeta(config: Record<string, unknown>, index?: string): PipelineChain<TContract, DocShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
|
|
770
969
|
vectorSearch(options: {
|
|
771
970
|
index: string;
|
|
@@ -774,7 +973,7 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
774
973
|
numCandidates: number;
|
|
775
974
|
limit: number;
|
|
776
975
|
filter?: Record<string, unknown>;
|
|
777
|
-
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N
|
|
976
|
+
}): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading', N>;
|
|
778
977
|
pipe(stage: MongoPipelineStage): PipelineChain<TContract, Shape, 'update-cleared', 'fam-cleared', 'past-leading'>;
|
|
779
978
|
pipe<NewShape extends DocShape>(stage: MongoPipelineStage): PipelineChain<TContract, NewShape, 'update-cleared', 'fam-cleared', 'past-leading'>;
|
|
780
979
|
/**
|
|
@@ -795,14 +994,14 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
795
994
|
* code. See `docs/architecture docs/adrs/ADR 201 - State-machine
|
|
796
995
|
* pattern for typed DSL builders.md` for the marker-transition table.
|
|
797
996
|
*/
|
|
798
|
-
updateMany(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N
|
|
997
|
+
updateMany(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>, updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateManyCommand>;
|
|
799
998
|
/**
|
|
800
999
|
* No-arg `updateOne()`: same as `updateMany()` but maps to a single-doc
|
|
801
1000
|
* update. Carries the same optional-callback/subclass-compat caveat
|
|
802
1001
|
* documented above — the callback form is reachable only via forced
|
|
803
1002
|
* casts in internal tests.
|
|
804
1003
|
*/
|
|
805
|
-
updateOne(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N
|
|
1004
|
+
updateOne(this: PipelineChain<TContract, Shape, 'update-ok', F, L, N>, updaterFn?: (fields: FieldAccessor<Shape, N>) => UpdaterResult): MongoQueryPlan<UpdateResult$1, UpdateOneCommand>;
|
|
806
1005
|
/**
|
|
807
1006
|
* Find a single document matching the accumulated pipeline (which must
|
|
808
1007
|
* consist solely of leading `$match` stages followed by at most one
|
|
@@ -816,23 +1015,23 @@ declare class PipelineChain<TContract extends MongoContractWithTypeMaps<MongoCon
|
|
|
816
1015
|
* runtime error is thrown as a defensive check (the type system should
|
|
817
1016
|
* prevent this).
|
|
818
1017
|
*/
|
|
819
|
-
findOneAndUpdate(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N
|
|
1018
|
+
findOneAndUpdate(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>, updaterFn: (fields: FieldAccessor<Shape, N>) => UpdaterResult, opts?: {
|
|
820
1019
|
readonly upsert?: boolean;
|
|
821
1020
|
readonly returnDocument?: 'before' | 'after';
|
|
822
|
-
}): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract
|
|
1021
|
+
}): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract> | null, FindOneAndUpdateCommand>;
|
|
823
1022
|
/**
|
|
824
1023
|
* Find a single document matching the accumulated pipeline and delete it.
|
|
825
1024
|
* Same marker gating and deconstruction as `findOneAndUpdate`.
|
|
826
1025
|
*/
|
|
827
|
-
findOneAndDelete(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N
|
|
1026
|
+
findOneAndDelete(this: PipelineChain<TContract, Shape, U, 'fam-ok', L, N>): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract> | null, FindOneAndDeleteCommand>;
|
|
828
1027
|
/**
|
|
829
1028
|
* Materialise the chain as a `MongoQueryPlan` wrapping an `AggregateCommand`.
|
|
830
1029
|
*/
|
|
831
|
-
build(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract
|
|
1030
|
+
build(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract>, AggregateCommand>;
|
|
832
1031
|
/**
|
|
833
1032
|
* Alias for `build()` — surfaces the read intent at the call site.
|
|
834
1033
|
*/
|
|
835
|
-
aggregate(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract
|
|
1034
|
+
aggregate(): MongoQueryPlan<ResolveRow<Shape, ExtractMongoCodecTypes<TContract>, TContract>, AggregateCommand>;
|
|
836
1035
|
}
|
|
837
1036
|
//#endregion
|
|
838
1037
|
//#region src/expression-helpers.d.ts
|
|
@@ -1158,12 +1357,12 @@ declare class FilteredCollection<TContract extends MongoContractWithTypeMaps<Mon
|
|
|
1158
1357
|
findOneAndUpdate(updaterFn: (fields: FieldAccessor<ModelToDocShape<TContract, ModelName>, ModelNestedShape<TContract, ModelName>>) => UpdaterResult, opts?: {
|
|
1159
1358
|
readonly upsert?: boolean;
|
|
1160
1359
|
readonly returnDocument?: 'before' | 'after';
|
|
1161
|
-
}): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract
|
|
1360
|
+
}): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>, TContract> | null, FindOneAndUpdateCommand>;
|
|
1162
1361
|
/**
|
|
1163
1362
|
* Find a single matching document and delete it. Returns the deleted
|
|
1164
1363
|
* document via the row stream.
|
|
1165
1364
|
*/
|
|
1166
|
-
findOneAndDelete(): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract
|
|
1365
|
+
findOneAndDelete(): MongoQueryPlan<ResolveRow<ModelToDocShape<TContract, ModelName>, ExtractMongoCodecTypes<TContract>, TContract> | null, FindOneAndDeleteCommand>;
|
|
1167
1366
|
}
|
|
1168
1367
|
/**
|
|
1169
1368
|
* Bound execution context shared across the three state classes.
|
|
@@ -1187,12 +1386,19 @@ interface BindingContext<TContract extends MongoContractWithTypeMaps<MongoContra
|
|
|
1187
1386
|
* cannot know what the caller's command yields.
|
|
1188
1387
|
*/
|
|
1189
1388
|
interface QueryRoot<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>> {
|
|
1190
|
-
from<K
|
|
1191
|
-
rawCommand<C
|
|
1389
|
+
from<K extends keyof TContract['roots'] & string>(rootName: K): CollectionHandle<TContract, TContract['roots'][K] & string & keyof TContract['models']>;
|
|
1390
|
+
rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C>;
|
|
1192
1391
|
}
|
|
1193
1392
|
declare function mongoQuery<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(options: {
|
|
1194
1393
|
contractJson: unknown;
|
|
1195
1394
|
}): QueryRoot<TContract>;
|
|
1196
1395
|
//#endregion
|
|
1197
|
-
|
|
1396
|
+
//#region src/result-shape.d.ts
|
|
1397
|
+
declare function contractFieldToMongoFieldShape(field: ContractField): MongoFieldShape;
|
|
1398
|
+
declare function contractModelToMongoResultShape(model: MongoModelDefinition, options?: {
|
|
1399
|
+
readonly selection?: readonly string[];
|
|
1400
|
+
readonly includeRelationNames?: readonly string[];
|
|
1401
|
+
}): MongoResultShape;
|
|
1402
|
+
//#endregion
|
|
1403
|
+
export { type ArrayField, type BooleanField, CollectionHandle, type DateField, type DeleteResult, type DocField, type DocShape, type Expression, type ExtractDocShape, type FieldAccessor, FilteredCollection, type FindAndModifyEnabled, type GroupSpec, type GroupedDocShape, type InsertManyResult, type InsertOneResult, type LeafExpression, type LiteralValue, type LookupBuilder, type LookupBuilderWithKey, type LookupFrom, type LookupOnResult, type LookupResult, type ModelArrayField, type ModelNestedShape, type ModelOf, type ModelToDocShape, type NestedDocShape, type NullableDocField, type NullableNumericField, type NumericField, type ObjectExpression, type ObjectField, type PathCompletions, PipelineChain, type ProjectedShape, type QueryRoot, type ResolvePath, type ResolveRow, type SortSpec, type StringField, type TypedAccumulatorExpr, type TypedAggExpr, type TypedUpdateOp, type UnwoundShape, type UpdateEnabled, type UpdateResult, type UpdaterResult, type ValidPaths, acc, contractFieldToMongoFieldShape, contractModelToMongoResultShape, createFieldAccessor, fn, mongoQuery };
|
|
1198
1404
|
//# sourceMappingURL=index.d.mts.map
|