@prisma-next/target-mongo 0.4.0-dev.9 → 0.4.2
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 +4 -1
- package/dist/control.d.mts +32 -21
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +101 -142
- package/dist/control.mjs.map +1 -1
- package/dist/{migration-factories-gwi81C8u.mjs → migration-factories-Dbk5afMU.mjs} +1 -1
- package/dist/{migration-factories-gwi81C8u.mjs.map → migration-factories-Dbk5afMU.mjs.map} +1 -1
- package/dist/migration.d.mts +1 -1
- package/dist/migration.mjs +1 -1
- package/dist/{op-factory-call-CfPGebEH.d.mts → op-factory-call-CVgzmLJh.d.mts} +26 -25
- package/dist/op-factory-call-CVgzmLJh.d.mts.map +1 -0
- package/dist/schema-verify.d.mts +22 -0
- package/dist/schema-verify.d.mts.map +1 -0
- package/dist/schema-verify.mjs +3 -0
- package/dist/verify-mongo-schema-P0TRBJNs.mjs +582 -0
- package/dist/verify-mongo-schema-P0TRBJNs.mjs.map +1 -0
- package/package.json +18 -13
- package/src/core/mongo-planner.ts +5 -6
- package/src/core/mongo-runner.ts +38 -26
- package/src/core/op-factory-call.ts +81 -26
- package/src/core/render-ops.ts +2 -35
- package/src/core/render-typescript.ts +42 -79
- package/src/core/schema-diff.ts +402 -0
- package/src/core/schema-verify/canonicalize-introspection.ts +389 -0
- package/src/core/schema-verify/verify-mongo-schema.ts +60 -0
- package/src/exports/control.ts +1 -1
- package/src/exports/schema-verify.ts +2 -0
- package/dist/op-factory-call-CfPGebEH.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ MongoDB target pack for Prisma Next.
|
|
|
14
14
|
- `./pack`: pure target pack ref used by `@prisma-next/family-mongo` and `@prisma-next/mongo-contract-ts`
|
|
15
15
|
- `./codec-types`: base Mongo codec type map
|
|
16
16
|
- `./migration`: factory functions (the `Migration` base class is in `@prisma-next/family-mongo/migration`)
|
|
17
|
+
- `./control`: `MongoMigrationRunner` and `createMongoRunnerDeps` for runtime migration execution
|
|
18
|
+
- `./schema-verify`: pure `verifyMongoSchema(...)` (no DB I/O); composes `contractToMongoSchemaIR` and `diffMongoSchemas` so the runner's post-apply verify step and `MongoFamilyInstance.schemaVerify` agree on "matches the contract" by construction
|
|
17
19
|
|
|
18
20
|
## Usage
|
|
19
21
|
|
|
@@ -33,6 +35,7 @@ const contract = defineContract({
|
|
|
33
35
|
### Migration authoring
|
|
34
36
|
|
|
35
37
|
```typescript
|
|
38
|
+
import { MigrationCLI } from '@prisma-next/cli/migration-cli';
|
|
36
39
|
import { Migration } from '@prisma-next/family-mongo/migration';
|
|
37
40
|
import { createIndex, createCollection } from '@prisma-next/target-mongo/migration';
|
|
38
41
|
|
|
@@ -49,7 +52,7 @@ class UsersMigration extends Migration {
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
export default UsersMigration;
|
|
52
|
-
|
|
55
|
+
MigrationCLI.run(import.meta.url, UsersMigration);
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
Run `tsx migration.ts` to produce `ops.json` and `migration.json` (when `describe()` is implemented). Use `--dry-run` to preview without writing.
|
package/dist/control.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a as DropCollectionCall, c as
|
|
1
|
+
import { a as DropCollectionCall, c as schemaCollectionToCreateCollectionOptions, i as CreateIndexCall, l as schemaIndexToCreateIndexOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall } from "./op-factory-call-CVgzmLJh.mjs";
|
|
2
2
|
import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
|
|
3
3
|
import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
|
|
4
4
|
import { AnyMongoMigrationOperation, MongoAndExpr, MongoDdlCommandVisitor, MongoExistsExpr, MongoExprFilter, MongoFieldFilter, MongoFilterExpr, MongoFilterVisitor, MongoInspectionCommandVisitor, MongoMigrationPlanOperation, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
|
|
5
5
|
import { Migration, MigrationMeta } from "@prisma-next/migration-tools/migration";
|
|
6
|
+
import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext, OperationContext } from "@prisma-next/framework-components/control";
|
|
6
7
|
import { MongoContract } from "@prisma-next/mongo-contract";
|
|
7
|
-
import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationPlannerConflict, MigrationPlannerResult, MigrationRunnerExecutionChecks, MigrationRunnerResult, MigrationScaffoldContext } from "@prisma-next/framework-components/control";
|
|
8
8
|
import { ContractMarkerRecord } from "@prisma-next/contract/types";
|
|
9
9
|
import { Db } from "mongodb";
|
|
10
10
|
import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
|
|
@@ -74,12 +74,11 @@ declare class MongoMigrationPlanner implements MigrationPlanner<'mongo', 'mongo'
|
|
|
74
74
|
/**
|
|
75
75
|
* Produce an empty `migration.ts` authoring surface for `migration new`.
|
|
76
76
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* contract `.d.ts`.
|
|
77
|
+
* The "empty migration" is a `PlannerProducedMongoMigration` with no
|
|
78
|
+
* operations; `renderTypeScript()` emits a stub class with the correct
|
|
79
|
+
* `from`/`to` metadata that the user then fills in with operations. The
|
|
80
|
+
* contract path on the context is unused — Mongo's emitted source does
|
|
81
|
+
* not import from the generated contract `.d.ts`.
|
|
83
82
|
*/
|
|
84
83
|
emptyMigration(context: MigrationScaffoldContext): MigrationPlanWithAuthoringSurface;
|
|
85
84
|
}
|
|
@@ -107,21 +106,25 @@ interface MongoRunnerDependencies {
|
|
|
107
106
|
readonly adapter: MongoAdapter;
|
|
108
107
|
readonly driver: MongoDriver;
|
|
109
108
|
readonly markerOps: MarkerOperations;
|
|
109
|
+
readonly introspectSchema: () => Promise<MongoSchemaIR>;
|
|
110
|
+
}
|
|
111
|
+
interface MongoMigrationRunnerExecuteOptions {
|
|
112
|
+
readonly plan: MigrationPlan;
|
|
113
|
+
readonly destinationContract: MongoContract;
|
|
114
|
+
readonly policy: MigrationOperationPolicy;
|
|
115
|
+
readonly callbacks?: {
|
|
116
|
+
onOperationStart?(op: MigrationPlanOperation): void;
|
|
117
|
+
onOperationComplete?(op: MigrationPlanOperation): void;
|
|
118
|
+
};
|
|
119
|
+
readonly executionChecks?: MigrationRunnerExecutionChecks;
|
|
120
|
+
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
|
|
121
|
+
readonly strictVerification?: boolean;
|
|
122
|
+
readonly context?: OperationContext;
|
|
110
123
|
}
|
|
111
124
|
declare class MongoMigrationRunner {
|
|
112
125
|
private readonly deps;
|
|
113
126
|
constructor(deps: MongoRunnerDependencies);
|
|
114
|
-
execute(options:
|
|
115
|
-
readonly plan: MigrationPlan;
|
|
116
|
-
readonly destinationContract: unknown;
|
|
117
|
-
readonly policy: MigrationOperationPolicy;
|
|
118
|
-
readonly callbacks?: {
|
|
119
|
-
onOperationStart?(op: MigrationPlanOperation): void;
|
|
120
|
-
onOperationComplete?(op: MigrationPlanOperation): void;
|
|
121
|
-
};
|
|
122
|
-
readonly executionChecks?: MigrationRunnerExecutionChecks;
|
|
123
|
-
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
|
|
124
|
-
}): Promise<MigrationRunnerResult>;
|
|
127
|
+
execute(options: MongoMigrationRunnerExecuteOptions): Promise<MigrationRunnerResult>;
|
|
125
128
|
private executeDataTransform;
|
|
126
129
|
private evaluateDataTransformChecks;
|
|
127
130
|
private evaluateChecks;
|
|
@@ -168,15 +171,23 @@ interface RenderMigrationMeta {
|
|
|
168
171
|
readonly labels?: readonly string[];
|
|
169
172
|
}
|
|
170
173
|
/**
|
|
171
|
-
* Render a list of Mongo `OpFactoryCall`s as a
|
|
174
|
+
* Render a list of Mongo `OpFactoryCall`s as a `migration.ts`
|
|
172
175
|
* source string. The result is shebanged, extends the user-facing
|
|
173
176
|
* `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
|
|
174
177
|
* implements the abstract `operations` and `describe` members. `meta` is
|
|
175
178
|
* always rendered — `describe()` is part of the `Migration` contract, so
|
|
176
179
|
* even an empty stub must satisfy it; callers pass empty strings for a
|
|
177
180
|
* migration-new scaffold.
|
|
181
|
+
*
|
|
182
|
+
* The walk is polymorphic: each call node contributes its own
|
|
183
|
+
* `renderTypeScript()` expression and declares its own
|
|
184
|
+
* `importRequirements()`. The top-level renderer aggregates imports
|
|
185
|
+
* across all nodes and emits one `import { … } from "…"` line per module.
|
|
186
|
+
* The `Migration` and `MigrationCLI` imports are always emitted — they're
|
|
187
|
+
* structural to the rendered scaffold (extends `Migration`, calls
|
|
188
|
+
* `MigrationCLI.run`), not driven by any node.
|
|
178
189
|
*/
|
|
179
190
|
declare function renderCallsToTypeScript(calls: ReadonlyArray<OpFactoryCall>, meta: RenderMigrationMeta): string;
|
|
180
191
|
//#endregion
|
|
181
|
-
export { CollModCall, type CollModMeta, CreateCollectionCall, CreateIndexCall, DropCollectionCall, DropIndexCall, FilterEvaluator, type MarkerOperations, MongoMigrationPlanner, MongoMigrationRunner, type MongoRunnerDependencies, type OpFactoryCall, type
|
|
192
|
+
export { CollModCall, type CollModMeta, CreateCollectionCall, CreateIndexCall, DropCollectionCall, DropIndexCall, FilterEvaluator, type MarkerOperations, MongoMigrationPlanner, MongoMigrationRunner, type MongoRunnerDependencies, type OpFactoryCall, type PlanCallsResult, PlannerProducedMongoMigration, type RenderMigrationMeta, contractToMongoSchemaIR, deserializeMongoOp, deserializeMongoOps, formatMongoOperations, initMarker, readMarker, renderCallsToTypeScript, renderOps, schemaCollectionToCreateCollectionOptions, schemaIndexToCreateIndexOptions, serializeMongoOps, updateMarker, writeLedgerEntry };
|
|
182
193
|
//# sourceMappingURL=control.d.mts.map
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;iBAoDgB,uBAAA,WAAkC,uBAAuB;;;iBC6CzD,qBAAA,sBAA2C;;;cC/C9C,eAAA,YAA2B;;mBAGrB,sBAAsB;cAK3B;YAKF;WAID;YAIC;eAIG;cAKD;;;;iBCjDQ,UAAA,KAAe,KAAK,QAAQ;iBAgB5B,UAAA,KAChB;;;IAEH;iBAcmB,YAAA,KAChB;;;IAGH;iBAiBmB,gBAAA,KAChB;;EHlCU,SAAA,IAAA,EAAA,MAAA;;IGoCb;;;iBC8ea,kBAAA,iBAAmC;iBAOnC,mBAAA,4BAA+C;iBAI/C,iBAAA,eAAgC;;;KC7epC,eAAA;;kBACoC;;;sBACI;;cAEvC,qBAAA,YAAiC;;;ILpD9B,SAAA,MAAA,EAAA,OAAuB;qBKwDlB;kCACa,cAAc;MAC1C;EJbU,IAAA,CAAA,OAAA,EAAA;;;qBIiIK;IHhLR,SAAA,QAAgB,EAAA,MAAA;IAGV,SAAA,mBAAA,EG+Ke,aH/Kf,CG+K6B,8BH/K7B,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAAsB,CAAA,CAAA,EGgLnC,sBHhLmC;EAK3B
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/contract-to-schema.ts","../src/core/ddl-formatter.ts","../src/core/filter-evaluator.ts","../src/core/marker-ledger.ts","../src/core/mongo-ops-serializer.ts","../src/core/mongo-planner.ts","../src/core/mongo-runner.ts","../src/core/planner-produced-migration.ts","../src/core/render-ops.ts","../src/core/render-typescript.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;iBAoDgB,uBAAA,WAAkC,uBAAuB;;;iBC6CzD,qBAAA,sBAA2C;;;cC/C9C,eAAA,YAA2B;;mBAGrB,sBAAsB;cAK3B;YAKF;WAID;YAIC;eAIG;cAKD;;;;iBCjDQ,UAAA,KAAe,KAAK,QAAQ;iBAgB5B,UAAA,KAChB;;;IAEH;iBAcmB,YAAA,KAChB;;;IAGH;iBAiBmB,gBAAA,KAChB;;EHlCU,SAAA,IAAA,EAAA,MAAA;;IGoCb;;;iBC8ea,kBAAA,iBAAmC;iBAOnC,mBAAA,4BAA+C;iBAI/C,iBAAA,eAAgC;;;KC7epC,eAAA;;kBACoC;;;sBACI;;cAEvC,qBAAA,YAAiC;;;ILpD9B,SAAA,MAAA,EAAA,OAAuB;qBKwDlB;kCACa,cAAc;MAC1C;EJbU,IAAA,CAAA,OAAA,EAAA;;;qBIiIK;IHhLR,SAAA,QAAgB,EAAA,MAAA;IAGV,SAAA,mBAAA,EG+Ke,aH/Kf,CG+K6B,8BH/K7B,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAAsB,CAAA,CAAA,EGgLnC,sBHhLmC;EAK3B;;;;;;;;;0BGiMY,2BAA2B;;;;UC5NpC,gBAAA;gBACD,QAAQ;;;;MAIlB;ENgBU,YAAA,CAAA,YAAA,EAAuB,MAAA,EAAA,WAAW,EAAA;;;MMZ7C;ELyDW,gBAAA,CAAA,KAAA,EAAqB;;;;EC/CxB,CAAA,CAAA,EILP,OJKO,CAAA,IAAA,CAAA;;AAG4B,UILxB,uBAAA,CJKwB;EAK3B,SAAA,eAAA,EITc,sBJSd,CITqC,OJSrC,CAAA,IAAA,CAAA,CAAA;EAKF,SAAA,kBAAA,EIbmB,6BJanB,CIbiD,OJajD,CIbyD,MJazD,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,CAAA;EAID,SAAA,OAAA,EIhBS,YJgBT;EAIC,SAAA,MAAA,EInBO,WJmBP;EAIG,SAAA,SAAA,EItBO,gBJsBP;EAKD,SAAA,gBAAA,EAAA,GAAA,GI1BqB,OJ0BrB,CI1B6B,aJ0B7B,CAAA;;AA9B4C,UIOzC,kCAAA,CJPyC;iBIQzC;gCACe;mBACb;EH7BG,SAAA,SAAU,CAAA,EAAA;IAAK,gBAAA,EAAA,EAAA,EG+BX,sBH/BW,CAAA,EAAA,IAAA;IAAa,mBAAA,EAAA,EAAA,EGgCrB,sBHhCqB,CAAA,EAAA,IAAA;EAAR,CAAA;EAAO,SAAA,eAAA,CAAA,EGkCpB,8BHlCoB;EAgB3B,SAAA,mBAChB,EGkB0B,aHhBtB,CGgBoC,8BHhBpC,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAcY,SAAA,kBAChB,CAAA,EAAA,OAGH;EAiBmB,SAAA,OAAA,CAAA,EGjBD,gBHoBlB;;cGLU,oBAAA;;EFmfG,WAAA,CAAA,IAAA,EElfqB,uBFkfc;EAOnC,OAAA,CAAA,OAAA,EEvfS,kCFufsC,CAAA,EEvfD,OFuf2B,CEvfnB,qBFufmB,CAAA;EAIzE,QAAA,oBAAiB;;;;EC7erB,QAAA,0BACoC;EAGnC,QAAA,yBAAsB;;;;;;;;;;;;;ALpDnC;;;;AC6CA;;;cMzEa,6BAAA,SACH,UAAU,uCACP;ELwBA,iBAAA,KAAgB;EAGV,iBAAA,IAAA;EAAsB,SAAA,QAAA,EAAA,OAAA;EAK3B,WAAA,CAAA,KAAA,EAAA,SK3BuB,aL2BvB,EAAA,EAAA,IAAA,EK1Ba,aL0Bb;EAKF,IAAA,UAAA,CAAA,CAAA,EAAA,SK1B0B,0BL0B1B,EAAA;EAID,QAAA,CAAA,CAAA,EK1BY,aL0BZ;EAIC,gBAAA,CAAA,CAAA,EAAA,MAAA;;;;iBMpEI,SAAA,QAAiB,cAAc,iBAAiB;;;UCC/C,mBAAA;;;;;;;;;;;;ATgDjB;;;;AC6CA;;;;AC/CA;;;AAQc,iBOTE,uBAAA,CPSF,KAAA,EORL,aPQK,CORS,aPQT,CAAA,EAAA,IAAA,EOPN,mBPOM,CAAA,EAAA,MAAA"}
|
package/dist/control.mjs
CHANGED
|
@@ -1,53 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { n as contractToMongoSchemaIR, t as verifyMongoSchema } from "./verify-mongo-schema-P0TRBJNs.mjs";
|
|
2
|
+
import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-Dbk5afMU.mjs";
|
|
3
|
+
import { canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
|
|
3
4
|
import { AggregateCommand, MongoAddFieldsStage, MongoLimitStage, MongoLookupStage, MongoMatchStage, MongoMergeStage, MongoProjectStage, MongoSortStage, RawAggregateCommand, RawDeleteManyCommand, RawDeleteOneCommand, RawFindOneAndDeleteCommand, RawFindOneAndUpdateCommand, RawInsertManyCommand, RawInsertOneCommand, RawUpdateManyCommand, RawUpdateOneCommand } from "@prisma-next/mongo-query-ast/execution";
|
|
4
5
|
import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
|
|
5
6
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
7
|
import { type } from "arktype";
|
|
8
|
+
import { TsExpression, jsonToTsSource, renderImports } from "@prisma-next/ts-render";
|
|
7
9
|
import { Migration } from "@prisma-next/migration-tools/migration";
|
|
8
10
|
import { detectScaffoldRuntime, shebangLineFor } from "@prisma-next/migration-tools/migration-ts";
|
|
9
11
|
import { errorRunnerFailed } from "@prisma-next/errors/execution";
|
|
10
12
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
11
13
|
|
|
12
|
-
//#region src/core/contract-to-schema.ts
|
|
13
|
-
function convertIndex(index) {
|
|
14
|
-
return new MongoSchemaIndex({
|
|
15
|
-
keys: index.keys,
|
|
16
|
-
unique: index.unique,
|
|
17
|
-
sparse: index.sparse,
|
|
18
|
-
expireAfterSeconds: index.expireAfterSeconds,
|
|
19
|
-
partialFilterExpression: index.partialFilterExpression,
|
|
20
|
-
wildcardProjection: index.wildcardProjection,
|
|
21
|
-
collation: index.collation,
|
|
22
|
-
weights: index.weights,
|
|
23
|
-
default_language: index.default_language,
|
|
24
|
-
language_override: index.language_override
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
function convertValidator(v) {
|
|
28
|
-
return new MongoSchemaValidator({
|
|
29
|
-
jsonSchema: v.jsonSchema,
|
|
30
|
-
validationLevel: v.validationLevel,
|
|
31
|
-
validationAction: v.validationAction
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
function convertOptions(o) {
|
|
35
|
-
return new MongoSchemaCollectionOptions(o);
|
|
36
|
-
}
|
|
37
|
-
function convertCollection(name, def) {
|
|
38
|
-
return new MongoSchemaCollection({
|
|
39
|
-
name,
|
|
40
|
-
indexes: (def.indexes ?? []).map(convertIndex),
|
|
41
|
-
...def.validator != null && { validator: convertValidator(def.validator) },
|
|
42
|
-
...def.options != null && { options: convertOptions(def.options) }
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
function contractToMongoSchemaIR(contract) {
|
|
46
|
-
if (!contract) return new MongoSchemaIR([]);
|
|
47
|
-
return new MongoSchemaIR(Object.entries(contract.storage.collections).map(([name, def]) => convertCollection(name, def)));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
//#endregion
|
|
51
14
|
//#region src/core/ddl-formatter.ts
|
|
52
15
|
function formatKeySpec(keys) {
|
|
53
16
|
return `{ ${keys.map((k) => `${JSON.stringify(k.field)}: ${JSON.stringify(k.direction)}`).join(", ")} }`;
|
|
@@ -665,7 +628,14 @@ function serializeMongoOps(ops) {
|
|
|
665
628
|
|
|
666
629
|
//#endregion
|
|
667
630
|
//#region src/core/op-factory-call.ts
|
|
668
|
-
|
|
631
|
+
const TARGET_MIGRATION_MODULE = "@prisma-next/target-mongo/migration";
|
|
632
|
+
var OpFactoryCallNode = class extends TsExpression {
|
|
633
|
+
importRequirements() {
|
|
634
|
+
return [{
|
|
635
|
+
moduleSpecifier: TARGET_MIGRATION_MODULE,
|
|
636
|
+
symbol: this.factoryName
|
|
637
|
+
}];
|
|
638
|
+
}
|
|
669
639
|
freeze() {
|
|
670
640
|
Object.freeze(this);
|
|
671
641
|
}
|
|
@@ -674,7 +644,7 @@ function formatKeys(keys) {
|
|
|
674
644
|
return keys.map((k) => `${k.field}:${k.direction}`).join(", ");
|
|
675
645
|
}
|
|
676
646
|
var CreateIndexCall = class extends OpFactoryCallNode {
|
|
677
|
-
|
|
647
|
+
factoryName = "createIndex";
|
|
678
648
|
operationClass = "additive";
|
|
679
649
|
collection;
|
|
680
650
|
keys;
|
|
@@ -688,12 +658,15 @@ var CreateIndexCall = class extends OpFactoryCallNode {
|
|
|
688
658
|
this.label = `Create index on ${collection} (${formatKeys(keys)})`;
|
|
689
659
|
this.freeze();
|
|
690
660
|
}
|
|
691
|
-
|
|
692
|
-
return
|
|
661
|
+
toOp() {
|
|
662
|
+
return createIndex(this.collection, this.keys, this.options);
|
|
663
|
+
}
|
|
664
|
+
renderTypeScript() {
|
|
665
|
+
return this.options ? `createIndex(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.keys)}, ${jsonToTsSource(this.options)})` : `createIndex(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.keys)})`;
|
|
693
666
|
}
|
|
694
667
|
};
|
|
695
668
|
var DropIndexCall = class extends OpFactoryCallNode {
|
|
696
|
-
|
|
669
|
+
factoryName = "dropIndex";
|
|
697
670
|
operationClass = "destructive";
|
|
698
671
|
collection;
|
|
699
672
|
keys;
|
|
@@ -705,12 +678,15 @@ var DropIndexCall = class extends OpFactoryCallNode {
|
|
|
705
678
|
this.label = `Drop index on ${collection} (${formatKeys(keys)})`;
|
|
706
679
|
this.freeze();
|
|
707
680
|
}
|
|
708
|
-
|
|
709
|
-
return
|
|
681
|
+
toOp() {
|
|
682
|
+
return dropIndex(this.collection, this.keys);
|
|
683
|
+
}
|
|
684
|
+
renderTypeScript() {
|
|
685
|
+
return `dropIndex(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.keys)})`;
|
|
710
686
|
}
|
|
711
687
|
};
|
|
712
688
|
var CreateCollectionCall = class extends OpFactoryCallNode {
|
|
713
|
-
|
|
689
|
+
factoryName = "createCollection";
|
|
714
690
|
operationClass = "additive";
|
|
715
691
|
collection;
|
|
716
692
|
options;
|
|
@@ -722,12 +698,15 @@ var CreateCollectionCall = class extends OpFactoryCallNode {
|
|
|
722
698
|
this.label = `Create collection ${collection}`;
|
|
723
699
|
this.freeze();
|
|
724
700
|
}
|
|
725
|
-
|
|
726
|
-
return
|
|
701
|
+
toOp() {
|
|
702
|
+
return createCollection(this.collection, this.options);
|
|
703
|
+
}
|
|
704
|
+
renderTypeScript() {
|
|
705
|
+
return this.options ? `createCollection(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.options)})` : `createCollection(${jsonToTsSource(this.collection)})`;
|
|
727
706
|
}
|
|
728
707
|
};
|
|
729
708
|
var DropCollectionCall = class extends OpFactoryCallNode {
|
|
730
|
-
|
|
709
|
+
factoryName = "dropCollection";
|
|
731
710
|
operationClass = "destructive";
|
|
732
711
|
collection;
|
|
733
712
|
label;
|
|
@@ -737,12 +716,15 @@ var DropCollectionCall = class extends OpFactoryCallNode {
|
|
|
737
716
|
this.label = `Drop collection ${collection}`;
|
|
738
717
|
this.freeze();
|
|
739
718
|
}
|
|
740
|
-
|
|
741
|
-
return
|
|
719
|
+
toOp() {
|
|
720
|
+
return dropCollection(this.collection);
|
|
721
|
+
}
|
|
722
|
+
renderTypeScript() {
|
|
723
|
+
return `dropCollection(${jsonToTsSource(this.collection)})`;
|
|
742
724
|
}
|
|
743
725
|
};
|
|
744
726
|
var CollModCall = class extends OpFactoryCallNode {
|
|
745
|
-
|
|
727
|
+
factoryName = "collMod";
|
|
746
728
|
collection;
|
|
747
729
|
options;
|
|
748
730
|
meta;
|
|
@@ -757,8 +739,11 @@ var CollModCall = class extends OpFactoryCallNode {
|
|
|
757
739
|
this.label = meta?.label ?? `Modify collection ${collection}`;
|
|
758
740
|
this.freeze();
|
|
759
741
|
}
|
|
760
|
-
|
|
761
|
-
return
|
|
742
|
+
toOp() {
|
|
743
|
+
return collMod(this.collection, this.options, this.meta);
|
|
744
|
+
}
|
|
745
|
+
renderTypeScript() {
|
|
746
|
+
return this.meta ? `collMod(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.options)}, ${jsonToTsSource(this.meta)})` : `collMod(${jsonToTsSource(this.collection)}, ${jsonToTsSource(this.options)})`;
|
|
762
747
|
}
|
|
763
748
|
};
|
|
764
749
|
function schemaIndexToCreateIndexOptions(index) {
|
|
@@ -798,41 +783,55 @@ function schemaCollectionToCreateCollectionOptions(coll) {
|
|
|
798
783
|
|
|
799
784
|
//#endregion
|
|
800
785
|
//#region src/core/render-ops.ts
|
|
801
|
-
const renderVisitor = {
|
|
802
|
-
createIndex(call) {
|
|
803
|
-
return createIndex(call.collection, call.keys, call.options);
|
|
804
|
-
},
|
|
805
|
-
dropIndex(call) {
|
|
806
|
-
return dropIndex(call.collection, call.keys);
|
|
807
|
-
},
|
|
808
|
-
createCollection(call) {
|
|
809
|
-
return createCollection(call.collection, call.options);
|
|
810
|
-
},
|
|
811
|
-
dropCollection(call) {
|
|
812
|
-
return dropCollection(call.collection);
|
|
813
|
-
},
|
|
814
|
-
collMod(call) {
|
|
815
|
-
return collMod(call.collection, call.options, call.meta);
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
786
|
function renderOps(calls) {
|
|
819
|
-
return calls.map((call) => call.
|
|
787
|
+
return calls.map((call) => call.toOp());
|
|
820
788
|
}
|
|
821
789
|
|
|
822
790
|
//#endregion
|
|
823
791
|
//#region src/core/render-typescript.ts
|
|
824
792
|
/**
|
|
825
|
-
*
|
|
793
|
+
* Always-present base imports for the rendered scaffold:
|
|
794
|
+
*
|
|
795
|
+
* - `Migration` from `@prisma-next/family-mongo/migration` — the
|
|
796
|
+
* user-facing Mongo `Migration` base; subclasses don't need to
|
|
797
|
+
* redeclare `targetId` or thread family/target generics.
|
|
798
|
+
* - `MigrationCLI` from `@prisma-next/cli/migration-cli` — the
|
|
799
|
+
* migration-file CLI entrypoint that loads `prisma-next.config.ts`,
|
|
800
|
+
* assembles a `ControlStack`, and instantiates the migration class.
|
|
801
|
+
* The migration file owns this dependency directly: pulling CLI
|
|
802
|
+
* machinery in at script run time is acceptable because the script's
|
|
803
|
+
* whole purpose is to be invoked from the project that owns the
|
|
804
|
+
* config. (Mirrors the postgres facade pattern; pulling `MigrationCLI`
|
|
805
|
+
* into `@prisma-next/family-mongo/migration` so a Mongo migration only
|
|
806
|
+
* needs one import is tracked separately as a follow-up.)
|
|
807
|
+
*/
|
|
808
|
+
const BASE_IMPORTS = [{
|
|
809
|
+
moduleSpecifier: "@prisma-next/family-mongo/migration",
|
|
810
|
+
symbol: "Migration"
|
|
811
|
+
}, {
|
|
812
|
+
moduleSpecifier: "@prisma-next/cli/migration-cli",
|
|
813
|
+
symbol: "MigrationCLI"
|
|
814
|
+
}];
|
|
815
|
+
/**
|
|
816
|
+
* Render a list of Mongo `OpFactoryCall`s as a `migration.ts`
|
|
826
817
|
* source string. The result is shebanged, extends the user-facing
|
|
827
818
|
* `Migration` (i.e. `MongoMigration`) from `@prisma-next/family-mongo`, and
|
|
828
819
|
* implements the abstract `operations` and `describe` members. `meta` is
|
|
829
820
|
* always rendered — `describe()` is part of the `Migration` contract, so
|
|
830
821
|
* even an empty stub must satisfy it; callers pass empty strings for a
|
|
831
822
|
* migration-new scaffold.
|
|
823
|
+
*
|
|
824
|
+
* The walk is polymorphic: each call node contributes its own
|
|
825
|
+
* `renderTypeScript()` expression and declares its own
|
|
826
|
+
* `importRequirements()`. The top-level renderer aggregates imports
|
|
827
|
+
* across all nodes and emits one `import { … } from "…"` line per module.
|
|
828
|
+
* The `Migration` and `MigrationCLI` imports are always emitted — they're
|
|
829
|
+
* structural to the rendered scaffold (extends `Migration`, calls
|
|
830
|
+
* `MigrationCLI.run`), not driven by any node.
|
|
832
831
|
*/
|
|
833
832
|
function renderCallsToTypeScript(calls, meta) {
|
|
834
|
-
const imports = buildImports(
|
|
835
|
-
const operationsBody = calls.map((c) => c.
|
|
833
|
+
const imports = buildImports(calls);
|
|
834
|
+
const operationsBody = calls.map((c) => c.renderTypeScript()).join(",\n");
|
|
836
835
|
return [
|
|
837
836
|
shebangLineFor(detectScaffoldRuntime()),
|
|
838
837
|
imports,
|
|
@@ -847,19 +846,14 @@ function renderCallsToTypeScript(calls, meta) {
|
|
|
847
846
|
"}",
|
|
848
847
|
"",
|
|
849
848
|
"export default M;",
|
|
850
|
-
"
|
|
849
|
+
"MigrationCLI.run(import.meta.url, M);",
|
|
851
850
|
""
|
|
852
851
|
].join("\n");
|
|
853
852
|
}
|
|
854
|
-
function
|
|
855
|
-
const
|
|
856
|
-
for (const call of calls)
|
|
857
|
-
return
|
|
858
|
-
}
|
|
859
|
-
function buildImports(factoryNames) {
|
|
860
|
-
const lines = ["import { Migration } from '@prisma-next/family-mongo/migration';"];
|
|
861
|
-
if (factoryNames.length > 0) lines.push(`import { ${factoryNames.join(", ")} } from '@prisma-next/target-mongo/migration';`);
|
|
862
|
-
return lines.join("\n");
|
|
853
|
+
function buildImports(calls) {
|
|
854
|
+
const requirements = [...BASE_IMPORTS];
|
|
855
|
+
for (const call of calls) for (const req of call.importRequirements()) requirements.push(req);
|
|
856
|
+
return renderImports(requirements);
|
|
863
857
|
}
|
|
864
858
|
function buildDescribeMethod(meta) {
|
|
865
859
|
const lines = [];
|
|
@@ -868,55 +862,12 @@ function buildDescribeMethod(meta) {
|
|
|
868
862
|
lines.push(` from: ${JSON.stringify(meta.from)},`);
|
|
869
863
|
lines.push(` to: ${JSON.stringify(meta.to)},`);
|
|
870
864
|
if (meta.kind) lines.push(` kind: ${JSON.stringify(meta.kind)},`);
|
|
871
|
-
if (meta.labels && meta.labels.length > 0) lines.push(` labels: ${
|
|
865
|
+
if (meta.labels && meta.labels.length > 0) lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
|
|
872
866
|
lines.push(" };");
|
|
873
867
|
lines.push(" }");
|
|
874
868
|
lines.push("");
|
|
875
869
|
return lines.join("\n");
|
|
876
870
|
}
|
|
877
|
-
const renderCallVisitor = {
|
|
878
|
-
createIndex(call) {
|
|
879
|
-
return call.options ? `createIndex(${renderLiteral(call.collection)}, ${renderLiteral(call.keys)}, ${renderLiteral(call.options)})` : `createIndex(${renderLiteral(call.collection)}, ${renderLiteral(call.keys)})`;
|
|
880
|
-
},
|
|
881
|
-
dropIndex(call) {
|
|
882
|
-
return `dropIndex(${renderLiteral(call.collection)}, ${renderLiteral(call.keys)})`;
|
|
883
|
-
},
|
|
884
|
-
createCollection(call) {
|
|
885
|
-
return call.options ? `createCollection(${renderLiteral(call.collection)}, ${renderLiteral(call.options)})` : `createCollection(${renderLiteral(call.collection)})`;
|
|
886
|
-
},
|
|
887
|
-
dropCollection(call) {
|
|
888
|
-
return `dropCollection(${renderLiteral(call.collection)})`;
|
|
889
|
-
},
|
|
890
|
-
collMod(call) {
|
|
891
|
-
return call.meta ? `collMod(${renderLiteral(call.collection)}, ${renderLiteral(call.options)}, ${renderLiteral(call.meta)})` : `collMod(${renderLiteral(call.collection)}, ${renderLiteral(call.options)})`;
|
|
892
|
-
}
|
|
893
|
-
};
|
|
894
|
-
function renderLiteral(value) {
|
|
895
|
-
if (value === void 0) return "undefined";
|
|
896
|
-
if (value === null) return "null";
|
|
897
|
-
if (typeof value === "string") return JSON.stringify(value);
|
|
898
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
899
|
-
if (Array.isArray(value)) {
|
|
900
|
-
if (value.length === 0) return "[]";
|
|
901
|
-
const items = value.map((v) => renderLiteral(v));
|
|
902
|
-
const singleLine = `[${items.join(", ")}]`;
|
|
903
|
-
if (singleLine.length <= 80) return singleLine;
|
|
904
|
-
return `[\n${items.map((i) => ` ${i}`).join(",\n")},\n]`;
|
|
905
|
-
}
|
|
906
|
-
if (typeof value === "object") {
|
|
907
|
-
const entries = Object.entries(value).filter(([, v]) => v !== void 0);
|
|
908
|
-
if (entries.length === 0) return "{}";
|
|
909
|
-
const items = entries.map(([k, v]) => `${renderKey(k)}: ${renderLiteral(v)}`);
|
|
910
|
-
const singleLine = `{ ${items.join(", ")} }`;
|
|
911
|
-
if (singleLine.length <= 80) return singleLine;
|
|
912
|
-
return `{\n${items.map((i) => ` ${i}`).join(",\n")},\n}`;
|
|
913
|
-
}
|
|
914
|
-
return String(value);
|
|
915
|
-
}
|
|
916
|
-
function renderKey(key) {
|
|
917
|
-
if (key === "__proto__") return JSON.stringify(key);
|
|
918
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
919
|
-
}
|
|
920
871
|
function indent(text, spaces) {
|
|
921
872
|
const pad = " ".repeat(spaces);
|
|
922
873
|
return text.split("\n").map((line) => line.trim() ? `${pad}${line}` : line).join("\n");
|
|
@@ -1087,12 +1038,11 @@ var MongoMigrationPlanner = class {
|
|
|
1087
1038
|
/**
|
|
1088
1039
|
* Produce an empty `migration.ts` authoring surface for `migration new`.
|
|
1089
1040
|
*
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
* contract `.d.ts`.
|
|
1041
|
+
* The "empty migration" is a `PlannerProducedMongoMigration` with no
|
|
1042
|
+
* operations; `renderTypeScript()` emits a stub class with the correct
|
|
1043
|
+
* `from`/`to` metadata that the user then fills in with operations. The
|
|
1044
|
+
* contract path on the context is unused — Mongo's emitted source does
|
|
1045
|
+
* not import from the generated contract `.d.ts`.
|
|
1096
1046
|
*/
|
|
1097
1047
|
emptyMigration(context) {
|
|
1098
1048
|
return new PlannerProducedMongoMigration([], {
|
|
@@ -1140,9 +1090,6 @@ function planMutableOptionsDiffCall(collName, origin, dest) {
|
|
|
1140
1090
|
//#endregion
|
|
1141
1091
|
//#region src/core/mongo-runner.ts
|
|
1142
1092
|
const READ_ONLY_CHECK_COMMAND_KINDS = new Set(["aggregate", "rawAggregate"]);
|
|
1143
|
-
function hasProfileHash(value) {
|
|
1144
|
-
return typeof value === "object" && value !== null && Object.hasOwn(value, "profileHash") && typeof value.profileHash === "string";
|
|
1145
|
-
}
|
|
1146
1093
|
function runnerFailure(code, summary, opts) {
|
|
1147
1094
|
return notOk({
|
|
1148
1095
|
code,
|
|
@@ -1194,11 +1141,23 @@ var MongoMigrationRunner = class {
|
|
|
1194
1141
|
}
|
|
1195
1142
|
}
|
|
1196
1143
|
const destination = options.plan.destination;
|
|
1197
|
-
const profileHash =
|
|
1144
|
+
const profileHash = options.destinationContract.profileHash ?? destination.storageHash;
|
|
1198
1145
|
if (operationsExecuted === 0 && existingMarker?.storageHash === destination.storageHash && existingMarker.profileHash === profileHash) return ok({
|
|
1199
1146
|
operationsPlanned: operations.length,
|
|
1200
1147
|
operationsExecuted
|
|
1201
1148
|
});
|
|
1149
|
+
const liveSchema = await this.deps.introspectSchema();
|
|
1150
|
+
const verifyResult = verifyMongoSchema({
|
|
1151
|
+
contract: options.destinationContract,
|
|
1152
|
+
schema: liveSchema,
|
|
1153
|
+
strict: options.strictVerification ?? true,
|
|
1154
|
+
frameworkComponents: options.frameworkComponents,
|
|
1155
|
+
...options.context ? { context: options.context } : {}
|
|
1156
|
+
});
|
|
1157
|
+
if (!verifyResult.ok) return runnerFailure("SCHEMA_VERIFY_FAILED", verifyResult.summary, {
|
|
1158
|
+
why: "The resulting database schema does not satisfy the destination contract.",
|
|
1159
|
+
meta: { issues: verifyResult.schema.issues }
|
|
1160
|
+
});
|
|
1202
1161
|
if (existingMarker) {
|
|
1203
1162
|
if (!await markerOps.updateMarker(existingMarker.storageHash, {
|
|
1204
1163
|
storageHash: destination.storageHash,
|