@prisma-next/mongo-orm 0.0.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 +19 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +77 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +46 -0
- package/src/exports/index.ts +15 -0
- package/src/mongo-orm.ts +145 -0
- package/src/types.ts +181 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @prisma-next/mongo-orm
|
|
2
|
+
|
|
3
|
+
MongoDB ORM client for Prisma Next.
|
|
4
|
+
|
|
5
|
+
## Responsibilities
|
|
6
|
+
|
|
7
|
+
- **ORM client factory**: `mongoOrm()` creates a typed client with root-based collection accessors
|
|
8
|
+
- **Typed queries**: `findMany` with equality filters (`MongoWhereFilter`) and reference includes (`MongoIncludeSpec`)
|
|
9
|
+
- **Row type inference**: `InferFullRow` (scalar fields + embedded documents), `InferRootRow` (discriminated union for polymorphic roots), `IncludeResultFields`
|
|
10
|
+
- **Polymorphic narrowing**: Discriminator field carries literal variant values, enabling TypeScript `switch`/`if` narrowing
|
|
11
|
+
- **Execution interface**: Declares `MongoQueryExecutor` interface structurally satisfied by the runtime layer
|
|
12
|
+
|
|
13
|
+
## Dependencies
|
|
14
|
+
|
|
15
|
+
- **Depends on**:
|
|
16
|
+
- `@prisma-next/mongo-core` (contract types, row inference, query plan types)
|
|
17
|
+
- `@prisma-next/runtime-executor` (`AsyncIterableResult` return type)
|
|
18
|
+
- **Depended on by**:
|
|
19
|
+
- `@prisma-next/mongo-runtime` (structurally satisfies `MongoQueryExecutor`)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ExtractMongoCodecTypes, InferModelRow, MongoContract, MongoContractWithTypeMaps, MongoQueryPlan, MongoTypeMaps } from "@prisma-next/mongo-core";
|
|
2
|
+
import { AsyncIterableResult } from "@prisma-next/runtime-executor";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
interface MongoQueryExecutor {
|
|
6
|
+
execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row>;
|
|
7
|
+
}
|
|
8
|
+
interface MongoOrmOptions<TContract extends MongoContract> {
|
|
9
|
+
readonly contract: TContract;
|
|
10
|
+
readonly executor: MongoQueryExecutor;
|
|
11
|
+
}
|
|
12
|
+
type Simplify<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
|
13
|
+
type ReferenceRelationKeys<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { [K in keyof TContract['models'][ModelName]['relations']]: TContract['models'][ModelName]['relations'][K] extends {
|
|
14
|
+
readonly strategy: 'reference';
|
|
15
|
+
} ? K : never }[keyof TContract['models'][ModelName]['relations']];
|
|
16
|
+
type EmbedRelationKeys<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { [K in keyof TContract['models'][ModelName]['relations']]: TContract['models'][ModelName]['relations'][K] extends {
|
|
17
|
+
readonly strategy: 'embed';
|
|
18
|
+
} ? K : never }[keyof TContract['models'][ModelName]['relations']];
|
|
19
|
+
type EmbedRelationRowType<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models'], RelKey extends keyof TContract['models'][ModelName]['relations']> = TContract['models'][ModelName]['relations'][RelKey] extends {
|
|
20
|
+
readonly to: infer To extends string & keyof TContract['models'];
|
|
21
|
+
readonly cardinality: infer C;
|
|
22
|
+
readonly strategy: 'embed';
|
|
23
|
+
} ? C extends '1:N' ? InferModelRow<TContract, To>[] : InferModelRow<TContract, To> : never;
|
|
24
|
+
type InferFullRow<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models']> = EmbedRelationKeys<TContract, ModelName> extends never ? InferModelRow<TContract, ModelName> : InferModelRow<TContract, ModelName> & { -readonly [K in EmbedRelationKeys<TContract, ModelName> & keyof TContract['models'][ModelName]['relations']]: EmbedRelationRowType<TContract, ModelName, K> };
|
|
25
|
+
type VariantRow<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models']> = TContract['models'][ModelName] extends {
|
|
26
|
+
readonly discriminator: {
|
|
27
|
+
readonly field: infer DiscField extends string;
|
|
28
|
+
};
|
|
29
|
+
readonly variants: infer V;
|
|
30
|
+
} ? V extends Record<string, {
|
|
31
|
+
readonly value: string;
|
|
32
|
+
}> ? { [VK in keyof V]: VK extends string & keyof TContract['models'] ? Simplify<Omit<InferFullRow<TContract, ModelName>, DiscField> & InferFullRow<TContract, VK> & Record<DiscField, V[VK]['value']>> : never }[keyof V] : InferFullRow<TContract, ModelName> : InferFullRow<TContract, ModelName>;
|
|
33
|
+
type InferRootRow<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models']> = VariantRow<TContract, ModelName>;
|
|
34
|
+
type IncludeRelationRowType<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models'], RelKey extends keyof TContract['models'][ModelName]['relations']> = TContract['models'][ModelName]['relations'][RelKey] extends {
|
|
35
|
+
readonly to: infer To extends string & keyof TContract['models'];
|
|
36
|
+
readonly cardinality: infer C;
|
|
37
|
+
readonly strategy: 'reference';
|
|
38
|
+
} ? C extends 'N:1' | '1:1' ? InferFullRow<TContract, To> | null : InferFullRow<TContract, To>[] : never;
|
|
39
|
+
type IncludeResultFields<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models'], TInclude extends MongoIncludeSpec<TContract, ModelName>> = { -readonly [K in keyof TInclude & string as TInclude[K] extends true ? K : never]: K extends keyof TContract['models'][ModelName]['relations'] ? IncludeRelationRowType<TContract, ModelName, K> : never };
|
|
40
|
+
type MongoWhereFilter<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models'], TCodecTypes extends Record<string, {
|
|
41
|
+
output: unknown;
|
|
42
|
+
}> = ExtractMongoCodecTypes<TContract>> = { readonly [K in keyof TContract['models'][ModelName]['fields']]?: TContract['models'][ModelName]['fields'][K] extends {
|
|
43
|
+
readonly codecId: infer CId extends string & keyof TCodecTypes;
|
|
44
|
+
} ? TCodecTypes[CId]['output'] : unknown };
|
|
45
|
+
type MongoIncludeSpec<TContract extends MongoContract, ModelName extends string & keyof TContract['models']> = { readonly [K in ReferenceRelationKeys<TContract, ModelName>]?: true };
|
|
46
|
+
interface MongoFindManyOptions<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models'], TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>> {
|
|
47
|
+
readonly where?: MongoWhereFilter<TContract, ModelName>;
|
|
48
|
+
readonly include?: TInclude;
|
|
49
|
+
}
|
|
50
|
+
type MongoOrmClient<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>> = { readonly [K in keyof TContract['roots']]: TContract['roots'][K] extends string & keyof TContract['models'] ? MongoCollection<TContract, TContract['roots'][K]> : never };
|
|
51
|
+
interface MongoCollection<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>, ModelName extends string & keyof TContract['models']> {
|
|
52
|
+
findMany<TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>>(options?: MongoFindManyOptions<TContract, ModelName, TInclude>): AsyncIterableResult<InferRootRow<TContract, ModelName> & IncludeResultFields<TContract, ModelName, TInclude>>;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/mongo-orm.d.ts
|
|
56
|
+
declare function mongoOrm<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(options: MongoOrmOptions<TContract>): MongoOrmClient<TContract>;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { type EmbedRelationKeys, type IncludeResultFields, type InferFullRow, type InferRootRow, type MongoCollection, type MongoFindManyOptions, type MongoIncludeSpec, type MongoOrmClient, type MongoOrmOptions, type MongoQueryExecutor, type MongoWhereFilter, type ReferenceRelationKeys, mongoOrm };
|
|
59
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/mongo-orm.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { AggregateCommand, FindCommand } from "@prisma-next/mongo-core";
|
|
2
|
+
|
|
3
|
+
//#region src/mongo-orm.ts
|
|
4
|
+
const stubMeta = {
|
|
5
|
+
target: "mongo",
|
|
6
|
+
storageHash: "orm",
|
|
7
|
+
lane: "mongo-orm",
|
|
8
|
+
paramDescriptors: []
|
|
9
|
+
};
|
|
10
|
+
function resolveCollection(model, modelName) {
|
|
11
|
+
return model.storage.collection ?? modelName;
|
|
12
|
+
}
|
|
13
|
+
function buildLookupStages(contract, model, include) {
|
|
14
|
+
const stages = [];
|
|
15
|
+
for (const [relName, shouldInclude] of Object.entries(include)) {
|
|
16
|
+
if (!shouldInclude) continue;
|
|
17
|
+
const relation = model.relations[relName];
|
|
18
|
+
if (!relation || relation.strategy !== "reference") continue;
|
|
19
|
+
const refRelation = relation;
|
|
20
|
+
if (refRelation.on.localFields.length !== 1 || refRelation.on.targetFields.length !== 1) throw new Error(`Compound references are not yet supported: relation "${relName}" has ${refRelation.on.localFields.length} local field(s) and ${refRelation.on.targetFields.length} target field(s)`);
|
|
21
|
+
const targetModel = contract.models[refRelation.to];
|
|
22
|
+
if (!targetModel) continue;
|
|
23
|
+
const targetCollection = resolveCollection(targetModel, refRelation.to);
|
|
24
|
+
stages.push({ $lookup: {
|
|
25
|
+
from: targetCollection,
|
|
26
|
+
localField: refRelation.on.localFields[0],
|
|
27
|
+
foreignField: refRelation.on.targetFields[0],
|
|
28
|
+
as: relName
|
|
29
|
+
} });
|
|
30
|
+
if (refRelation.cardinality === "N:1" || refRelation.cardinality === "1:1") stages.push({ $unwind: {
|
|
31
|
+
path: `$${relName}`,
|
|
32
|
+
preserveNullAndEmptyArrays: true
|
|
33
|
+
} });
|
|
34
|
+
}
|
|
35
|
+
return stages;
|
|
36
|
+
}
|
|
37
|
+
var MongoCollectionImpl = class {
|
|
38
|
+
#contract;
|
|
39
|
+
#modelName;
|
|
40
|
+
#executor;
|
|
41
|
+
constructor(contract, modelName, executor) {
|
|
42
|
+
this.#contract = contract;
|
|
43
|
+
this.#modelName = modelName;
|
|
44
|
+
this.#executor = executor;
|
|
45
|
+
}
|
|
46
|
+
findMany(options) {
|
|
47
|
+
const model = this.#contract.models[this.#modelName];
|
|
48
|
+
const collection = resolveCollection(model, this.#modelName);
|
|
49
|
+
const filter = options?.where ? options.where : void 0;
|
|
50
|
+
const include = options?.include;
|
|
51
|
+
const hasIncludes = include && Object.keys(include).length > 0;
|
|
52
|
+
let plan;
|
|
53
|
+
if (hasIncludes) {
|
|
54
|
+
const pipeline = [];
|
|
55
|
+
if (filter && Object.keys(filter).length > 0) pipeline.push({ $match: filter });
|
|
56
|
+
pipeline.push(...buildLookupStages(this.#contract, model, include));
|
|
57
|
+
plan = {
|
|
58
|
+
command: new AggregateCommand(collection, pipeline),
|
|
59
|
+
meta: stubMeta
|
|
60
|
+
};
|
|
61
|
+
} else plan = {
|
|
62
|
+
command: new FindCommand(collection, filter),
|
|
63
|
+
meta: stubMeta
|
|
64
|
+
};
|
|
65
|
+
return this.#executor.execute(plan);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function mongoOrm(options) {
|
|
69
|
+
const { contract, executor } = options;
|
|
70
|
+
const client = {};
|
|
71
|
+
for (const [rootName, modelName] of Object.entries(contract.roots)) client[rootName] = new MongoCollectionImpl(contract, modelName, executor);
|
|
72
|
+
return client;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
export { mongoOrm };
|
|
77
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["stubMeta: PlanMeta","stages: Record<string, unknown>[]","#contract","#modelName","#executor","plan: MongoQueryPlan","pipeline: Record<string, unknown>[]","client: Record<string, unknown>"],"sources":["../src/mongo-orm.ts"],"sourcesContent":["import type { PlanMeta } from '@prisma-next/contract/types';\nimport {\n AggregateCommand,\n FindCommand,\n type MongoContract,\n type MongoContractWithTypeMaps,\n type MongoExpr,\n type MongoModelDefinition,\n type MongoQueryPlan,\n type MongoReferenceRelation,\n type MongoTypeMaps,\n} from '@prisma-next/mongo-core';\nimport type { AsyncIterableResult } from '@prisma-next/runtime-executor';\nimport type {\n MongoFindManyOptions,\n MongoIncludeSpec,\n MongoOrmClient,\n MongoOrmOptions,\n MongoQueryExecutor,\n} from './types';\n\nconst stubMeta: PlanMeta = {\n target: 'mongo',\n storageHash: 'orm',\n lane: 'mongo-orm',\n paramDescriptors: [],\n};\n\nfunction resolveCollection(model: MongoModelDefinition, modelName: string): string {\n return model.storage.collection ?? modelName;\n}\n\nfunction buildLookupStages(\n contract: MongoContract,\n model: MongoModelDefinition,\n include: Record<string, true>,\n): Record<string, unknown>[] {\n const stages: Record<string, unknown>[] = [];\n\n for (const [relName, shouldInclude] of Object.entries(include)) {\n if (!shouldInclude) continue;\n\n const relation = model.relations[relName];\n if (!relation || relation.strategy !== 'reference') continue;\n\n const refRelation = relation as MongoReferenceRelation;\n\n if (refRelation.on.localFields.length !== 1 || refRelation.on.targetFields.length !== 1) {\n throw new Error(\n `Compound references are not yet supported: relation \"${relName}\" has ${refRelation.on.localFields.length} local field(s) and ${refRelation.on.targetFields.length} target field(s)`,\n );\n }\n\n const targetModel = contract.models[refRelation.to];\n if (!targetModel) continue;\n\n const targetCollection = resolveCollection(targetModel, refRelation.to);\n\n stages.push({\n $lookup: {\n from: targetCollection,\n localField: refRelation.on.localFields[0],\n foreignField: refRelation.on.targetFields[0],\n as: relName,\n },\n });\n\n if (refRelation.cardinality === 'N:1' || refRelation.cardinality === '1:1') {\n stages.push({\n $unwind: {\n path: `$${relName}`,\n preserveNullAndEmptyArrays: true,\n },\n });\n }\n }\n\n return stages;\n}\n\nclass MongoCollectionImpl<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n ModelName extends string & keyof TContract['models'],\n> {\n readonly #contract: TContract;\n readonly #modelName: ModelName;\n readonly #executor: MongoQueryExecutor;\n\n constructor(contract: TContract, modelName: ModelName, executor: MongoQueryExecutor) {\n this.#contract = contract;\n this.#modelName = modelName;\n this.#executor = executor;\n }\n\n findMany<TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>>(\n options?: MongoFindManyOptions<TContract, ModelName, TInclude>,\n ): AsyncIterableResult<unknown> {\n const model = this.#contract.models[this.#modelName] as MongoModelDefinition;\n const collection = resolveCollection(model, this.#modelName as string);\n const filter = options?.where ? (options.where as unknown as MongoExpr) : undefined;\n const include = options?.include as Record<string, true> | undefined;\n\n const hasIncludes = include && Object.keys(include).length > 0;\n\n let plan: MongoQueryPlan;\n if (hasIncludes) {\n const pipeline: Record<string, unknown>[] = [];\n\n if (filter && Object.keys(filter as Record<string, unknown>).length > 0) {\n pipeline.push({ $match: filter });\n }\n\n pipeline.push(...buildLookupStages(this.#contract, model, include));\n\n plan = {\n command: new AggregateCommand(collection, pipeline),\n meta: stubMeta,\n };\n } else {\n plan = {\n command: new FindCommand(collection, filter),\n meta: stubMeta,\n };\n }\n\n return this.#executor.execute(plan);\n }\n}\n\nexport function mongoOrm<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(\n options: MongoOrmOptions<TContract>,\n): MongoOrmClient<TContract> {\n const { contract, executor } = options;\n const client: Record<string, unknown> = {};\n\n for (const [rootName, modelName] of Object.entries(contract.roots)) {\n client[rootName] = new MongoCollectionImpl(\n contract,\n modelName as string & keyof TContract['models'],\n executor,\n );\n }\n\n return client as MongoOrmClient<TContract>;\n}\n"],"mappings":";;;AAqBA,MAAMA,WAAqB;CACzB,QAAQ;CACR,aAAa;CACb,MAAM;CACN,kBAAkB,EAAE;CACrB;AAED,SAAS,kBAAkB,OAA6B,WAA2B;AACjF,QAAO,MAAM,QAAQ,cAAc;;AAGrC,SAAS,kBACP,UACA,OACA,SAC2B;CAC3B,MAAMC,SAAoC,EAAE;AAE5C,MAAK,MAAM,CAAC,SAAS,kBAAkB,OAAO,QAAQ,QAAQ,EAAE;AAC9D,MAAI,CAAC,cAAe;EAEpB,MAAM,WAAW,MAAM,UAAU;AACjC,MAAI,CAAC,YAAY,SAAS,aAAa,YAAa;EAEpD,MAAM,cAAc;AAEpB,MAAI,YAAY,GAAG,YAAY,WAAW,KAAK,YAAY,GAAG,aAAa,WAAW,EACpF,OAAM,IAAI,MACR,wDAAwD,QAAQ,QAAQ,YAAY,GAAG,YAAY,OAAO,sBAAsB,YAAY,GAAG,aAAa,OAAO,kBACpK;EAGH,MAAM,cAAc,SAAS,OAAO,YAAY;AAChD,MAAI,CAAC,YAAa;EAElB,MAAM,mBAAmB,kBAAkB,aAAa,YAAY,GAAG;AAEvE,SAAO,KAAK,EACV,SAAS;GACP,MAAM;GACN,YAAY,YAAY,GAAG,YAAY;GACvC,cAAc,YAAY,GAAG,aAAa;GAC1C,IAAI;GACL,EACF,CAAC;AAEF,MAAI,YAAY,gBAAgB,SAAS,YAAY,gBAAgB,MACnE,QAAO,KAAK,EACV,SAAS;GACP,MAAM,IAAI;GACV,4BAA4B;GAC7B,EACF,CAAC;;AAIN,QAAO;;AAGT,IAAM,sBAAN,MAGE;CACA,CAASC;CACT,CAASC;CACT,CAASC;CAET,YAAY,UAAqB,WAAsB,UAA8B;AACnF,QAAKF,WAAY;AACjB,QAAKC,YAAa;AAClB,QAAKC,WAAY;;CAGnB,SACE,SAC8B;EAC9B,MAAM,QAAQ,MAAKF,SAAU,OAAO,MAAKC;EACzC,MAAM,aAAa,kBAAkB,OAAO,MAAKA,UAAqB;EACtE,MAAM,SAAS,SAAS,QAAS,QAAQ,QAAiC;EAC1E,MAAM,UAAU,SAAS;EAEzB,MAAM,cAAc,WAAW,OAAO,KAAK,QAAQ,CAAC,SAAS;EAE7D,IAAIE;AACJ,MAAI,aAAa;GACf,MAAMC,WAAsC,EAAE;AAE9C,OAAI,UAAU,OAAO,KAAK,OAAkC,CAAC,SAAS,EACpE,UAAS,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAGnC,YAAS,KAAK,GAAG,kBAAkB,MAAKJ,UAAW,OAAO,QAAQ,CAAC;AAEnE,UAAO;IACL,SAAS,IAAI,iBAAiB,YAAY,SAAS;IACnD,MAAM;IACP;QAED,QAAO;GACL,SAAS,IAAI,YAAY,YAAY,OAAO;GAC5C,MAAM;GACP;AAGH,SAAO,MAAKE,SAAU,QAAQ,KAAK;;;AAIvC,SAAgB,SACd,SAC2B;CAC3B,MAAM,EAAE,UAAU,aAAa;CAC/B,MAAMG,SAAkC,EAAE;AAE1C,MAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,SAAS,MAAM,CAChE,QAAO,YAAY,IAAI,oBACrB,UACA,WACA,SACD;AAGH,QAAO"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-next/mongo-orm",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"description": "MongoDB ORM client for Prisma Next",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"test": "vitest run --passWithNoTests",
|
|
10
|
+
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"lint": "biome check . --error-on-warnings",
|
|
13
|
+
"lint:fix": "biome check --write .",
|
|
14
|
+
"lint:fix:unsafe": "biome check --write --unsafe .",
|
|
15
|
+
"clean": "rm -rf dist dist-tsc dist-tsc-prod coverage .tmp-output"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@prisma-next/contract": "workspace:*",
|
|
19
|
+
"@prisma-next/mongo-core": "workspace:*",
|
|
20
|
+
"@prisma-next/runtime-executor": "workspace:*"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@prisma-next/test-utils": "workspace:*",
|
|
24
|
+
"@prisma-next/tsconfig": "workspace:*",
|
|
25
|
+
"@prisma-next/tsdown": "workspace:*",
|
|
26
|
+
"tsdown": "catalog:",
|
|
27
|
+
"typescript": "catalog:",
|
|
28
|
+
"vitest": "catalog:"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src"
|
|
33
|
+
],
|
|
34
|
+
"exports": {
|
|
35
|
+
".": "./dist/index.mjs",
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"main": "./dist/index.mjs",
|
|
39
|
+
"module": "./dist/index.mjs",
|
|
40
|
+
"types": "./dist/index.d.mts",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/prisma/prisma-next.git",
|
|
44
|
+
"directory": "packages/2-mongo-family/4-orm"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { mongoOrm } from '../mongo-orm';
|
|
2
|
+
export type {
|
|
3
|
+
EmbedRelationKeys,
|
|
4
|
+
IncludeResultFields,
|
|
5
|
+
InferFullRow,
|
|
6
|
+
InferRootRow,
|
|
7
|
+
MongoCollection,
|
|
8
|
+
MongoFindManyOptions,
|
|
9
|
+
MongoIncludeSpec,
|
|
10
|
+
MongoOrmClient,
|
|
11
|
+
MongoOrmOptions,
|
|
12
|
+
MongoQueryExecutor,
|
|
13
|
+
MongoWhereFilter,
|
|
14
|
+
ReferenceRelationKeys,
|
|
15
|
+
} from '../types';
|
package/src/mongo-orm.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { PlanMeta } from '@prisma-next/contract/types';
|
|
2
|
+
import {
|
|
3
|
+
AggregateCommand,
|
|
4
|
+
FindCommand,
|
|
5
|
+
type MongoContract,
|
|
6
|
+
type MongoContractWithTypeMaps,
|
|
7
|
+
type MongoExpr,
|
|
8
|
+
type MongoModelDefinition,
|
|
9
|
+
type MongoQueryPlan,
|
|
10
|
+
type MongoReferenceRelation,
|
|
11
|
+
type MongoTypeMaps,
|
|
12
|
+
} from '@prisma-next/mongo-core';
|
|
13
|
+
import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
|
|
14
|
+
import type {
|
|
15
|
+
MongoFindManyOptions,
|
|
16
|
+
MongoIncludeSpec,
|
|
17
|
+
MongoOrmClient,
|
|
18
|
+
MongoOrmOptions,
|
|
19
|
+
MongoQueryExecutor,
|
|
20
|
+
} from './types';
|
|
21
|
+
|
|
22
|
+
const stubMeta: PlanMeta = {
|
|
23
|
+
target: 'mongo',
|
|
24
|
+
storageHash: 'orm',
|
|
25
|
+
lane: 'mongo-orm',
|
|
26
|
+
paramDescriptors: [],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function resolveCollection(model: MongoModelDefinition, modelName: string): string {
|
|
30
|
+
return model.storage.collection ?? modelName;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildLookupStages(
|
|
34
|
+
contract: MongoContract,
|
|
35
|
+
model: MongoModelDefinition,
|
|
36
|
+
include: Record<string, true>,
|
|
37
|
+
): Record<string, unknown>[] {
|
|
38
|
+
const stages: Record<string, unknown>[] = [];
|
|
39
|
+
|
|
40
|
+
for (const [relName, shouldInclude] of Object.entries(include)) {
|
|
41
|
+
if (!shouldInclude) continue;
|
|
42
|
+
|
|
43
|
+
const relation = model.relations[relName];
|
|
44
|
+
if (!relation || relation.strategy !== 'reference') continue;
|
|
45
|
+
|
|
46
|
+
const refRelation = relation as MongoReferenceRelation;
|
|
47
|
+
|
|
48
|
+
if (refRelation.on.localFields.length !== 1 || refRelation.on.targetFields.length !== 1) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Compound references are not yet supported: relation "${relName}" has ${refRelation.on.localFields.length} local field(s) and ${refRelation.on.targetFields.length} target field(s)`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const targetModel = contract.models[refRelation.to];
|
|
55
|
+
if (!targetModel) continue;
|
|
56
|
+
|
|
57
|
+
const targetCollection = resolveCollection(targetModel, refRelation.to);
|
|
58
|
+
|
|
59
|
+
stages.push({
|
|
60
|
+
$lookup: {
|
|
61
|
+
from: targetCollection,
|
|
62
|
+
localField: refRelation.on.localFields[0],
|
|
63
|
+
foreignField: refRelation.on.targetFields[0],
|
|
64
|
+
as: relName,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (refRelation.cardinality === 'N:1' || refRelation.cardinality === '1:1') {
|
|
69
|
+
stages.push({
|
|
70
|
+
$unwind: {
|
|
71
|
+
path: `$${relName}`,
|
|
72
|
+
preserveNullAndEmptyArrays: true,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return stages;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class MongoCollectionImpl<
|
|
82
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
83
|
+
ModelName extends string & keyof TContract['models'],
|
|
84
|
+
> {
|
|
85
|
+
readonly #contract: TContract;
|
|
86
|
+
readonly #modelName: ModelName;
|
|
87
|
+
readonly #executor: MongoQueryExecutor;
|
|
88
|
+
|
|
89
|
+
constructor(contract: TContract, modelName: ModelName, executor: MongoQueryExecutor) {
|
|
90
|
+
this.#contract = contract;
|
|
91
|
+
this.#modelName = modelName;
|
|
92
|
+
this.#executor = executor;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
findMany<TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>>(
|
|
96
|
+
options?: MongoFindManyOptions<TContract, ModelName, TInclude>,
|
|
97
|
+
): AsyncIterableResult<unknown> {
|
|
98
|
+
const model = this.#contract.models[this.#modelName] as MongoModelDefinition;
|
|
99
|
+
const collection = resolveCollection(model, this.#modelName as string);
|
|
100
|
+
const filter = options?.where ? (options.where as unknown as MongoExpr) : undefined;
|
|
101
|
+
const include = options?.include as Record<string, true> | undefined;
|
|
102
|
+
|
|
103
|
+
const hasIncludes = include && Object.keys(include).length > 0;
|
|
104
|
+
|
|
105
|
+
let plan: MongoQueryPlan;
|
|
106
|
+
if (hasIncludes) {
|
|
107
|
+
const pipeline: Record<string, unknown>[] = [];
|
|
108
|
+
|
|
109
|
+
if (filter && Object.keys(filter as Record<string, unknown>).length > 0) {
|
|
110
|
+
pipeline.push({ $match: filter });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pipeline.push(...buildLookupStages(this.#contract, model, include));
|
|
114
|
+
|
|
115
|
+
plan = {
|
|
116
|
+
command: new AggregateCommand(collection, pipeline),
|
|
117
|
+
meta: stubMeta,
|
|
118
|
+
};
|
|
119
|
+
} else {
|
|
120
|
+
plan = {
|
|
121
|
+
command: new FindCommand(collection, filter),
|
|
122
|
+
meta: stubMeta,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return this.#executor.execute(plan);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function mongoOrm<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(
|
|
131
|
+
options: MongoOrmOptions<TContract>,
|
|
132
|
+
): MongoOrmClient<TContract> {
|
|
133
|
+
const { contract, executor } = options;
|
|
134
|
+
const client: Record<string, unknown> = {};
|
|
135
|
+
|
|
136
|
+
for (const [rootName, modelName] of Object.entries(contract.roots)) {
|
|
137
|
+
client[rootName] = new MongoCollectionImpl(
|
|
138
|
+
contract,
|
|
139
|
+
modelName as string & keyof TContract['models'],
|
|
140
|
+
executor,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return client as MongoOrmClient<TContract>;
|
|
145
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtractMongoCodecTypes,
|
|
3
|
+
InferModelRow,
|
|
4
|
+
MongoContract,
|
|
5
|
+
MongoContractWithTypeMaps,
|
|
6
|
+
MongoQueryPlan,
|
|
7
|
+
MongoTypeMaps,
|
|
8
|
+
} from '@prisma-next/mongo-core';
|
|
9
|
+
import type { AsyncIterableResult } from '@prisma-next/runtime-executor';
|
|
10
|
+
|
|
11
|
+
export interface MongoQueryExecutor {
|
|
12
|
+
execute<Row>(plan: MongoQueryPlan<Row>): AsyncIterableResult<Row>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface MongoOrmOptions<TContract extends MongoContract> {
|
|
16
|
+
readonly contract: TContract;
|
|
17
|
+
readonly executor: MongoQueryExecutor;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type Simplify<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
|
21
|
+
|
|
22
|
+
// --- Relation type helpers ---
|
|
23
|
+
|
|
24
|
+
export type ReferenceRelationKeys<
|
|
25
|
+
TContract extends MongoContract,
|
|
26
|
+
ModelName extends string & keyof TContract['models'],
|
|
27
|
+
> = {
|
|
28
|
+
[K in keyof TContract['models'][ModelName]['relations']]: TContract['models'][ModelName]['relations'][K] extends {
|
|
29
|
+
readonly strategy: 'reference';
|
|
30
|
+
}
|
|
31
|
+
? K
|
|
32
|
+
: never;
|
|
33
|
+
}[keyof TContract['models'][ModelName]['relations']];
|
|
34
|
+
|
|
35
|
+
export type EmbedRelationKeys<
|
|
36
|
+
TContract extends MongoContract,
|
|
37
|
+
ModelName extends string & keyof TContract['models'],
|
|
38
|
+
> = {
|
|
39
|
+
[K in keyof TContract['models'][ModelName]['relations']]: TContract['models'][ModelName]['relations'][K] extends {
|
|
40
|
+
readonly strategy: 'embed';
|
|
41
|
+
}
|
|
42
|
+
? K
|
|
43
|
+
: never;
|
|
44
|
+
}[keyof TContract['models'][ModelName]['relations']];
|
|
45
|
+
|
|
46
|
+
// --- Embedded field types ---
|
|
47
|
+
|
|
48
|
+
type EmbedRelationRowType<
|
|
49
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
50
|
+
ModelName extends string & keyof TContract['models'],
|
|
51
|
+
RelKey extends keyof TContract['models'][ModelName]['relations'],
|
|
52
|
+
> = TContract['models'][ModelName]['relations'][RelKey] extends {
|
|
53
|
+
readonly to: infer To extends string & keyof TContract['models'];
|
|
54
|
+
readonly cardinality: infer C;
|
|
55
|
+
readonly strategy: 'embed';
|
|
56
|
+
}
|
|
57
|
+
? C extends '1:N'
|
|
58
|
+
? InferModelRow<TContract, To>[]
|
|
59
|
+
: InferModelRow<TContract, To>
|
|
60
|
+
: never;
|
|
61
|
+
|
|
62
|
+
export type InferFullRow<
|
|
63
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
64
|
+
ModelName extends string & keyof TContract['models'],
|
|
65
|
+
> = EmbedRelationKeys<TContract, ModelName> extends never
|
|
66
|
+
? InferModelRow<TContract, ModelName>
|
|
67
|
+
: InferModelRow<TContract, ModelName> & {
|
|
68
|
+
-readonly [K in EmbedRelationKeys<TContract, ModelName> &
|
|
69
|
+
keyof TContract['models'][ModelName]['relations']]: EmbedRelationRowType<
|
|
70
|
+
TContract,
|
|
71
|
+
ModelName,
|
|
72
|
+
K
|
|
73
|
+
>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// --- Polymorphic row type ---
|
|
77
|
+
|
|
78
|
+
type VariantRow<
|
|
79
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
80
|
+
ModelName extends string & keyof TContract['models'],
|
|
81
|
+
> = TContract['models'][ModelName] extends {
|
|
82
|
+
readonly discriminator: { readonly field: infer DiscField extends string };
|
|
83
|
+
readonly variants: infer V;
|
|
84
|
+
}
|
|
85
|
+
? V extends Record<string, { readonly value: string }>
|
|
86
|
+
? {
|
|
87
|
+
[VK in keyof V]: VK extends string & keyof TContract['models']
|
|
88
|
+
? Simplify<
|
|
89
|
+
Omit<InferFullRow<TContract, ModelName>, DiscField> &
|
|
90
|
+
InferFullRow<TContract, VK> &
|
|
91
|
+
Record<DiscField, V[VK]['value']>
|
|
92
|
+
>
|
|
93
|
+
: never;
|
|
94
|
+
}[keyof V]
|
|
95
|
+
: InferFullRow<TContract, ModelName>
|
|
96
|
+
: InferFullRow<TContract, ModelName>;
|
|
97
|
+
|
|
98
|
+
export type InferRootRow<
|
|
99
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
100
|
+
ModelName extends string & keyof TContract['models'],
|
|
101
|
+
> = VariantRow<TContract, ModelName>;
|
|
102
|
+
|
|
103
|
+
// --- Include result type augmentation ---
|
|
104
|
+
|
|
105
|
+
type IncludeRelationRowType<
|
|
106
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
107
|
+
ModelName extends string & keyof TContract['models'],
|
|
108
|
+
RelKey extends keyof TContract['models'][ModelName]['relations'],
|
|
109
|
+
> = TContract['models'][ModelName]['relations'][RelKey] extends {
|
|
110
|
+
readonly to: infer To extends string & keyof TContract['models'];
|
|
111
|
+
readonly cardinality: infer C;
|
|
112
|
+
readonly strategy: 'reference';
|
|
113
|
+
}
|
|
114
|
+
? C extends 'N:1' | '1:1'
|
|
115
|
+
? InferFullRow<TContract, To> | null
|
|
116
|
+
: InferFullRow<TContract, To>[]
|
|
117
|
+
: never;
|
|
118
|
+
|
|
119
|
+
export type IncludeResultFields<
|
|
120
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
121
|
+
ModelName extends string & keyof TContract['models'],
|
|
122
|
+
TInclude extends MongoIncludeSpec<TContract, ModelName>,
|
|
123
|
+
> = {
|
|
124
|
+
-readonly [K in keyof TInclude & string as TInclude[K] extends true
|
|
125
|
+
? K
|
|
126
|
+
: never]: K extends keyof TContract['models'][ModelName]['relations']
|
|
127
|
+
? IncludeRelationRowType<TContract, ModelName, K>
|
|
128
|
+
: never;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// --- Query options ---
|
|
132
|
+
|
|
133
|
+
export type MongoWhereFilter<
|
|
134
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
135
|
+
ModelName extends string & keyof TContract['models'],
|
|
136
|
+
TCodecTypes extends Record<string, { output: unknown }> = ExtractMongoCodecTypes<TContract>,
|
|
137
|
+
> = {
|
|
138
|
+
readonly [K in keyof TContract['models'][ModelName]['fields']]?: TContract['models'][ModelName]['fields'][K] extends {
|
|
139
|
+
readonly codecId: infer CId extends string & keyof TCodecTypes;
|
|
140
|
+
}
|
|
141
|
+
? TCodecTypes[CId]['output']
|
|
142
|
+
: unknown;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type MongoIncludeSpec<
|
|
146
|
+
TContract extends MongoContract,
|
|
147
|
+
ModelName extends string & keyof TContract['models'],
|
|
148
|
+
> = {
|
|
149
|
+
readonly [K in ReferenceRelationKeys<TContract, ModelName>]?: true;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export interface MongoFindManyOptions<
|
|
153
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
154
|
+
ModelName extends string & keyof TContract['models'],
|
|
155
|
+
TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>,
|
|
156
|
+
> {
|
|
157
|
+
readonly where?: MongoWhereFilter<TContract, ModelName>;
|
|
158
|
+
readonly include?: TInclude;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- Client types ---
|
|
162
|
+
|
|
163
|
+
export type MongoOrmClient<
|
|
164
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
165
|
+
> = {
|
|
166
|
+
readonly [K in keyof TContract['roots']]: TContract['roots'][K] extends string &
|
|
167
|
+
keyof TContract['models']
|
|
168
|
+
? MongoCollection<TContract, TContract['roots'][K]>
|
|
169
|
+
: never;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export interface MongoCollection<
|
|
173
|
+
TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,
|
|
174
|
+
ModelName extends string & keyof TContract['models'],
|
|
175
|
+
> {
|
|
176
|
+
findMany<TInclude extends MongoIncludeSpec<TContract, ModelName> = Record<string, never>>(
|
|
177
|
+
options?: MongoFindManyOptions<TContract, ModelName, TInclude>,
|
|
178
|
+
): AsyncIterableResult<
|
|
179
|
+
InferRootRow<TContract, ModelName> & IncludeResultFields<TContract, ModelName, TInclude>
|
|
180
|
+
>;
|
|
181
|
+
}
|