@prisma-next/target-mongo 0.7.0 → 0.8.0-dev.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/dist/control.d.mts +168 -101
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +1194 -1138
- package/dist/control.mjs.map +1 -1
- package/dist/{migration-factories-ZBsWqXt-.mjs → migration-factories-BRBKKZia.mjs} +1 -1
- package/dist/{migration-factories-ZBsWqXt-.mjs.map → migration-factories-BRBKKZia.mjs.map} +1 -1
- package/dist/migration.d.mts +2 -2
- package/dist/migration.mjs +1 -1
- package/dist/{op-factory-call-9z5D19cP.d.mts → op-factory-call-BC-llGKt.d.mts} +2 -2
- package/dist/{op-factory-call-9z5D19cP.d.mts.map → op-factory-call-BC-llGKt.d.mts.map} +1 -1
- package/package.json +23 -21
- package/src/core/control-target.ts +185 -0
- package/src/core/mongo-planner.ts +1 -1
- package/src/core/mongo-runner.ts +3 -45
- package/src/core/mongo-target-contract-serializer.ts +73 -0
- package/src/core/mongo-target-contract.ts +15 -0
- package/src/core/mongo-target-database.ts +82 -0
- package/src/core/mongo-target-schema-verifier.ts +54 -0
- package/src/exports/control.ts +8 -9
- package/dist/schema-verify.d.mts +0 -22
- package/dist/schema-verify.d.mts.map +0 -1
- package/dist/schema-verify.mjs +0 -2
- package/dist/verify-mongo-schema-DlPXaotB.mjs +0 -578
- package/dist/verify-mongo-schema-DlPXaotB.mjs.map +0 -1
- package/src/core/contract-to-schema.ts +0 -63
- package/src/core/ddl-formatter.ts +0 -112
- package/src/core/marker-ledger.ts +0 -232
- package/src/core/schema-diff.ts +0 -402
- package/src/core/schema-verify/canonicalize-introspection.ts +0 -389
- package/src/core/schema-verify/verify-mongo-schema.ts +0 -60
- package/src/exports/schema-verify.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-factories-ZBsWqXt-.mjs","names":[],"sources":["../src/core/migration-factories.ts"],"sourcesContent":["import type {\n MongoDataTransformCheck,\n MongoDataTransformOperation,\n MongoFilterExpr,\n MongoIndexKey,\n} from '@prisma-next/mongo-query-ast/control';\nimport {\n buildIndexOpId,\n CollModCommand,\n type CollModOptions,\n CreateCollectionCommand,\n type CreateCollectionOptions,\n CreateIndexCommand,\n type CreateIndexOptions,\n DropCollectionCommand,\n DropIndexCommand,\n defaultMongoIndexName,\n keysToKeySpec,\n ListCollectionsCommand,\n ListIndexesCommand,\n MongoAndExpr,\n MongoExistsExpr,\n MongoFieldFilter,\n type MongoMigrationPlanOperation,\n} from '@prisma-next/mongo-query-ast/control';\nimport type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { CollModMeta } from './op-factory-call';\n\ninterface Buildable {\n build(): MongoQueryPlan;\n}\n\nfunction isBuildable(value: unknown): value is Buildable {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'build' in value &&\n typeof (value as { build: unknown }).build === 'function'\n );\n}\n\nfunction resolveQuery(value: MongoQueryPlan | Buildable): MongoQueryPlan {\n return isBuildable(value) ? value.build() : value;\n}\n\n// Every MongoDB document carries `_id`, so `exists('_id')` is equivalent to\n// \"match all\". The filter AST has no identity/always-true expression.\nconst MATCH_ALL_FILTER: MongoFilterExpr = MongoExistsExpr.exists('_id');\n\nexport function dataTransform(\n name: string,\n options: {\n /**\n * Optional opt-in routing identity. Presence opts the transform into\n * invariant-aware routing; absence means it is path-dependent and\n * not referenceable from refs.\n */\n invariantId?: string;\n check?: {\n source: () => MongoQueryPlan | Buildable;\n filter?: MongoFilterExpr;\n expect?: 'exists' | 'notExists';\n description?: string;\n };\n run: () => MongoQueryPlan | Buildable;\n },\n): MongoDataTransformOperation {\n let precheck: readonly MongoDataTransformCheck[] = [];\n let postcheck: readonly MongoDataTransformCheck[] = [];\n\n if (options.check) {\n const source = resolveQuery(options.check.source());\n const filter = options.check.filter ?? MATCH_ALL_FILTER;\n const description = options.check.description ?? `Check for data transform: ${name}`;\n const precheckExpect = options.check.expect ?? 'exists';\n const postcheckExpect: 'exists' | 'notExists' =\n precheckExpect === 'exists' ? 'notExists' : 'exists';\n\n precheck = [{ description, source, filter, expect: precheckExpect }];\n postcheck = [{ description, source, filter, expect: postcheckExpect }];\n }\n\n const run: MongoQueryPlan[] = [resolveQuery(options.run())];\n\n return {\n id: `data_transform.${name}`,\n label: `Data transform: ${name}`,\n operationClass: 'data',\n name,\n ...ifDefined('invariantId', options.invariantId),\n precheck,\n run,\n postcheck,\n };\n}\n\nfunction formatKeys(keys: ReadonlyArray<MongoIndexKey>): string {\n return keys.map((k) => `${k.field}:${k.direction}`).join(', ');\n}\n\nfunction isTextIndex(keys: ReadonlyArray<MongoIndexKey>): boolean {\n return keys.some((k) => k.direction === 'text');\n}\n\nfunction keyFilter(keys: ReadonlyArray<MongoIndexKey>) {\n return isTextIndex(keys)\n ? MongoFieldFilter.eq('key._fts', 'text')\n : MongoFieldFilter.eq('key', keysToKeySpec(keys));\n}\n\nexport function createIndex(\n collection: string,\n keys: ReadonlyArray<MongoIndexKey>,\n options?: CreateIndexOptions,\n): MongoMigrationPlanOperation {\n const name = defaultMongoIndexName(keys);\n const filter = keyFilter(keys);\n const fullFilter = options?.unique\n ? MongoAndExpr.of([filter, MongoFieldFilter.eq('unique', true)])\n : filter;\n\n return {\n id: buildIndexOpId('create', collection, keys),\n label: `Create index on ${collection} (${formatKeys(keys)})`,\n operationClass: 'additive',\n precheck: [\n {\n description: `index does not already exist on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'notExists',\n },\n ],\n execute: [\n {\n description: `create index on ${collection}`,\n command: new CreateIndexCommand(collection, keys, {\n ...options,\n unique: options?.unique ?? undefined,\n name,\n }),\n },\n ],\n postcheck: [\n {\n description: `index exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter: fullFilter,\n expect: 'exists',\n },\n ],\n };\n}\n\nexport function dropIndex(\n collection: string,\n keys: ReadonlyArray<MongoIndexKey>,\n): MongoMigrationPlanOperation {\n const indexName = defaultMongoIndexName(keys);\n const filter = keyFilter(keys);\n\n return {\n id: buildIndexOpId('drop', collection, keys),\n label: `Drop index on ${collection} (${formatKeys(keys)})`,\n operationClass: 'destructive',\n precheck: [\n {\n description: `index exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'exists',\n },\n ],\n execute: [\n {\n description: `drop index on ${collection}`,\n command: new DropIndexCommand(collection, indexName),\n },\n ],\n postcheck: [\n {\n description: `index no longer exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'notExists',\n },\n ],\n };\n}\n\nexport function createCollection(\n collection: string,\n options?: CreateCollectionOptions,\n): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.create`,\n label: `Create collection ${collection}`,\n operationClass: 'additive',\n precheck: [\n {\n description: `collection ${collection} does not exist`,\n source: new ListCollectionsCommand(),\n filter: MongoFieldFilter.eq('name', collection),\n expect: 'notExists',\n },\n ],\n execute: [\n {\n description: `create collection ${collection}`,\n command: new CreateCollectionCommand(collection, options),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function dropCollection(collection: string): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.drop`,\n label: `Drop collection ${collection}`,\n operationClass: 'destructive',\n precheck: [],\n execute: [\n {\n description: `drop collection ${collection}`,\n command: new DropCollectionCommand(collection),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function setValidation(\n collection: string,\n schema: Record<string, unknown>,\n options?: { validationLevel?: 'strict' | 'moderate'; validationAction?: 'error' | 'warn' },\n): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.setValidation`,\n label: `Set validation on ${collection}`,\n operationClass: 'destructive',\n precheck: [],\n execute: [\n {\n description: `set validation on ${collection}`,\n command: new CollModCommand(collection, {\n validator: { $jsonSchema: schema },\n validationLevel: options?.validationLevel,\n validationAction: options?.validationAction,\n }),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function collMod(\n collection: string,\n options: CollModOptions,\n meta?: CollModMeta,\n): MongoMigrationPlanOperation {\n const hasValidator = options.validator != null && Object.keys(options.validator).length > 0;\n\n return {\n id: meta?.id ?? `collection.${collection}.collMod`,\n label: meta?.label ?? `Modify collection ${collection}`,\n operationClass: meta?.operationClass ?? 'destructive',\n precheck:\n options.validator != null\n ? [\n {\n description: `collection ${collection} exists`,\n source: new ListCollectionsCommand(),\n filter: MongoFieldFilter.eq('name', collection),\n expect: 'exists' as const,\n },\n ]\n : [],\n execute: [\n {\n description: `modify ${collection}`,\n command: new CollModCommand(collection, options),\n },\n ],\n postcheck: hasValidator\n ? [\n {\n description: `validator applied on ${collection}`,\n source: new ListCollectionsCommand(),\n filter: MongoAndExpr.of([\n MongoFieldFilter.eq('name', collection),\n ...(options.validationLevel\n ? [MongoFieldFilter.eq('options.validationLevel', options.validationLevel)]\n : []),\n ...(options.validationAction\n ? [MongoFieldFilter.eq('options.validationAction', options.validationAction)]\n : []),\n ]),\n expect: 'exists' as const,\n },\n ]\n : [],\n };\n}\n\nexport function validatedCollection(\n name: string,\n schema: Record<string, unknown>,\n indexes: ReadonlyArray<{ keys: MongoIndexKey[]; unique?: boolean }>,\n): MongoMigrationPlanOperation[] {\n return [\n createCollection(name, {\n validator: { $jsonSchema: schema },\n validationLevel: 'strict',\n validationAction: 'error',\n }),\n ...indexes.map((idx) => createIndex(name, idx.keys, { unique: idx.unique })),\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-factories-BRBKKZia.mjs","names":[],"sources":["../src/core/migration-factories.ts"],"sourcesContent":["import type {\n MongoDataTransformCheck,\n MongoDataTransformOperation,\n MongoFilterExpr,\n MongoIndexKey,\n} from '@prisma-next/mongo-query-ast/control';\nimport {\n buildIndexOpId,\n CollModCommand,\n type CollModOptions,\n CreateCollectionCommand,\n type CreateCollectionOptions,\n CreateIndexCommand,\n type CreateIndexOptions,\n DropCollectionCommand,\n DropIndexCommand,\n defaultMongoIndexName,\n keysToKeySpec,\n ListCollectionsCommand,\n ListIndexesCommand,\n MongoAndExpr,\n MongoExistsExpr,\n MongoFieldFilter,\n type MongoMigrationPlanOperation,\n} from '@prisma-next/mongo-query-ast/control';\nimport type { MongoQueryPlan } from '@prisma-next/mongo-query-ast/execution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { CollModMeta } from './op-factory-call';\n\ninterface Buildable {\n build(): MongoQueryPlan;\n}\n\nfunction isBuildable(value: unknown): value is Buildable {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'build' in value &&\n typeof (value as { build: unknown }).build === 'function'\n );\n}\n\nfunction resolveQuery(value: MongoQueryPlan | Buildable): MongoQueryPlan {\n return isBuildable(value) ? value.build() : value;\n}\n\n// Every MongoDB document carries `_id`, so `exists('_id')` is equivalent to\n// \"match all\". The filter AST has no identity/always-true expression.\nconst MATCH_ALL_FILTER: MongoFilterExpr = MongoExistsExpr.exists('_id');\n\nexport function dataTransform(\n name: string,\n options: {\n /**\n * Optional opt-in routing identity. Presence opts the transform into\n * invariant-aware routing; absence means it is path-dependent and\n * not referenceable from refs.\n */\n invariantId?: string;\n check?: {\n source: () => MongoQueryPlan | Buildable;\n filter?: MongoFilterExpr;\n expect?: 'exists' | 'notExists';\n description?: string;\n };\n run: () => MongoQueryPlan | Buildable;\n },\n): MongoDataTransformOperation {\n let precheck: readonly MongoDataTransformCheck[] = [];\n let postcheck: readonly MongoDataTransformCheck[] = [];\n\n if (options.check) {\n const source = resolveQuery(options.check.source());\n const filter = options.check.filter ?? MATCH_ALL_FILTER;\n const description = options.check.description ?? `Check for data transform: ${name}`;\n const precheckExpect = options.check.expect ?? 'exists';\n const postcheckExpect: 'exists' | 'notExists' =\n precheckExpect === 'exists' ? 'notExists' : 'exists';\n\n precheck = [{ description, source, filter, expect: precheckExpect }];\n postcheck = [{ description, source, filter, expect: postcheckExpect }];\n }\n\n const run: MongoQueryPlan[] = [resolveQuery(options.run())];\n\n return {\n id: `data_transform.${name}`,\n label: `Data transform: ${name}`,\n operationClass: 'data',\n name,\n ...ifDefined('invariantId', options.invariantId),\n precheck,\n run,\n postcheck,\n };\n}\n\nfunction formatKeys(keys: ReadonlyArray<MongoIndexKey>): string {\n return keys.map((k) => `${k.field}:${k.direction}`).join(', ');\n}\n\nfunction isTextIndex(keys: ReadonlyArray<MongoIndexKey>): boolean {\n return keys.some((k) => k.direction === 'text');\n}\n\nfunction keyFilter(keys: ReadonlyArray<MongoIndexKey>) {\n return isTextIndex(keys)\n ? MongoFieldFilter.eq('key._fts', 'text')\n : MongoFieldFilter.eq('key', keysToKeySpec(keys));\n}\n\nexport function createIndex(\n collection: string,\n keys: ReadonlyArray<MongoIndexKey>,\n options?: CreateIndexOptions,\n): MongoMigrationPlanOperation {\n const name = defaultMongoIndexName(keys);\n const filter = keyFilter(keys);\n const fullFilter = options?.unique\n ? MongoAndExpr.of([filter, MongoFieldFilter.eq('unique', true)])\n : filter;\n\n return {\n id: buildIndexOpId('create', collection, keys),\n label: `Create index on ${collection} (${formatKeys(keys)})`,\n operationClass: 'additive',\n precheck: [\n {\n description: `index does not already exist on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'notExists',\n },\n ],\n execute: [\n {\n description: `create index on ${collection}`,\n command: new CreateIndexCommand(collection, keys, {\n ...options,\n unique: options?.unique ?? undefined,\n name,\n }),\n },\n ],\n postcheck: [\n {\n description: `index exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter: fullFilter,\n expect: 'exists',\n },\n ],\n };\n}\n\nexport function dropIndex(\n collection: string,\n keys: ReadonlyArray<MongoIndexKey>,\n): MongoMigrationPlanOperation {\n const indexName = defaultMongoIndexName(keys);\n const filter = keyFilter(keys);\n\n return {\n id: buildIndexOpId('drop', collection, keys),\n label: `Drop index on ${collection} (${formatKeys(keys)})`,\n operationClass: 'destructive',\n precheck: [\n {\n description: `index exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'exists',\n },\n ],\n execute: [\n {\n description: `drop index on ${collection}`,\n command: new DropIndexCommand(collection, indexName),\n },\n ],\n postcheck: [\n {\n description: `index no longer exists on ${collection}`,\n source: new ListIndexesCommand(collection),\n filter,\n expect: 'notExists',\n },\n ],\n };\n}\n\nexport function createCollection(\n collection: string,\n options?: CreateCollectionOptions,\n): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.create`,\n label: `Create collection ${collection}`,\n operationClass: 'additive',\n precheck: [\n {\n description: `collection ${collection} does not exist`,\n source: new ListCollectionsCommand(),\n filter: MongoFieldFilter.eq('name', collection),\n expect: 'notExists',\n },\n ],\n execute: [\n {\n description: `create collection ${collection}`,\n command: new CreateCollectionCommand(collection, options),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function dropCollection(collection: string): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.drop`,\n label: `Drop collection ${collection}`,\n operationClass: 'destructive',\n precheck: [],\n execute: [\n {\n description: `drop collection ${collection}`,\n command: new DropCollectionCommand(collection),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function setValidation(\n collection: string,\n schema: Record<string, unknown>,\n options?: { validationLevel?: 'strict' | 'moderate'; validationAction?: 'error' | 'warn' },\n): MongoMigrationPlanOperation {\n return {\n id: `collection.${collection}.setValidation`,\n label: `Set validation on ${collection}`,\n operationClass: 'destructive',\n precheck: [],\n execute: [\n {\n description: `set validation on ${collection}`,\n command: new CollModCommand(collection, {\n validator: { $jsonSchema: schema },\n validationLevel: options?.validationLevel,\n validationAction: options?.validationAction,\n }),\n },\n ],\n postcheck: [],\n };\n}\n\nexport function collMod(\n collection: string,\n options: CollModOptions,\n meta?: CollModMeta,\n): MongoMigrationPlanOperation {\n const hasValidator = options.validator != null && Object.keys(options.validator).length > 0;\n\n return {\n id: meta?.id ?? `collection.${collection}.collMod`,\n label: meta?.label ?? `Modify collection ${collection}`,\n operationClass: meta?.operationClass ?? 'destructive',\n precheck:\n options.validator != null\n ? [\n {\n description: `collection ${collection} exists`,\n source: new ListCollectionsCommand(),\n filter: MongoFieldFilter.eq('name', collection),\n expect: 'exists' as const,\n },\n ]\n : [],\n execute: [\n {\n description: `modify ${collection}`,\n command: new CollModCommand(collection, options),\n },\n ],\n postcheck: hasValidator\n ? [\n {\n description: `validator applied on ${collection}`,\n source: new ListCollectionsCommand(),\n filter: MongoAndExpr.of([\n MongoFieldFilter.eq('name', collection),\n ...(options.validationLevel\n ? [MongoFieldFilter.eq('options.validationLevel', options.validationLevel)]\n : []),\n ...(options.validationAction\n ? [MongoFieldFilter.eq('options.validationAction', options.validationAction)]\n : []),\n ]),\n expect: 'exists' as const,\n },\n ]\n : [],\n };\n}\n\nexport function validatedCollection(\n name: string,\n schema: Record<string, unknown>,\n indexes: ReadonlyArray<{ keys: MongoIndexKey[]; unique?: boolean }>,\n): MongoMigrationPlanOperation[] {\n return [\n createCollection(name, {\n validator: { $jsonSchema: schema },\n validationLevel: 'strict',\n validationAction: 'error',\n }),\n ...indexes.map((idx) => createIndex(name, idx.keys, { unique: idx.unique })),\n ];\n}\n"],"mappings":"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"}
|
package/dist/migration.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as CollModMeta } from "./op-factory-call-
|
|
2
|
-
import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
|
|
1
|
+
import { n as CollModMeta } from "./op-factory-call-BC-llGKt.mjs";
|
|
3
2
|
import { CollModOptions, CreateCollectionOptions, CreateIndexOptions, MongoDataTransformOperation, MongoFilterExpr, MongoIndexKey, MongoMigrationPlanOperation } from "@prisma-next/mongo-query-ast/control";
|
|
3
|
+
import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
|
|
4
4
|
import { placeholder } from "@prisma-next/errors/migration";
|
|
5
5
|
|
|
6
6
|
//#region src/core/migration-factories.d.ts
|
package/dist/migration.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as dropCollection, c as validatedCollection, i as dataTransform, n as createCollection, o as dropIndex, r as createIndex, s as setValidation, t as collMod } from "./migration-factories-
|
|
1
|
+
import { a as dropCollection, c as validatedCollection, i as dataTransform, n as createCollection, o as dropIndex, r as createIndex, s as setValidation, t as collMod } from "./migration-factories-BRBKKZia.mjs";
|
|
2
2
|
import { placeholder } from "@prisma-next/errors/migration";
|
|
3
3
|
export { collMod, createCollection, createIndex, dataTransform, dropCollection, dropIndex, placeholder, setValidation, validatedCollection };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MongoSchemaCollection, MongoSchemaIndex } from "@prisma-next/mongo-schema-ir";
|
|
2
|
-
import { CollModOptions, CreateCollectionOptions, CreateIndexOptions, MongoIndexKey, MongoMigrationPlanOperation } from "@prisma-next/mongo-query-ast/control";
|
|
3
2
|
import { ImportRequirement, TsExpression } from "@prisma-next/ts-render";
|
|
3
|
+
import { CollModOptions, CreateCollectionOptions, CreateIndexOptions, MongoIndexKey, MongoMigrationPlanOperation } from "@prisma-next/mongo-query-ast/control";
|
|
4
4
|
import { MigrationOperationClass, OpFactoryCall } from "@prisma-next/framework-components/control";
|
|
5
5
|
|
|
6
6
|
//#region src/core/op-factory-call.d.ts
|
|
@@ -73,4 +73,4 @@ declare function schemaIndexToCreateIndexOptions(index: MongoSchemaIndex): Creat
|
|
|
73
73
|
declare function schemaCollectionToCreateCollectionOptions(coll: MongoSchemaCollection): CreateCollectionOptions | undefined;
|
|
74
74
|
//#endregion
|
|
75
75
|
export { DropCollectionCall as a, schemaCollectionToCreateCollectionOptions as c, CreateIndexCall as i, schemaIndexToCreateIndexOptions as l, CollModMeta as n, DropIndexCall as o, CreateCollectionCall as r, OpFactoryCall$1 as s, CollModCall as t };
|
|
76
|
-
//# sourceMappingURL=op-factory-call-
|
|
76
|
+
//# sourceMappingURL=op-factory-call-BC-llGKt.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"op-factory-call-
|
|
1
|
+
{"version":3,"file":"op-factory-call-BC-llGKt.d.mts","names":[],"sources":["../src/core/op-factory-call.ts"],"mappings":";;;;;;UA6CiB,WAAA;EAAA,SACN,EAAA;EAAA,SACA,KAAA;EAAA,SACA,cAAA,GAAiB,uBAAA;AAAA;AAAA,uBAKb,iBAAA,SAA0B,YAAA,YAAwB,aAAA;EAAA,kBAC7C,WAAA;EAAA,kBACA,cAAA,EAAgB,uBAAA;EAAA,kBAChB,KAAA;EAAA,SACT,IAAA,CAAA,GAAQ,2BAAA;EAEjB,kBAAA,CAAA,YAA+B,iBAAA;EAAA,UAIrB,MAAA,CAAA;AAAA;AAAA,cASC,eAAA,SAAwB,iBAAA;EAAA,SAC1B,WAAA;EAAA,SACA,cAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA,EAAM,aAAA,CAAc,aAAA;EAAA,SACpB,OAAA,EAAS,kBAAA;EAAA,SACT,KAAA;cAGP,UAAA,UACA,IAAA,EAAM,aAAA,CAAc,aAAA,GACpB,OAAA,GAAU,kBAAA;EAUZ,IAAA,CAAA,GAAQ,2BAAA;EAIR,gBAAA,CAAA;AAAA;AAAA,cAOW,aAAA,SAAsB,iBAAA;EAAA,SACxB,WAAA;EAAA,SACA,cAAA;EAAA,SACA,UAAA;EAAA,SACA,IAAA,EAAM,aAAA,CAAc,aAAA;EAAA,SACpB,KAAA;cAEG,UAAA,UAAoB,IAAA,EAAM,aAAA,CAAc,aAAA;EAQpD,IAAA,CAAA,GAAQ,2BAAA;EAIR,gBAAA,CAAA;AAAA;AAAA,cAKW,oBAAA,SAA6B,iBAAA;EAAA,SAC/B,WAAA;EAAA,SACA,cAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,EAAS,uBAAA;EAAA,SACT,KAAA;cAEG,UAAA,UAAoB,OAAA,GAAU,uBAAA;EAQ1C,IAAA,CAAA,GAAQ,2BAAA;EAIR,gBAAA,CAAA;AAAA;AAAA,cAOW,kBAAA,SAA2B,iBAAA;EAAA,SAC7B,WAAA;EAAA,SACA,cAAA;EAAA,SACA,UAAA;EAAA,SACA,KAAA;cAEG,UAAA;EAOZ,IAAA,CAAA,GAAQ,2BAAA;EAIR,gBAAA,CAAA;AAAA;AAAA,cAKW,WAAA,SAAoB,iBAAA;EAAA,SACtB,WAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,EAAS,cAAA;EAAA,SACT,IAAA,EAAM,WAAA;EAAA,SACN,cAAA,EAAgB,uBAAA;EAAA,SAChB,KAAA;cAEG,UAAA,UAAoB,OAAA,EAAS,cAAA,EAAgB,IAAA,GAAO,WAAA;EAUhE,IAAA,CAAA,GAAQ,2BAAA;EAIR,gBAAA,CAAA;AAAA;AAAA,KAOU,eAAA,GACR,eAAA,GACA,aAAA,GACA,oBAAA,GACA,kBAAA,GACA,WAAA;AAAA,iBAEY,+BAAA,CAAgC,KAAA,EAAO,gBAAA,GAAmB,kBAAA;AAAA,iBAc1D,yCAAA,CACd,IAAA,EAAM,qBAAA,GACL,uBAAA"}
|
package/package.json
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-mongo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-dev.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "MongoDB target pack for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
+
"@prisma-next/adapter-mongo": "0.8.0-dev.1",
|
|
10
|
+
"@prisma-next/contract": "0.8.0-dev.1",
|
|
11
|
+
"@prisma-next/driver-mongo": "0.8.0-dev.1",
|
|
12
|
+
"@prisma-next/errors": "0.8.0-dev.1",
|
|
13
|
+
"@prisma-next/family-mongo": "0.8.0-dev.1",
|
|
14
|
+
"@prisma-next/framework-components": "0.8.0-dev.1",
|
|
15
|
+
"@prisma-next/migration-tools": "0.8.0-dev.1",
|
|
16
|
+
"@prisma-next/ts-render": "0.8.0-dev.1",
|
|
17
|
+
"@prisma-next/mongo-codec": "0.8.0-dev.1",
|
|
18
|
+
"@prisma-next/mongo-contract": "0.8.0-dev.1",
|
|
19
|
+
"@prisma-next/mongo-lowering": "0.8.0-dev.1",
|
|
20
|
+
"@prisma-next/mongo-query-ast": "0.8.0-dev.1",
|
|
21
|
+
"@prisma-next/mongo-schema-ir": "0.8.0-dev.1",
|
|
22
|
+
"@prisma-next/mongo-value": "0.8.0-dev.1",
|
|
23
|
+
"@prisma-next/utils": "0.8.0-dev.1",
|
|
9
24
|
"arktype": "^2.1.29",
|
|
10
|
-
"mongodb": "^6.16.0"
|
|
11
|
-
"@prisma-next/contract": "0.7.0",
|
|
12
|
-
"@prisma-next/framework-components": "0.7.0",
|
|
13
|
-
"@prisma-next/errors": "0.7.0",
|
|
14
|
-
"@prisma-next/migration-tools": "0.7.0",
|
|
15
|
-
"@prisma-next/ts-render": "0.7.0",
|
|
16
|
-
"@prisma-next/mongo-codec": "0.7.0",
|
|
17
|
-
"@prisma-next/mongo-contract": "0.7.0",
|
|
18
|
-
"@prisma-next/mongo-lowering": "0.7.0",
|
|
19
|
-
"@prisma-next/mongo-query-ast": "0.7.0",
|
|
20
|
-
"@prisma-next/mongo-schema-ir": "0.7.0",
|
|
21
|
-
"@prisma-next/mongo-value": "0.7.0",
|
|
22
|
-
"@prisma-next/utils": "0.7.0"
|
|
25
|
+
"mongodb": "^6.16.0"
|
|
23
26
|
},
|
|
24
27
|
"devDependencies": {
|
|
28
|
+
"@prisma-next/mongo-contract-psl": "0.8.0-dev.1",
|
|
29
|
+
"@prisma-next/psl-parser": "0.8.0-dev.1",
|
|
30
|
+
"@prisma-next/test-utils": "0.8.0-dev.1",
|
|
31
|
+
"@prisma-next/tsconfig": "0.8.0-dev.1",
|
|
32
|
+
"@prisma-next/tsdown": "0.8.0-dev.1",
|
|
25
33
|
"mongodb-memory-server": "11.0.1",
|
|
26
34
|
"pathe": "^2.0.3",
|
|
27
35
|
"tsdown": "0.22.0",
|
|
28
36
|
"typescript": "5.9.3",
|
|
29
|
-
"vitest": "4.1.5"
|
|
30
|
-
"@prisma-next/test-utils": "0.7.0",
|
|
31
|
-
"@prisma-next/tsconfig": "0.7.0",
|
|
32
|
-
"@prisma-next/tsdown": "0.7.0"
|
|
37
|
+
"vitest": "4.1.5"
|
|
33
38
|
},
|
|
34
39
|
"files": [
|
|
35
40
|
"dist",
|
|
@@ -41,7 +46,6 @@
|
|
|
41
46
|
"./migration": "./dist/migration.mjs",
|
|
42
47
|
"./pack": "./dist/pack.mjs",
|
|
43
48
|
"./runtime": "./dist/runtime.mjs",
|
|
44
|
-
"./schema-verify": "./dist/schema-verify.mjs",
|
|
45
49
|
"./package.json": "./package.json"
|
|
46
50
|
},
|
|
47
51
|
"repository": {
|
|
@@ -49,8 +53,6 @@
|
|
|
49
53
|
"url": "https://github.com/prisma/prisma-next.git",
|
|
50
54
|
"directory": "packages/3-mongo-target/1-mongo-target"
|
|
51
55
|
},
|
|
52
|
-
"main": "./dist/pack.mjs",
|
|
53
|
-
"module": "./dist/pack.mjs",
|
|
54
56
|
"types": "./dist/pack.d.mts",
|
|
55
57
|
"prismaNext": {
|
|
56
58
|
"minServerVersion": "6.0"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMongoRunnerDeps,
|
|
3
|
+
extractDb,
|
|
4
|
+
type MongoRunnerDependencies,
|
|
5
|
+
} from '@prisma-next/adapter-mongo/control';
|
|
6
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
7
|
+
import { MongoDriverImpl } from '@prisma-next/driver-mongo';
|
|
8
|
+
import type {
|
|
9
|
+
MongoControlFamilyInstance,
|
|
10
|
+
MongoControlTargetDescriptor,
|
|
11
|
+
} from '@prisma-next/family-mongo/control';
|
|
12
|
+
import { contractToMongoSchemaIR } from '@prisma-next/family-mongo/control';
|
|
13
|
+
import type {
|
|
14
|
+
MigrationRunner,
|
|
15
|
+
MigrationRunnerResult,
|
|
16
|
+
MigrationRunnerSuccessValue,
|
|
17
|
+
MultiSpaceCapableRunner,
|
|
18
|
+
MultiSpaceRunnerFailure,
|
|
19
|
+
MultiSpaceRunnerPerSpaceOptions,
|
|
20
|
+
MultiSpaceRunnerResult,
|
|
21
|
+
} from '@prisma-next/framework-components/control';
|
|
22
|
+
import {
|
|
23
|
+
type ContractSpaceMember,
|
|
24
|
+
projectSchemaToSpace,
|
|
25
|
+
} from '@prisma-next/migration-tools/aggregate';
|
|
26
|
+
import type { MongoContract } from '@prisma-next/mongo-contract';
|
|
27
|
+
import type { MongoSchemaCollection } from '@prisma-next/mongo-schema-ir';
|
|
28
|
+
import { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';
|
|
29
|
+
import { notOk, ok } from '@prisma-next/utils/result';
|
|
30
|
+
import { mongoTargetDescriptorMeta } from './descriptor-meta';
|
|
31
|
+
import { MongoMigrationPlanner } from './mongo-planner';
|
|
32
|
+
import { MongoMigrationRunner, type MongoMigrationRunnerExecuteOptions } from './mongo-runner';
|
|
33
|
+
import type { MongoTargetContract } from './mongo-target-contract';
|
|
34
|
+
import { MongoTargetContractSerializer } from './mongo-target-contract-serializer';
|
|
35
|
+
import { MongoTargetSchemaVerifier } from './mongo-target-schema-verifier';
|
|
36
|
+
|
|
37
|
+
export type { MongoControlTargetDescriptor };
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* `migration.ts` default-exports a `Migration` subclass whose `operations`
|
|
41
|
+
* getter returns the ordered list of operations and whose `describe()`
|
|
42
|
+
* returns the manifest identity metadata. `MongoMigrationPlanner.plan()`
|
|
43
|
+
* returns a `MigrationPlanWithAuthoringSurface` that knows how to render
|
|
44
|
+
* itself back to such a file; `MongoMigrationPlanner.emptyMigration()`
|
|
45
|
+
* returns the same shape for `migration new`. Users run the scaffolded
|
|
46
|
+
* `migration.ts` directly (via `node migration.ts`) to self-emit
|
|
47
|
+
* `ops.json` and attest the `migrationHash`.
|
|
48
|
+
*/
|
|
49
|
+
export const mongoTargetDescriptor: MongoControlTargetDescriptor<MongoTargetContract> = {
|
|
50
|
+
...mongoTargetDescriptorMeta,
|
|
51
|
+
contractSerializer: new MongoTargetContractSerializer(),
|
|
52
|
+
schemaVerifier: new MongoTargetSchemaVerifier(),
|
|
53
|
+
migrations: {
|
|
54
|
+
createPlanner(_family: MongoControlFamilyInstance) {
|
|
55
|
+
return new MongoMigrationPlanner();
|
|
56
|
+
},
|
|
57
|
+
createRunner(family: MongoControlFamilyInstance) {
|
|
58
|
+
// Deps are bound to the first driver passed to execute() and cached for
|
|
59
|
+
// subsequent calls. Callers must not change the driver between calls.
|
|
60
|
+
let cachedDeps: MongoRunnerDependencies | undefined;
|
|
61
|
+
|
|
62
|
+
const runMongo = async (
|
|
63
|
+
driver: Parameters<MigrationRunner<'mongo', 'mongo'>['execute']>[0]['driver'],
|
|
64
|
+
runnerOptions: Omit<MongoMigrationRunnerExecuteOptions, 'destinationContract'> & {
|
|
65
|
+
readonly destinationContract: unknown;
|
|
66
|
+
},
|
|
67
|
+
): Promise<MigrationRunnerResult> => {
|
|
68
|
+
cachedDeps ??= createMongoRunnerDeps(
|
|
69
|
+
driver,
|
|
70
|
+
MongoDriverImpl.fromDb(extractDb(driver)),
|
|
71
|
+
family,
|
|
72
|
+
);
|
|
73
|
+
// The framework `MigrationRunner` interface types `destinationContract`
|
|
74
|
+
// as `unknown`; the Mongo runner narrows to `MongoContract`. Validation
|
|
75
|
+
// happens upstream — `migration apply` calls
|
|
76
|
+
// `familyInstance.validateContract(migration.toContract)` before
|
|
77
|
+
// routing the contract here, so this cast preserves the framework
|
|
78
|
+
// signature without weakening the runner's typed surface.
|
|
79
|
+
return new MongoMigrationRunner(cachedDeps).execute({
|
|
80
|
+
...runnerOptions,
|
|
81
|
+
destinationContract: runnerOptions.destinationContract as MongoContract,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const runner: MigrationRunner<'mongo', 'mongo'> & MultiSpaceCapableRunner<'mongo', 'mongo'> =
|
|
86
|
+
{
|
|
87
|
+
async execute(options) {
|
|
88
|
+
const { driver, ...runnerOptions } = options;
|
|
89
|
+
return runMongo(driver, runnerOptions);
|
|
90
|
+
},
|
|
91
|
+
// Mongo cannot wrap DDL ops in a session transaction (createCollection,
|
|
92
|
+
// createIndex, collMod, setValidation all bypass transactions even on
|
|
93
|
+
// replica sets), so the cross-space envelope is *resumable* rather than
|
|
94
|
+
// transactional. Per-space-internal verify-gated marker atomicity
|
|
95
|
+
// already lives in `runner.execute`: ops apply, schema is introspected
|
|
96
|
+
// and verified, and the marker advances only on verify-pass. This loop
|
|
97
|
+
// composes that guarantee across spaces — earlier-advanced markers are
|
|
98
|
+
// not rolled back when a later space fails. Re-running reads each
|
|
99
|
+
// marker, finds spaces 1..N−1 at-head (no-op skip), retries N onward.
|
|
100
|
+
//
|
|
101
|
+
// Per-space verify is sliced via `projectSchemaToSpace`: the live DB
|
|
102
|
+
// holds collections owned by sibling spaces, but each space's verify
|
|
103
|
+
// only sees the slice that space's contract actually claims. Without
|
|
104
|
+
// the projection an aggregate of two spaces could not pass strict
|
|
105
|
+
// verify (every other-space collection would look like an extra).
|
|
106
|
+
//
|
|
107
|
+
// See `docs/architecture docs/subsystems/10. MongoDB Family.md` §
|
|
108
|
+
// Contract spaces and ADR 212 — Contract spaces.
|
|
109
|
+
async executeAcrossSpaces({ driver, perSpaceOptions }): Promise<MultiSpaceRunnerResult> {
|
|
110
|
+
const members = perSpaceOptions.map(toSpaceMember);
|
|
111
|
+
const perSpaceResults: Array<{
|
|
112
|
+
space: string;
|
|
113
|
+
value: MigrationRunnerSuccessValue;
|
|
114
|
+
}> = [];
|
|
115
|
+
for (let i = 0; i < perSpaceOptions.length; i++) {
|
|
116
|
+
const spaceOptions = perSpaceOptions[i];
|
|
117
|
+
if (!spaceOptions) continue;
|
|
118
|
+
const member = members[i];
|
|
119
|
+
if (!member) continue;
|
|
120
|
+
const others = members.filter((_, j) => j !== i);
|
|
121
|
+
const projectSchema = (schema: MongoSchemaIR): MongoSchemaIR => {
|
|
122
|
+
// `projectSchemaToSpace` returns a plain object
|
|
123
|
+
// `{...schemaIR, collections: prunedArray}` (not a
|
|
124
|
+
// `MongoSchemaIR` instance), so the descriptor rewraps
|
|
125
|
+
// the pruned collections into a fresh `MongoSchemaIR`
|
|
126
|
+
// before handing it to `verifyMongoSchema` (which
|
|
127
|
+
// depends on the class's `collectionNames` /
|
|
128
|
+
// `collection(name)` accessors).
|
|
129
|
+
const projected = projectSchemaToSpace(schema, member, others) as {
|
|
130
|
+
readonly collections: ReadonlyArray<MongoSchemaCollection>;
|
|
131
|
+
};
|
|
132
|
+
return new MongoSchemaIR(projected.collections);
|
|
133
|
+
};
|
|
134
|
+
const result = await runMongo(driver, { ...spaceOptions, projectSchema });
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
return notOk<MultiSpaceRunnerFailure>({
|
|
137
|
+
...result.failure,
|
|
138
|
+
failingSpace: spaceOptions.space,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
perSpaceResults.push({ space: spaceOptions.space, value: result.value });
|
|
142
|
+
}
|
|
143
|
+
return ok({ perSpaceResults });
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
return runner;
|
|
147
|
+
},
|
|
148
|
+
contractToSchema(contract: Contract | null) {
|
|
149
|
+
return contractToMongoSchemaIR(contract as MongoContract | null);
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
create() {
|
|
153
|
+
return { familyId: 'mongo' as const, targetId: 'mongo' as const };
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Synthesise the minimum {@link projectSchemaToSpace}-compatible
|
|
159
|
+
* `ContractSpaceMember` shape from a per-space option entry. The
|
|
160
|
+
* projector only reads `spaceId` and `contract.storage`; the rest of
|
|
161
|
+
* `ContractSpaceMember` (head ref invariants, hydrated migration
|
|
162
|
+
* graph) is irrelevant at runner time and stubbed with sentinels.
|
|
163
|
+
*
|
|
164
|
+
* The `as unknown as ContractSpaceMember` cast is the load-bearing bit
|
|
165
|
+
* — the projector duck-types its members so a sentinel-shaped graph
|
|
166
|
+
* never gets read, but the framework type carries a richer shape.
|
|
167
|
+
*/
|
|
168
|
+
function toSpaceMember(
|
|
169
|
+
opts: MultiSpaceRunnerPerSpaceOptions<'mongo', 'mongo'>,
|
|
170
|
+
): ContractSpaceMember {
|
|
171
|
+
return {
|
|
172
|
+
spaceId: opts.space,
|
|
173
|
+
contract: opts.destinationContract as Contract,
|
|
174
|
+
headRef: { hash: '', invariants: [] },
|
|
175
|
+
migrations: {
|
|
176
|
+
graph: {
|
|
177
|
+
nodes: new Set<string>(),
|
|
178
|
+
forwardChain: new Map(),
|
|
179
|
+
reverseChain: new Map(),
|
|
180
|
+
migrationByHash: new Map(),
|
|
181
|
+
},
|
|
182
|
+
packagesByMigrationHash: new Map(),
|
|
183
|
+
},
|
|
184
|
+
} as unknown as ContractSpaceMember;
|
|
185
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import { contractToMongoSchemaIR } from '@prisma-next/family-mongo/control';
|
|
2
3
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
3
4
|
import type {
|
|
4
5
|
MigrationOperationClass,
|
|
@@ -18,7 +19,6 @@ import type {
|
|
|
18
19
|
MongoSchemaValidator,
|
|
19
20
|
} from '@prisma-next/mongo-schema-ir';
|
|
20
21
|
import { canonicalize, deepEqual } from '@prisma-next/mongo-schema-ir';
|
|
21
|
-
import { contractToMongoSchemaIR } from './contract-to-schema';
|
|
22
22
|
import type { OpFactoryCall } from './op-factory-call';
|
|
23
23
|
import {
|
|
24
24
|
CollModCall,
|
package/src/core/mongo-runner.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { MarkerOperations, MongoRunnerDependencies } from '@prisma-next/adapter-mongo/control';
|
|
1
2
|
import type { ContractMarkerRecord } from '@prisma-next/contract/types';
|
|
2
3
|
import { errorRunnerFailed } from '@prisma-next/errors/execution';
|
|
4
|
+
import { verifyMongoSchema } from '@prisma-next/family-mongo/schema-verify';
|
|
3
5
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
4
6
|
import {
|
|
5
7
|
APP_SPACE_ID,
|
|
@@ -17,7 +19,6 @@ import type {
|
|
|
17
19
|
AnyMongoMigrationOperation,
|
|
18
20
|
MongoDataTransformCheck,
|
|
19
21
|
MongoDataTransformOperation,
|
|
20
|
-
MongoDdlCommandVisitor,
|
|
21
22
|
MongoInspectionCommandVisitor,
|
|
22
23
|
MongoMigrationCheck,
|
|
23
24
|
MongoMigrationPlanOperation,
|
|
@@ -26,53 +27,10 @@ import type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';
|
|
|
26
27
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
27
28
|
import { FilterEvaluator } from './filter-evaluator';
|
|
28
29
|
import { deserializeMongoOps } from './mongo-ops-serializer';
|
|
29
|
-
import { verifyMongoSchema } from './schema-verify/verify-mongo-schema';
|
|
30
30
|
|
|
31
31
|
const READ_ONLY_CHECK_COMMAND_KINDS: ReadonlySet<string> = new Set(['aggregate', 'rawAggregate']);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
* Marker / ledger operations the Mongo runner depends on. Every method
|
|
35
|
-
* takes a `space` parameter so each loaded contract space addresses its
|
|
36
|
-
* own marker row independently — see ADR 212 for the per-space
|
|
37
|
-
* mechanism.
|
|
38
|
-
*/
|
|
39
|
-
export interface MarkerOperations {
|
|
40
|
-
readMarker(space: string): Promise<ContractMarkerRecord | null>;
|
|
41
|
-
initMarker(
|
|
42
|
-
space: string,
|
|
43
|
-
destination: {
|
|
44
|
-
readonly storageHash: string;
|
|
45
|
-
readonly profileHash: string;
|
|
46
|
-
readonly invariants?: readonly string[];
|
|
47
|
-
},
|
|
48
|
-
): Promise<void>;
|
|
49
|
-
updateMarker(
|
|
50
|
-
space: string,
|
|
51
|
-
expectedFrom: string,
|
|
52
|
-
destination: {
|
|
53
|
-
readonly storageHash: string;
|
|
54
|
-
readonly profileHash: string;
|
|
55
|
-
readonly invariants?: readonly string[];
|
|
56
|
-
},
|
|
57
|
-
): Promise<boolean>;
|
|
58
|
-
writeLedgerEntry(
|
|
59
|
-
space: string,
|
|
60
|
-
entry: {
|
|
61
|
-
readonly edgeId: string;
|
|
62
|
-
readonly from: string;
|
|
63
|
-
readonly to: string;
|
|
64
|
-
},
|
|
65
|
-
): Promise<void>;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface MongoRunnerDependencies {
|
|
69
|
-
readonly commandExecutor: MongoDdlCommandVisitor<Promise<void>>;
|
|
70
|
-
readonly inspectionExecutor: MongoInspectionCommandVisitor<Promise<Record<string, unknown>[]>>;
|
|
71
|
-
readonly adapter: MongoAdapter;
|
|
72
|
-
readonly driver: MongoDriver;
|
|
73
|
-
readonly markerOps: MarkerOperations;
|
|
74
|
-
readonly introspectSchema: () => Promise<MongoSchemaIR>;
|
|
75
|
-
}
|
|
33
|
+
export type { MarkerOperations, MongoRunnerDependencies };
|
|
76
34
|
|
|
77
35
|
export interface MongoMigrationRunnerExecuteOptions {
|
|
78
36
|
readonly plan: MigrationPlan;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { MongoContractSerializerBase } from '@prisma-next/family-mongo/ir';
|
|
2
|
+
import { UNSPECIFIED_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
3
|
+
import { type MongoContract, MongoStorage } from '@prisma-next/mongo-contract';
|
|
4
|
+
import type { JsonObject } from '@prisma-next/utils/json';
|
|
5
|
+
import type { MongoTargetContract } from './mongo-target-contract';
|
|
6
|
+
import { MongoTargetUnspecifiedDatabase } from './mongo-target-database';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Mongo target `ContractSerializer` concretion. Plugs into the
|
|
10
|
+
* family-shared deserialization pipeline at `constructTargetContract`,
|
|
11
|
+
* wrapping the validated flat-data shape in a `MongoStorage` class
|
|
12
|
+
* instance and providing the target's default namespace map.
|
|
13
|
+
*
|
|
14
|
+
* Default namespaces is
|
|
15
|
+
* `{ [UNSPECIFIED_NAMESPACE_ID]: MongoTargetUnspecifiedDatabase.instance }`
|
|
16
|
+
* — supplied at this target-layer call site because the family-layer
|
|
17
|
+
* `MongoStorage` class is target-agnostic (it cannot import the
|
|
18
|
+
* Mongo-target's namespace concretion). Contracts authored before
|
|
19
|
+
* multi-namespace support bind to the unspecified singleton without the
|
|
20
|
+
* call site declaring anything.
|
|
21
|
+
*
|
|
22
|
+
* `validated.storage.collections` already carries `MongoCollection` IR
|
|
23
|
+
* class instances by the time this method runs — the family-base
|
|
24
|
+
* `hydrateMongoContract` walks the arktype-validated tree and
|
|
25
|
+
* constructs class instances before validation. The target serializer
|
|
26
|
+
* just wraps the envelope.
|
|
27
|
+
*/
|
|
28
|
+
export class MongoTargetContractSerializer extends MongoContractSerializerBase<MongoTargetContract> {
|
|
29
|
+
protected constructTargetContract(validated: MongoContract): MongoTargetContract {
|
|
30
|
+
const { storage, ...rest } = validated;
|
|
31
|
+
const targetStorage = new MongoStorage({
|
|
32
|
+
storageHash: storage.storageHash,
|
|
33
|
+
collections: storage.collections,
|
|
34
|
+
namespaces: {
|
|
35
|
+
[UNSPECIFIED_NAMESPACE_ID]: MongoTargetUnspecifiedDatabase.instance,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return { ...rest, storage: targetStorage };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Produce the canonical on-disk JSON shape from an in-memory Mongo
|
|
43
|
+
* contract. Strips runtime-only fields the storage class carries
|
|
44
|
+
* for its live-instance API but that don't belong in the persisted
|
|
45
|
+
* envelope: `MongoStorage.namespaces` is a Namespace-class map the
|
|
46
|
+
* verifier and runtime walk; the persisted shape omits it (today's
|
|
47
|
+
* contracts have a single implicit unspecified namespace; future
|
|
48
|
+
* explicit per-collection assignment will surface in JSON via a
|
|
49
|
+
* different field).
|
|
50
|
+
*
|
|
51
|
+
* Constructing the JsonObject here — rather than relying on
|
|
52
|
+
* non-enumerable property tricks at the storage class — keeps the
|
|
53
|
+
* "what's on disk" decision in the SPI implementer, where it
|
|
54
|
+
* belongs.
|
|
55
|
+
*/
|
|
56
|
+
override serializeContract(contract: MongoTargetContract): JsonObject {
|
|
57
|
+
const { storage, ...rest } = contract;
|
|
58
|
+
// `as unknown as JsonObject` because the returned literal mixes
|
|
59
|
+
// `MongoCollection` class instances under `storage.collections` with
|
|
60
|
+
// the JSON-clean remainder of the contract envelope. The class
|
|
61
|
+
// instances are JSON-clean by construction (their `kind` literal is
|
|
62
|
+
// enumerable; nested IR shapes are normalised by the constructor),
|
|
63
|
+
// so the canonical-stringify pass produces correct output, but the
|
|
64
|
+
// structural type system doesn't know `MongoCollection` is JSON-safe.
|
|
65
|
+
return {
|
|
66
|
+
...rest,
|
|
67
|
+
storage: {
|
|
68
|
+
storageHash: storage.storageHash,
|
|
69
|
+
collections: storage.collections,
|
|
70
|
+
},
|
|
71
|
+
} as unknown as JsonObject;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MongoContract, MongoStorage } from '@prisma-next/mongo-contract';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mongo target contract envelope: the result of
|
|
5
|
+
* `descriptor.contractSerializer.deserializeContract(json)`.
|
|
6
|
+
*
|
|
7
|
+
* Structurally `MongoContract` with the storage envelope promoted to
|
|
8
|
+
* the family-layer `MongoStorage` class instance — the class carries
|
|
9
|
+
* `namespaces` and gives the rest of the framework a stable surface to
|
|
10
|
+
* reach for. The leaf collection / index shapes inside
|
|
11
|
+
* `storage.collections` are family-layer `MongoCollection` instances.
|
|
12
|
+
*/
|
|
13
|
+
export type MongoTargetContract = Omit<MongoContract, 'storage'> & {
|
|
14
|
+
readonly storage: MongoStorage;
|
|
15
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
freezeNode,
|
|
3
|
+
NamespaceBase,
|
|
4
|
+
UNSPECIFIED_NAMESPACE_ID,
|
|
5
|
+
} from '@prisma-next/framework-components/ir';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mongo target `Namespace` concretion. In Mongo the "namespace" concept
|
|
9
|
+
* binds to the connection's `db` field — a `MongoTargetDatabase` instance
|
|
10
|
+
* names the database the collections live under.
|
|
11
|
+
*
|
|
12
|
+
* Qualifier emission is the rendering seam: query / DDL emission asks the
|
|
13
|
+
* namespace for its qualifier (e.g. `"<db>.<collection>"`) and consumes
|
|
14
|
+
* the result polymorphically. The unspecified singleton overrides these
|
|
15
|
+
* methods to elide the prefix entirely — call sites stay polymorphic and
|
|
16
|
+
* never branch on `id === UNSPECIFIED_NAMESPACE_ID`.
|
|
17
|
+
*
|
|
18
|
+
* **Freeze-trap warning.** The constructor calls `freezeNode(this)` at
|
|
19
|
+
* the end. Direct subclasses MUST NOT add instance fields — the freeze
|
|
20
|
+
* runs in this base constructor and any subclass field assignment will
|
|
21
|
+
* silently fail in non-strict mode or throw in strict mode. The
|
|
22
|
+
* `MongoTargetUnspecifiedDatabase` singleton below is intentionally
|
|
23
|
+
* field-free for this reason; if a future subclass needs to carry
|
|
24
|
+
* additional fields, lift this `freezeNode` to the leaf-class
|
|
25
|
+
* constructors (or to a `seal()` hook each leaf calls explicitly).
|
|
26
|
+
*/
|
|
27
|
+
export class MongoTargetDatabase extends NamespaceBase {
|
|
28
|
+
readonly kind = 'database' as const;
|
|
29
|
+
readonly id: string;
|
|
30
|
+
|
|
31
|
+
constructor(id: string) {
|
|
32
|
+
super();
|
|
33
|
+
this.id = id;
|
|
34
|
+
freezeNode(this);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The bare qualifier as it would appear in a rendered string. The
|
|
39
|
+
* unspecified-database singleton overrides this to return `''`.
|
|
40
|
+
*/
|
|
41
|
+
qualifier(): string {
|
|
42
|
+
return this.id;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Qualify a collection name with the database prefix. The
|
|
47
|
+
* unspecified-database singleton overrides this to emit just the
|
|
48
|
+
* collection name. Used by emission/introspection paths that need a
|
|
49
|
+
* fully-qualified reference.
|
|
50
|
+
*/
|
|
51
|
+
qualifyCollection(collectionName: string): string {
|
|
52
|
+
return `${this.id}.${collectionName}`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Singleton subclass for the reserved sentinel namespace id
|
|
58
|
+
* (`UNSPECIFIED_NAMESPACE_ID`). Overrides qualifier emission to elide
|
|
59
|
+
* the database prefix — call sites that consume `qualifier()` /
|
|
60
|
+
* `qualifyCollection()` get unqualified output without branching on the
|
|
61
|
+
* namespace id.
|
|
62
|
+
*
|
|
63
|
+
* This is the target-side materialization of "the framework provides
|
|
64
|
+
* affordances; targets implement specifics": the framework names the
|
|
65
|
+
* sentinel; Mongo decides what no-database-bound means here (the
|
|
66
|
+
* collection name, naked).
|
|
67
|
+
*/
|
|
68
|
+
export class MongoTargetUnspecifiedDatabase extends MongoTargetDatabase {
|
|
69
|
+
static readonly instance: MongoTargetUnspecifiedDatabase = new MongoTargetUnspecifiedDatabase();
|
|
70
|
+
|
|
71
|
+
private constructor() {
|
|
72
|
+
super(UNSPECIFIED_NAMESPACE_ID);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override qualifier(): string {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
override qualifyCollection(collectionName: string): string {
|
|
80
|
+
return collectionName;
|
|
81
|
+
}
|
|
82
|
+
}
|