@prisma-next/mongo-query-builder 0.11.0-dev.9 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,33 +1,44 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo-query-builder",
3
- "version": "0.11.0-dev.9",
3
+ "version": "0.12.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Type-safe MongoDB query builder (reads, writes, find-and-modify, pipeline-terminal writes) with document shape tracking",
8
8
  "dependencies": {
9
- "@prisma-next/contract": "0.11.0-dev.9",
10
- "@prisma-next/mongo-contract": "0.11.0-dev.9",
11
- "@prisma-next/mongo-query-ast": "0.11.0-dev.9",
12
- "@prisma-next/mongo-value": "0.11.0-dev.9",
13
- "@prisma-next/utils": "0.11.0-dev.9"
9
+ "@prisma-next/contract": "0.12.0",
10
+ "@prisma-next/mongo-contract": "0.12.0",
11
+ "@prisma-next/mongo-query-ast": "0.12.0",
12
+ "@prisma-next/mongo-value": "0.12.0",
13
+ "@prisma-next/utils": "0.12.0"
14
14
  },
15
15
  "devDependencies": {
16
- "@prisma-next/tsconfig": "0.11.0-dev.9",
17
- "@prisma-next/tsdown": "0.11.0-dev.9",
16
+ "@prisma-next/tsconfig": "0.12.0",
17
+ "@prisma-next/tsdown": "0.12.0",
18
18
  "tsdown": "0.22.0",
19
19
  "typescript": "5.9.3",
20
20
  "vitest": "4.1.6"
21
21
  },
22
+ "peerDependencies": {
23
+ "typescript": ">=5.9"
24
+ },
25
+ "peerDependenciesMeta": {
26
+ "typescript": {
27
+ "optional": true
28
+ }
29
+ },
22
30
  "files": [
23
31
  "dist",
24
32
  "src"
25
33
  ],
34
+ "types": "./dist/index.d.mts",
26
35
  "exports": {
27
36
  ".": "./dist/index.mjs",
28
37
  "./package.json": "./package.json"
29
38
  },
30
- "types": "./dist/index.d.mts",
39
+ "engines": {
40
+ "node": ">=24"
41
+ },
31
42
  "repository": {
32
43
  "type": "git",
33
44
  "url": "https://github.com/prisma/prisma-next.git",
package/src/builder.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PlanMeta } from '@prisma-next/contract/types';
1
+ import { contractModels, type PlanMeta } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  ExtractMongoCodecTypes,
4
4
  MongoContract,
@@ -820,7 +820,7 @@ export class PipelineChain<
820
820
  let resultShape: MongoResultShape | undefined;
