@prisma-next/mongo-query-builder 0.5.0-dev.5 → 0.5.0-dev.50

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,14 +1,15 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo-query-builder",
3
- "version": "0.5.0-dev.5",
3
+ "version": "0.5.0-dev.50",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Type-safe MongoDB query builder (reads, writes, find-and-modify, pipeline-terminal writes) with document shape tracking",
7
7
  "dependencies": {
8
- "@prisma-next/mongo-contract": "0.5.0-dev.5",
9
- "@prisma-next/contract": "0.5.0-dev.5",
10
- "@prisma-next/mongo-query-ast": "0.5.0-dev.5",
11
- "@prisma-next/mongo-value": "0.5.0-dev.5"
8
+ "@prisma-next/contract": "0.5.0-dev.50",
9
+ "@prisma-next/mongo-query-ast": "0.5.0-dev.50",
10
+ "@prisma-next/utils": "0.5.0-dev.50",
11
+ "@prisma-next/mongo-contract": "0.5.0-dev.50",
12
+ "@prisma-next/mongo-value": "0.5.0-dev.50"
12
13
  },
13
14
  "devDependencies": {
14
15
  "tsdown": "0.18.4",
package/src/builder.ts CHANGED
@@ -3,6 +3,7 @@ import type {
3
3
  ExtractMongoCodecTypes,
4
4
  MongoContract,
5
5
  MongoContractWithTypeMaps,
6
+ MongoModelDefinition,
6
7
  MongoTypeMaps,
7
8
  } from '@prisma-next/mongo-contract';
8
9
  import type {
@@ -14,6 +15,7 @@ import type {
14
15
  MongoPipelineStage,
15
16
  MongoProjectionValue,
16
17
  MongoQueryPlan,
18
+ MongoResultShape,
17
19
  MongoUpdatePipelineStage,
18
20
  MongoWindowField,
19
21
  UpdateResult,
@@ -54,9 +56,12 @@ import {
54
56
  UpdateManyCommand,
55
57
  UpdateOneCommand,
56
58
  } from '@prisma-next/mongo-query-ast/execution';
59
+ import { ifDefined } from '@prisma-next/utils/defined';
57
60
  import { createFieldAccessor, type Expression, type FieldAccessor } from './field-accessor';
58
61
  import type { FindAndModifyEnabled, LeadingMatch, UpdateEnabled } from './markers';
62
+ import { pipelineSupportsFlatResultShape } from './pipeline-result-shape';
59
63
  import type { NestedDocShape } from './resolve-path';
64
+ import { contractModelToMongoResultShape } from './result-shape';
60
65
  import type {
61
66
  DocField,
62
67
  DocShape,
@@ -75,6 +80,7 @@ interface PipelineChainState {
75
80
  readonly collection: string;
76
81
  readonly stages: ReadonlyArray<MongoPipelineStage>;
77
82
  readonly storageHash: string;
83
+ readonly modelName?: string;
78
84
  }
79
85
 
80
86
  /**
@@ -148,7 +154,6 @@ export class PipelineChain<
148
154
  target: 'mongo',
149
155
  storageHash: this.#state.storageHash,
150
156
  lane: 'mongo-query',
151
- paramDescriptors: [],
152
157
  };
153
158
  }
154
159
 
@@ -509,7 +514,6 @@ export class PipelineChain<
509
514
  target: 'mongo',
510
515
  storageHash: this.#state.storageHash,
511
516
  lane: 'mongo-query',
512
- paramDescriptors: [],
513
517
  };
514
518
  return { collection: this.#state.collection, command, meta };
515
519
  }
@@ -767,7 +771,6 @@ export class PipelineChain<
767
771
  target: 'mongo',
768
772
  storageHash: this.#state.storageHash,
769
773
  lane: 'mongo-query',
770
- paramDescriptors: [],
771
774
  };
772
775
  return { collection: this.#state.collection, command, meta };
773
776
  }
@@ -788,7 +791,6 @@ export class PipelineChain<
788
791
  target: 'mongo',
789
792
  storageHash: this.#state.storageHash,
790
793
  lane: 'mongo-query',
791
- paramDescriptors: [],
792
794
  };
793
795
  return { collection: this.#state.collection, command, meta };
794
796
  }
@@ -804,9 +806,24 @@ export class PipelineChain<
804
806
  target: 'mongo',
805
807
  storageHash: this.#state.storageHash,
806
808
  lane: 'mongo-query',
807
- paramDescriptors: [],
808
809
  };
809
- return { collection: this.#state.collection, command, meta };
810
+ const modelName = this.#state.modelName;
811
+ const contractNarrow = this.#contract as MongoContract;
812
+ let resultShape: MongoResultShape | undefined;
813
+ if (modelName !== undefined) {
814
+ if (pipelineSupportsFlatResultShape(this.#state.stages)) {
815
+ const model = contractNarrow.models[modelName] as MongoModelDefinition | undefined;
816
+ resultShape = model ? contractModelToMongoResultShape(model) : { kind: 'unknown' as const };
817
+ } else {
818
+ resultShape = { kind: 'unknown' as const };
819
+ }
820
+ }
821
+ return {
822
+ collection: this.#state.collection,
823
+ command,
824
+ meta,
825
+ ...ifDefined('resultShape', resultShape),
826
+ };
810
827
  }
811
828
 
812
829
  /**
@@ -25,6 +25,10 @@ export type {
25
25
  ResolvePath,
26
26
  ValidPaths,
27
27
  } from '../resolve-path';
28
+ export {
29
+ contractFieldToMongoFieldShape,
30
+ contractModelToMongoResultShape,
31
+ } from '../result-shape';
28
32
  export { CollectionHandle, FilteredCollection } from '../state-classes';
29
33
  export type {
30
34
  ArrayField,
@@ -0,0 +1,15 @@
1
+ import type { MongoPipelineStage } from '@prisma-next/mongo-query-ast/execution';
2
+
3
+ const identityStageKinds = new Set(['match', 'sort', 'limit', 'skip', 'sample']);
4
+
5
+ export function pipelineSupportsFlatResultShape(
6
+ stages: ReadonlyArray<MongoPipelineStage>,
7
+ ): boolean {
8
+ for (const stage of stages) {
9
+ const k = stage.kind;
10
+ if (!identityStageKinds.has(k)) {
11
+ return false;
12
+ }
13
+ }
14
+ return true;
15
+ }
package/src/query.ts CHANGED
@@ -47,7 +47,6 @@ export function mongoQuery<
47
47
  target: 'mongo',
48
48
  storageHash: String(storageHash),
49
49
  lane: 'mongo-query',
50
- paramDescriptors: [],
51
50
  };
52
51
  return { collection: command.collection, command, meta };
53
52
  },
@@ -0,0 +1,63 @@
1
+ import type { ContractField } from '@prisma-next/contract/types';
2
+ import type { MongoModelDefinition } from '@prisma-next/mongo-contract';
3
+ import type { MongoFieldShape, MongoResultShape } from '@prisma-next/mongo-query-ast/execution';
4
+ import {
5
+ freezeMongoFieldShape,
6
+ freezeMongoResultShape,
7
+ } from '@prisma-next/mongo-query-ast/execution';
8
+
9
+ export function contractFieldToMongoFieldShape(field: ContractField): MongoFieldShape {
10
+ const { type, nullable, many } = field;
11
+ if (type.kind === 'valueObject' || type.kind === 'union') {
12
+ return Object.freeze({ kind: 'unknown' as const });
13
+ }
14
+ if (type.kind !== 'scalar') {
15
+ return Object.freeze({ kind: 'unknown' as const });
16
+ }
17
+ if (field.dict === true) {
18
+ return Object.freeze({ kind: 'unknown' as const });
19
+ }
20
+ if (many === true) {
21
+ return freezeMongoFieldShape({
22
+ kind: 'array',
23
+ nullable,
24
+ element: { kind: 'leaf', codecId: type.codecId, nullable: false },
25
+ });
26
+ }
27
+ return freezeMongoFieldShape({
28
+ kind: 'leaf',
29
+ codecId: type.codecId,
30
+ nullable,
31
+ });
32
+ }
33
+
34
+ export function contractModelToMongoResultShape(
35
+ model: MongoModelDefinition,
36
+ options?: {
37
+ readonly selection?: readonly string[];
38
+ readonly includeRelationNames?: readonly string[];
39
+ },
40
+ ): MongoResultShape {
41
+ const fields: Record<string, MongoFieldShape> = {};
42
+ for (const rel of options?.includeRelationNames ?? []) {
43
+ fields[rel] = Object.freeze({ kind: 'unknown' as const });
44
+ }
45
+ const modelFields = model.fields;
46
+ // An explicit empty selection is honored as-is (returns a document shape
47
+ // with no fields). Only the absence of a selection falls back to the model's
48
+ // full field set.
49
+ const keys = options?.selection !== undefined ? options.selection : Object.keys(modelFields);
50
+
51
+ for (const key of keys) {
52
+ if (Object.hasOwn(fields, key)) {
53
+ continue;
54
+ }
55
+ const cf = modelFields[key];
56
+ if (!cf) {
57
+ fields[key] = Object.freeze({ kind: 'unknown' as const });
58
+ continue;
59
+ }
60
+ fields[key] = contractFieldToMongoFieldShape(cf);
61
+ }
62
+ return freezeMongoResultShape({ kind: 'document', fields });
63
+ }
@@ -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;