@prisma-next/mongo-query-builder 0.5.0-dev.5 → 0.5.0-dev.51
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/dist/index.d.mts +12 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +82 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/builder.ts +23 -6
- package/src/exports/index.ts +4 -0
- package/src/pipeline-result-shape.ts +15 -0
- package/src/query.ts +0 -1
- package/src/result-shape.ts +63 -0
- package/src/state-classes.ts +2 -1
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/mongo-query-builder",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.51",
|
|
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.
|
|
9
|
-
"@prisma-next/contract": "0.5.0-dev.
|
|
10
|
-
"@prisma-next/mongo-query-ast": "0.5.0-dev.
|
|
11
|
-
"@prisma-next/mongo-value": "0.5.0-dev.
|
|
8
|
+
"@prisma-next/mongo-contract": "0.5.0-dev.51",
|
|
9
|
+
"@prisma-next/contract": "0.5.0-dev.51",
|
|
10
|
+
"@prisma-next/mongo-query-ast": "0.5.0-dev.51",
|
|
11
|
+
"@prisma-next/mongo-value": "0.5.0-dev.51",
|
|
12
|
+
"@prisma-next/utils": "0.5.0-dev.51"
|
|
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
|
-
|
|
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
|
/**
|
package/src/exports/index.ts
CHANGED
|
@@ -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
|
@@ -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
|
+
}
|
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;
|