821
821
  if (modelName !== undefined) {
822
822
  if (pipelineSupportsFlatResultShape(this.#state.stages)) {
823
- const model = contractNarrow.models[modelName] as MongoModelDefinition | undefined;
823
+ const model = contractModels(contractNarrow)[modelName] as MongoModelDefinition | undefined;
824
824
  resultShape = model ? contractModelToMongoResultShape(model) : { kind: 'unknown' as const };
825
825
  } else {
826
826
  resultShape = { kind: 'unknown' as const };
@@ -1,20 +1,26 @@
1
- import type { MongoContract } from '@prisma-next/mongo-contract';
1
+ import { contractModels } from '@prisma-next/contract/types';
2
+ import type {
3
+ MongoContract,
4
+ MongoModelDefinition,
5
+ MongoModelsMap,
6
+ RootModelName,
7
+ } from '@prisma-next/mongo-contract';
2
8
  import { createFieldAccessor, type FieldAccessor, type LeafExpression } from './field-accessor';
3
9
  import type { ModelNestedShape } from './resolve-path';
4
10
  import type { DocField, DocShape, ModelToDocShape } from './types';
5
11
 
6
12
  /**
7
13
  * Resolved foreign-model name for a contract root. Looks `RootName` up
8
- * through `TContract['roots']` and intersects the result back with
9
- * `keyof TContract['models']` so it can be used as a `ModelName` index
10
- * into `models`. Resolves to `never` when the root is not present (this
11
- * surface should never be reachable through normal use because `from()`
12
- * constrains its `R` parameter to `keyof TContract['roots']`).
14
+ * through `TContract['roots']` and extracts the referenced model name
15
+ * so it can be used as a `ModelName` index into `models`. Resolves to
16
+ * `never` when the root is not present (this surface should never be
17
+ * reachable through normal use because `from()` constrains its `R`
18
+ * parameter to `keyof TContract['roots']`).
13
19
  */
14
20
  export type ModelOf<
15
21
  TContract extends MongoContract,
16
22
  RootName extends keyof TContract['roots'] & string,
17
- > = TContract['roots'][RootName] & string & keyof TContract['models'];
23
+ > = RootModelName<TContract, RootName>;
18
24
 
19
25
  /**
20
26
  * Object returned by the user from the `on(...)` callback. Each side is
@@ -92,7 +98,7 @@ export interface LookupBuilder<
92
98
  on(
93
99
  cb: (
94
100
  local: FieldAccessor<Shape, Nested>,
95
- foreign: ModelName extends keyof TContract['models'] & string
101
+ foreign: ModelName extends keyof MongoModelsMap<TContract> & string
96
102
  ? FieldAccessor<
97
103
  ModelToDocShape<TContract, ModelName>,
98
104
  ModelNestedShape<TContract, ModelName>
@@ -137,12 +143,12 @@ export function createLookupFrom<
137
143
  Nested extends Record<string, DocField>,
138
144
  >(contract: TContract): LookupFrom<TContract, Shape, Nested> {
139
145
  const callable = ((rootName) => {
140
- const modelName = contract.roots[rootName];
146
+ const modelName = contract.roots[rootName]?.model;
141
147
  if (!modelName) {
142
148
  const validRoots = Object.keys(contract.roots).join(', ');
143
149
  throw new Error(`lookup() unknown root: "${rootName}". Valid roots: ${validRoots}`);
144
150
  }
145
- const model = contract.models[modelName];
151
+ const model = contractModels(contract)[modelName] as MongoModelDefinition | undefined;
146
152
  const foreignCollection = model?.storage?.collection ?? rootName;
147
153
  return createLookupBuilder({
148
154
  rootName,
@@ -260,7 +266,7 @@ export function extractLookupResult(
260
266
  'Returning a hand-rolled options object is not supported.',
261
267
  );
262
268
  }
263
- const model = contract.models[result._model];
269
+ const model = contractModels(contract)[result._model] as MongoModelDefinition | undefined;
264
270
  const foreignCollection = model?.storage?.collection ?? result._root;
265
271
  return {
266
272
  foreignCollection,
package/src/query.ts CHANGED
@@ -3,8 +3,10 @@ import type {
3
3
  MongoContract,
4
4
  MongoContractWithTypeMaps,
5
5
  MongoTypeMaps,
6
+ RootModelName,
6
7
  } from '@prisma-next/mongo-contract';
7
8
  import type { AnyMongoCommand, MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';
9
+ import { blindCast } from '@prisma-next/utils/casts';
8
10
  import { asMongoContract, type CollectionHandle, createCollectionHandle } from './state-classes';
9
11
 
10
12
  /**
@@ -23,14 +25,17 @@ export interface QueryRoot<
23
25
  > {
24
26
  from<K extends keyof TContract['roots'] & string>(
25
27
  rootName: K,
26
- ): CollectionHandle<TContract, TContract['roots'][K] & string & keyof TContract['models']>;
28
+ ): CollectionHandle<TContract, RootModelName<TContract, K>>;
27
29
  rawCommand<C extends AnyMongoCommand>(command: C): MongoQueryPlan<unknown, C>;
28
30
  }
29
31
 
30
32
  export function mongoQuery<
31
33
  TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
32
34
  >(options: { contractJson: unknown }): QueryRoot<TContract> {
33
- const contract = options.contractJson as TContract;
35
+ const contract = blindCast<
36
+ TContract,
37
+ 'mongoQuery accepts validated contract JSON with domain.namespaces'
38
+ >(options.contractJson);
34
39
  return {
35
40
  from<K extends keyof TContract['roots'] & string>(rootName: K) {
36
41
  return createCollectionHandle(contract, rootName);
@@ -1,4 +1,5 @@
1
- import type { MongoContract } from '@prisma-next/mongo-contract';
1
+ import type { ContractValueObjectsMap } from '@prisma-next/contract/types';
2
+ import type { MongoContract, MongoModelsMap } from '@prisma-next/mongo-contract';
2
3
  import type { DocField } from './types';
3
4
 
4
5
  /**
@@ -95,10 +96,6 @@ export type NestedDocShape = Record<string, DocField>;
95
96
 
96
97
  // ── Contract → NestedDocShape translation ────────────────────────────────
97
98
 
98
- type ContractHasValueObjects = {
99
- readonly valueObjects?: Record<string, { readonly fields: Record<string, unknown> }>;
100
- };
101
-
102
99
  type FieldToLeaf<F> = F extends {
103
100
  readonly type: { readonly kind: 'scalar'; readonly codecId: infer C extends string };
104
101
  readonly nullable: infer N extends boolean;
@@ -122,7 +119,7 @@ type FieldToLeaf<F> = F extends {
122
119
  * `ModelNestedShape` hover output and `keyof`/indexed-access resolution
123
120
  * concrete instead of collapsing to `{ [x: string]: … }`.
124
121
  */
125
- type TranslateField<TContract extends ContractHasValueObjects, F> = F extends {
122
+ type TranslateField<TContract extends MongoContract, F> = F extends {
126
123
  readonly many: true;
127
124
  }
128
125
  ? FieldToLeaf<F>
@@ -147,16 +144,10 @@ type TranslateField<TContract extends ContractHasValueObjects, F> = F extends {
147
144
  * `VOs[VOName]['fields']` is preserved and the hover / indexed-access
148
145
  * surface stays concrete at instantiation time.
149
146
  */
150
- type VONestedShape<
151
- TContract extends ContractHasValueObjects,
152
- VOName extends string,
153
- > = TContract extends {
154
- readonly valueObjects: infer VOs extends Record<
155
- string,
156
- { readonly fields: Record<string, unknown> }
157
- >;
158
- }
159
- ? VOName extends keyof VOs
147
+ type VONestedShape<TContract extends MongoContract, VOName extends string> = [
148
+ ContractValueObjectsMap<TContract>,
149
+ ] extends [infer VOs extends Record<string, { readonly fields: Record<string, unknown> }>]
150
+ ? VOName extends keyof VOs & string
160
151
  ? {
161
152
  readonly [K in keyof VOs[VOName]['fields'] & string]: TranslateField<
162
153
  TContract,
@@ -174,7 +165,7 @@ type VONestedShape<
174
165
  *
175
166
  * The mapped iteration is inlined (not hidden behind a helper type that
176
167
  * takes `Fields` as a generic) so TypeScript recognises the mapped type
177
- * as homomorphic over `TContract['models'][ModelName]['fields']`. That
168
+ * as homomorphic over `MongoModelsMap<TContract>[ModelName]['fields']`. That
178
169
  * preserves the literal field-name keys at instantiation — without this,
179
170
  * the intersection of `Record<string, ContractField>` and the specific
180
171
  * literal field record collapses `keyof` to `string` and the result hover
@@ -182,11 +173,11 @@ type VONestedShape<
182
173
  */
183
174
  export type ModelNestedShape<
184
175
  TContract extends MongoContract,
185
- ModelName extends string & keyof TContract['models'],
176
+ ModelName extends string & keyof MongoModelsMap<TContract>,
186
177
  > = {
187
- readonly [K in keyof TContract['models'][ModelName]['fields'] & string]: TranslateField<
188
- TContract & ContractHasValueObjects,
189
- TContract['models'][ModelName]['fields'][K]
178
+ readonly [K in keyof MongoModelsMap<TContract>[ModelName]['fields'] & string]: TranslateField<
179
+ TContract,
180
+ MongoModelsMap<TContract>[ModelName]['fields'][K]
190
181
  >;
191
182
  };
192
183
 
@@ -1,9 +1,12 @@
1
- import type { PlanMeta } from '@prisma-next/contract/types';
1
+ import { contractModels, type PlanMeta } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  ExtractMongoCodecTypes,
4
4
  MongoContract,
5
5
  MongoContractWithTypeMaps,
6
+ MongoModelDefinition,
7
+ MongoModelsMap,
6
8
  MongoTypeMaps,
9
+ RootModelName,
7
10
  } from '@prisma-next/mongo-contract';
8
11
  import type {
9
12
  DeleteResult,
@@ -92,7 +95,7 @@ function writeMeta(storageHash: string): PlanMeta {
92
95
  */
93
96
  export class CollectionHandle<
94
97
  TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
95
- ModelName extends keyof TContract['models'] & string,
98
+ ModelName extends keyof MongoModelsMap<TContract> & string,
96
99
  > extends PipelineChain<
97
100
  TContract,
98
101
  ModelToDocShape<TContract, ModelName>,
@@ -316,7 +319,7 @@ export class CollectionHandle<
316
319
  */
317
320
  export class FilteredCollection<
318
321
  TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
319
- ModelName extends keyof TContract['models'] & string,
322
+ ModelName extends keyof MongoModelsMap<TContract> & string,
320
323
  > extends PipelineChain<
321
324
  TContract,
322
325
  ModelToDocShape<TContract, ModelName>,
@@ -632,18 +635,18 @@ export function createCollectionHandle<
632
635
  >(
633
636
  contract: TContract,
634
637
  rootName: RootName,
635
- ): CollectionHandle<TContract, TContract['roots'][RootName] & string & keyof TContract['models']> {
638
+ ): CollectionHandle<TContract, RootModelName<TContract, RootName>> {
636
639
  const c = asMongoContract(contract);
637
- const modelName = c.roots[rootName];
640
+ const modelName = c.roots[rootName]?.model;
638
641
  if (!modelName) {
639
642
  const validRoots = Object.keys(c.roots).join(', ');
640
643
  throw new Error(`Unknown root: "${rootName}". Valid roots: ${validRoots}`);
641
644
  }
642
- const model = c.models[modelName];
645
+ const model = contractModels(c)[modelName] as MongoModelDefinition | undefined;
643
646
  if (!model) {
644
647
  throw new Error(`Unknown model: "${modelName}" referenced by root "${rootName}".`);
645
648
  }
646
- const collectionName = model.storage?.collection ?? rootName;
649
+ const collectionName = model.storage.collection ?? rootName;
647
650
  if (!c.storage?.storageHash) {
648
651
  throw new Error(
649
652
  'Contract is missing storage.storageHash. Pass a validated contract to mongoQuery().',
@@ -655,6 +658,6 @@ export function createCollectionHandle<
655
658
  collection: collectionName,
656
659
  storageHash: String(c.storage.storageHash),
657
660
  },
658
- modelName as TContract['roots'][RootName] & string & keyof TContract['models'],
661
+ modelName as RootModelName<TContract, RootName>,
659
662
  );
660
663
  }
package/src/types.ts CHANGED
@@ -3,6 +3,7 @@ import type {
3
3
  InferModelRow,
4
4
  MongoContract,
5
5
  MongoContractWithTypeMaps,
6
+ MongoModelsMap,
6
7
  MongoTypeMaps,
7
8
  } from '@prisma-next/mongo-contract';
8
9
  import type { MongoAggAccumulator, MongoAggExpr } from '@prisma-next/mongo-query-ast/execution';
@@ -41,11 +42,11 @@ type ExtractCodecId<F> = F extends { type: { kind: 'scalar'; codecId: infer C }
41
42
 
42
43
  export type ModelToDocShape<
43
44
  TContract extends MongoContract,
44
- ModelName extends string & keyof TContract['models'],
45
+ ModelName extends string & keyof MongoModelsMap<TContract>,
45
46
  > = {
46
- [K in keyof TContract['models'][ModelName]['fields'] & string]: {
47
- readonly codecId: ExtractCodecId<TContract['models'][ModelName]['fields'][K]>;
48
- readonly nullable: TContract['models'][ModelName]['fields'][K]['nullable'];
47
+ [K in keyof MongoModelsMap<TContract>[ModelName]['fields'] & string]: {
48
+ readonly codecId: ExtractCodecId<MongoModelsMap<TContract>[ModelName]['fields'][K]>;
49
+ readonly nullable: MongoModelsMap<TContract>[ModelName]['fields'][K]['nullable'];
49
50
  };
50
51
  } & ModelOriginBranded<ModelName>;
51
52
 
@@ -65,7 +66,7 @@ type ResolveFields<
65
66
  -readonly [K in keyof Shape & string]: Shape[K] extends ModelArrayField<infer ModelName>
66
67
  ? IsConcreteContract<TContract> extends true
67
68
  ? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>
68
- ? ModelName extends string & keyof TContract['models']
69
+ ? ModelName extends string & keyof MongoModelsMap<TContract>
69
70
  ? Array<InferModelRow<TContract, ModelName>>
70
71
  : unknown[]
71
72
  : unknown[]
@@ -131,7 +132,7 @@ export type ResolveRow<
131
132
  > = Shape extends { readonly [ModelOriginBrand]?: infer ModelName extends string }
132
133
  ? IsConcreteContract<TContract> extends true
133
134
  ? TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>
134
- ? ModelName extends string & keyof TContract['models']
135
+ ? ModelName extends string & keyof MongoModelsMap<TContract>
135
136
  ? Flatten<
136
137
  InferModelRow<TContract, ModelName> &
137
138
  Omit<