@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/src/state-classes.ts
CHANGED
|
@@ -71,7 +71,6 @@ function writeMeta(storageHash: string): PlanMeta {
|
|
|
71
71
|
target: 'mongo',
|
|
72
72
|
storageHash,
|
|
73
73
|
lane: 'mongo-query',
|
|
74
|
-
paramDescriptors: [],
|
|
75
74
|
};
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -110,6 +109,7 @@ export class CollectionHandle<
|
|
|
110
109
|
collection: ctx.collection,
|
|
111
110
|
stages: [],
|
|
112
111
|
storageHash: ctx.storageHash,
|
|
112
|
+
modelName: modelName as string,
|
|
113
113
|
});
|
|
114
114
|
this.#ctx = ctx;
|
|
115
115
|
this.#modelName = modelName;
|
|
@@ -346,6 +346,7 @@ export class FilteredCollection<
|
|
|
346
346
|
collection: ctx.collection,
|
|
347
347
|
stages: [new MongoMatchStage(leading)],
|
|
348
348
|
storageHash: ctx.storageHash,
|
|
349
|
+
modelName: modelName as string,
|
|
349
350
|
});
|
|
350
351
|
this.#ctx = ctx;
|
|
351
352
|
this.#modelName = modelName;
|
|
@@ -545,7 +546,11 @@ export class FilteredCollection<
|
|
|
545
546
|
) => UpdaterResult,
|
|
546
547
|
opts: { readonly upsert?: boolean; readonly returnDocument?: 'before' | 'after' } = {},
|
|
547
548
|
): MongoQueryPlan<
|
|
548
|
-
ResolveRow<
|
|
549
|
+
ResolveRow<
|
|
550
|
+
ModelToDocShape<TContract, ModelName>,
|
|
551
|
+
ExtractMongoCodecTypes<TContract>,
|
|
552
|
+
TContract
|
|
553
|
+
> | null,
|
|
549
554
|
FindOneAndUpdateCommand
|
|
550
555
|
> {
|
|
551
556
|
const update = resolveUpdaterCallback<
|
|
@@ -572,7 +577,11 @@ export class FilteredCollection<
|
|
|
572
577
|
* document via the row stream.
|
|
573
578
|
*/
|
|
574
579
|
override findOneAndDelete(): MongoQueryPlan<
|
|
575
|
-
ResolveRow<
|
|
580
|
+
ResolveRow<
|
|
581
|
+
ModelToDocShape<TContract, ModelName>,
|
|
582
|
+
ExtractMongoCodecTypes<TContract>,
|
|
583
|
+
TContract
|
|
584
|
+
> | null,
|
|
576
585
|
FindOneAndDeleteCommand
|
|
577
586
|
> {
|
|
578
587
|
const command = new FindOneAndDeleteCommand(this.#ctx.collection, this.#foldedFilter());
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ExtractMongoTypeMaps,
|
|
3
|
+
InferModelRow,
|
|
4
|
+
MongoContract,
|
|
5
|
+
MongoContractWithTypeMaps,
|
|
6
|
+
MongoTypeMaps,
|
|
7
|
+
} from '@prisma-next/mongo-contract';
|
|
2
8
|
import type { MongoAggAccumulator, MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';
|
|
9
|
+
import type { ModelArrayField, ModelOriginBrand, ModelOriginBranded } from './resolve-path';
|
|
3
10
|
|
|
4
11
|
export interface DocField {
|
|
5
12
|
readonly codecId: string;
|
|
@@ -40,19 +47,103 @@ export type ModelToDocShape<
|
|
|
40
47
|
readonly codecId: ExtractCodecId<TContract['models'][ModelName]['fields'][K]>;
|
|
41
48
|
readonly nullable: TContract['models'][ModelName]['fields'][K]['nullable'];
|
|
42
49
|
};
|
|
43
|
-
}
|
|
50
|
+
} & ModelOriginBranded<ModelName>;
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Per-field resolver. Walks `Shape`'s string keys, routing
|
|
54
|
+
* `ModelArrayField` (the lookup marker) through `InferModelRow` and
|
|
55
|
+
* everything else through the codec-lookup branch.
|
|
56
|
+
*
|
|
57
|
+
* Internal helper — public callers should use `ResolveRow`, which adds
|
|
58
|
+
* the model-origin brand detection on top.
|
|
59
|
+
*/
|
|
60
|
+
type ResolveFields<
|
|
46
61
|
Shape extends DocShape,
|
|
47
62
|
CodecTypes extends Record<string, { readonly output: unknown }>,
|
|
63
|
+
TContract extends MongoContract,
|
|
48
64
|
> = {
|
|
49
|
-
-readonly [K in keyof Shape & string]: Shape[K]
|
|
50
|
-
?
|
|
51
|
-
?
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
-readonly [K in keyof Shape & string]: Shape[K] extends ModelArrayField<infer ModelName>
|
|
66
|
+
? IsConcreteContract<TContract> extends true
|
|
67
|
+
? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>
|
|
68
|
+
? ModelName extends string & keyof TContract['models']
|
|
69
|
+
? Array<InferModelRow<TContract, ModelName>>
|
|
70
|
+
: unknown[]
|
|
71
|
+
: unknown[]
|
|
72
|
+
: unknown[]
|
|
73
|
+
: Shape[K]['codecId'] extends keyof CodecTypes
|
|
74
|
+
? Shape[K]['nullable'] extends true
|
|
75
|
+
? CodecTypes[Shape[K]['codecId']]['output'] | null
|
|
76
|
+
: CodecTypes[Shape[K]['codecId']]['output']
|
|
77
|
+
: unknown;
|
|
54
78
|
};
|
|
55
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Resolve a `DocShape` to a concrete row object type.
|
|
82
|
+
*
|
|
83
|
+
* The optional `TContract` parameter exists so the resolver can:
|
|
84
|
+
*
|
|
85
|
+
* 1. Detect the `ModelOriginBrand` on `Shape` — the phantom symbol
|
|
86
|
+
* placed by `ModelToDocShape`. When present (and the contract has
|
|
87
|
+
* type maps), the row is resolved via `InferModelRow<TC, M>` from
|
|
88
|
+
* `@prisma-next/mongo-contract`, which walks scalar / valueObject /
|
|
89
|
+
* union field kinds (handling nested value-objects and `many: true`).
|
|
90
|
+
* This makes entry-point reads (`q.from('users').build()`) and
|
|
91
|
+
* shape-extending stages (`match`, `addFields`) resolve value-object
|
|
92
|
+
* fields to their concrete nested types instead of `unknown`.
|
|
93
|
+
*
|
|
94
|
+
* 2. Detect the per-field `ModelArrayField<ModelName>` marker produced
|
|
95
|
+
* by `lookup()` and resolve it to `Array<InferModelRow<TC, M>>` so
|
|
96
|
+
* lookup rows carry the same fully-typed foreign rows.
|
|
97
|
+
*
|
|
98
|
+
* When the contract is not threaded through (or lacks the type-map
|
|
99
|
+
* phantom), both branches fall back to `unknown` / `unknown[]` —
|
|
100
|
+
* preserving the legacy resolver shape for call sites that do not need
|
|
101
|
+
* model-row resolution.
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* Flatten an intersection `A & B` into a single object literal so callers
|
|
105
|
+
* (and `expectTypeOf().toEqualTypeOf<…>()`) see one homogeneous record
|
|
106
|
+
* rather than the intersection form. Vitest's strict equality check
|
|
107
|
+
* treats `A & B` as distinct from the structurally-equivalent flat
|
|
108
|
+
* record, even when assignability is bidirectional, so the
|
|
109
|
+
* `ResolveRow` brand-positive branch normalises its result through this.
|
|
110
|
+
*/
|
|
111
|
+
type Flatten<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Decide whether to route a brand-positive `ResolveRow` through
|
|
115
|
+
* `InferModelRow`. The default `MongoContract` (no concrete models)
|
|
116
|
+
* still satisfies `MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>`
|
|
117
|
+
* because the phantom key is optional, but `InferModelRow<MongoContract, …>`
|
|
118
|
+
* collapses to an empty/unknown row. Gate on the presence of the
|
|
119
|
+
* type-maps phantom: a concrete contract attaches concrete `TestTypeMaps`-
|
|
120
|
+
* shaped maps, while the default `MongoContract` has no phantom and
|
|
121
|
+
* `ExtractMongoTypeMaps` resolves to `never`.
|
|
122
|
+
*/
|
|
123
|
+
type IsConcreteContract<TContract> = [ExtractMongoTypeMaps<TContract>] extends [never]
|
|
124
|
+
? false
|
|
125
|
+
: true;
|
|
126
|
+
|
|
127
|
+
export type ResolveRow<
|
|
128
|
+
Shape extends DocShape,
|
|
129
|
+
CodecTypes extends Record<string, { readonly output: unknown }>,
|
|
130
|
+
TContract extends MongoContract = MongoContract,
|
|
131
|
+
> = Shape extends { readonly [ModelOriginBrand]?: infer ModelName extends string }
|
|
132
|
+
? IsConcreteContract<TContract> extends true
|
|
133
|
+
? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>
|
|
134
|
+
? ModelName extends string & keyof TContract['models']
|
|
135
|
+
? Flatten<
|
|
136
|
+
InferModelRow<TContract, ModelName> &
|
|
137
|
+
Omit<
|
|
138
|
+
ResolveFields<Shape, CodecTypes, TContract>,
|
|
139
|
+
keyof InferModelRow<TContract, ModelName>
|
|
140
|
+
>
|
|
141
|
+
>
|
|
142
|
+
: ResolveFields<Shape, CodecTypes, TContract>
|
|
143
|
+
: ResolveFields<Shape, CodecTypes, TContract>
|
|
144
|
+
: ResolveFields<Shape, CodecTypes, TContract>
|
|
145
|
+
: ResolveFields<Shape, CodecTypes, TContract>;
|
|
146
|
+
|
|
56
147
|
export interface TypedAggExpr<F extends DocField> {
|
|
57
148
|
readonly _field: F;
|
|
58
149
|
readonly node: MongoAggExpr;
|
|
@@ -108,6 +199,16 @@ export type GroupedDocShape<Spec extends GroupSpec> = {
|
|
|
108
199
|
*/
|
|
109
200
|
type UnwrapArrayDocField<F extends DocField> = F;
|
|
110
201
|
|
|
202
|
+
/**
|
|
203
|
+
* `$unwind` reshapes the array slot but leaves the rest of the document
|
|
204
|
+
* structurally intact. The mapped iteration is keyed on `keyof S & string`,
|
|
205
|
+
* which discards the symbol-keyed `ModelOriginBrand` carried by
|
|
206
|
+
* model-rooted shapes. Preserve the brand explicitly so post-unwind
|
|
207
|
+
* `ResolveRow` still routes through `InferModelRow` and value-object
|
|
208
|
+
* fields keep their concrete nested types.
|
|
209
|
+
*/
|
|
111
210
|
export type UnwoundShape<S extends DocShape, K extends keyof S & string> = {
|
|
112
211
|
[P in keyof S & string]: P extends K ? UnwrapArrayDocField<S[P]> : S[P];
|
|
113
|
-
}
|
|
212
|
+
} & (S extends ModelOriginBranded<infer ModelName extends string>
|
|
213
|
+
? ModelOriginBranded<ModelName>
|
|
214
|
+
: unknown);
|