@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 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
- Migration.run(import.meta.url, UsersMigration)
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.
@@ -1,10 +1,10 @@
1
- import { a as DropCollectionCall, c as OpFactoryCallVisitor, i as CreateIndexCall, l as schemaCollectionToCreateCollectionOptions, n as CollModMeta, o as DropIndexCall, r as CreateCollectionCall, s as OpFactoryCall, t as CollModCall, u as schemaIndexToCreateIndexOptions } from "./op-factory-call-CfPGebEH.mjs";
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
- * Mongo is a class-flow target, so the "empty migration" is a
78
- * `PlannerProducedMongoMigration` with no operations; `renderTypeScript()`
79
- * emits a stub class with the correct `from`/`to` metadata that the user
80
- * then fills in with operations. The contract path on the context is
81
- * unused — Mongo's emitted source does not import from the generated
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 class-flow `migration.ts`
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 OpFactoryCallVisitor, type PlanCallsResult, PlannerProducedMongoMigration, type RenderMigrationMeta, contractToMongoSchemaIR, deserializeMongoOp, deserializeMongoOps, formatMongoOperations, initMarker, readMarker, renderCallsToTypeScript, renderOps, schemaCollectionToCreateCollectionOptions, schemaIndexToCreateIndexOptions, serializeMongoOps, updateMarker, writeLedgerEntry };
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
@@ -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;;;;;;;;;;0BGkMY,2BAA2B;AF7NrD;;;UGMiB,gBAAA;gBACD,QAAQ;;;;MAIlB;;;INUU,SAAA,WAAA,EAAuB,MAAA;MMNlC;;;ILmDW,SAAA,IAAA,EAAA,MAAqB;;MK9C/B;;AJDO,UIII,uBAAA,CJJY;EAGV,SAAA,eAAA,EIES,sBJFT,CIEgC,OJFhC,CAAA,IAAA,CAAA,CAAA;EAAsB,SAAA,kBAAA,EIGV,6BJHU,CIGoB,OJHpB,CIG4B,MJH5B,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,CAAA,CAAA;EAK3B,SAAA,OAAA,EIDM,YJCN;EAKF,SAAA,MAAA,EILO,WJKP;EAID,SAAA,SAAA,EIRW,gBJQX;;AAQI,cIDF,oBAAA,CJCE;EAKD,iBAAA,IAAA;EA9B0B,WAAA,CAAA,IAAA,EIyBH,uBJzBG;EAAkB,OAAA,CAAA,OAAA,EAAA;mBI4BvC;;qBAEE;IHjDC,SAAU,SAAA,CAAA,EAAA;MAAK,gBAAA,EAAA,EAAA,EGmDT,sBHnDS,CAAA,EAAA,IAAA;MAAa,mBAAA,EAAA,EAAA,EGoDnB,sBHpDmB,CAAA,EAAA,IAAA;IAAR,CAAA;IAAO,SAAA,eAAA,CAAA,EGsDlB,8BHtDkB;IAgB3B,SAAU,mBAG7B,EGoC+B,aHpCxB,CGoCsC,8BHpCtC,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA;EAcY,CAAA,CAAA,EGuBhB,OHvBgB,CGuBR,qBHnBX,CAAA;EAiBmB,QAAA,oBAAgB;;;;ECiftB,QAAA,0BAAmC;EAOnC,QAAA,yBAAmB;AAInC;;;;;;;;;;;;AJ7hBA;;;;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;;;;iBMnCI,SAAA,QAAiB,cAAc,iBAAiB;;;UCzB/C,mBAAA;;;;;;;;;;;;ATyCjB;;;iBSzBgB,uBAAA,QACP,cAAc,sBACf"}
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":"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"}
package/dist/control.mjs CHANGED
@@ -1,53 +1,16 @@
1
- import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-gwi81C8u.mjs";
2
- import { MongoSchemaCollection, MongoSchemaCollectionOptions, MongoSchemaIR, MongoSchemaIndex, MongoSchemaValidator, canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
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
- var OpFactoryCallNode = class {
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
- factory = "createIndex";
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
- accept(visitor) {
692
- return visitor.createIndex(this);
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
- factory = "dropIndex";
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
- accept(visitor) {
709
- return visitor.dropIndex(this);
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
- factory = "createCollection";
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
- accept(visitor) {
726
- return visitor.createCollection(this);
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
- factory = "dropCollection";
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
- accept(visitor) {
741
- return visitor.dropCollection(this);
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
- factory = "collMod";
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
- accept(visitor) {
761
- return visitor.collMod(this);
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.accept(renderVisitor));
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
- * Render a list of Mongo `OpFactoryCall`s as a class-flow `migration.ts`
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(collectFactoryNames(calls));
835
- const operationsBody = calls.map((c) => c.accept(renderCallVisitor)).join(",\n");
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
- "Migration.run(import.meta.url, M);",
849
+ "MigrationCLI.run(import.meta.url, M);",
851
850
  ""
852
851
  ].join("\n");
853
852
  }
854
- function collectFactoryNames(calls) {
855
- const names = /* @__PURE__ */ new Set();
856
- for (const call of calls) names.add(call.factory);
857
- return [...names].sort();
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: ${renderLiteral(meta.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
- * Mongo is a class-flow target, so the "empty migration" is a
1091
- * `PlannerProducedMongoMigration` with no operations; `renderTypeScript()`
1092
- * emits a stub class with the correct `from`/`to` metadata that the user
1093
- * then fills in with operations. The contract path on the context is
1094
- * unused — Mongo's emitted source does not import from the generated
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 = hasProfileHash(options.destinationContract) ? options.destinationContract.profileHash : destination.storageHash;
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,