@prisma-next/target-mongo 0.4.0-dev.7 → 0.4.0-dev.9
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 +9 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +289 -12
- package/dist/control.mjs.map +1 -1
- package/dist/{migration-factories-Brzz-QGG.mjs → migration-factories-gwi81C8u.mjs} +43 -3
- package/dist/migration-factories-gwi81C8u.mjs.map +1 -0
- package/dist/migration.d.mts +15 -2
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/pack.d.mts +7 -10
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +2 -1
- package/dist/pack.mjs.map +1 -1
- package/package.json +13 -12
- package/src/core/codec-types.ts +12 -0
- package/src/core/descriptor-meta.ts +7 -1
- package/src/core/migration-factories.ts +69 -1
- package/src/core/mongo-ops-serializer.ts +324 -5
- package/src/core/mongo-runner.ts +144 -8
- package/src/exports/migration.ts +1 -0
- package/src/exports/pack.ts +10 -6
- package/dist/migration-factories-Brzz-QGG.mjs.map +0 -1
package/dist/control.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
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";
|
|
2
2
|
import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
|
|
3
|
+
import { MongoQueryPlan } from "@prisma-next/mongo-query-ast/execution";
|
|
3
4
|
import { AnyMongoMigrationOperation, MongoAndExpr, MongoDdlCommandVisitor, MongoExistsExpr, MongoExprFilter, MongoFieldFilter, MongoFilterExpr, MongoFilterVisitor, MongoInspectionCommandVisitor, MongoMigrationPlanOperation, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
|
|
4
5
|
import { Migration, MigrationMeta } from "@prisma-next/migration-tools/migration";
|
|
5
6
|
import { MongoContract } from "@prisma-next/mongo-contract";
|
|
@@ -7,6 +8,7 @@ import { MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, Migrat
|
|
|
7
8
|
import { ContractMarkerRecord } from "@prisma-next/contract/types";
|
|
8
9
|
import { Db } from "mongodb";
|
|
9
10
|
import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
|
|
11
|
+
import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
|
|
10
12
|
|
|
11
13
|
//#region src/core/contract-to-schema.d.ts
|
|
12
14
|
declare function contractToMongoSchemaIR(contract: MongoContract | null): MongoSchemaIR;
|
|
@@ -43,9 +45,9 @@ declare function writeLedgerEntry(db: Db, entry: {
|
|
|
43
45
|
}): Promise<void>;
|
|
44
46
|
//#endregion
|
|
45
47
|
//#region src/core/mongo-ops-serializer.d.ts
|
|
46
|
-
declare function deserializeMongoOp(json: unknown):
|
|
47
|
-
declare function deserializeMongoOps(json: readonly unknown[]):
|
|
48
|
-
declare function serializeMongoOps(ops: readonly
|
|
48
|
+
declare function deserializeMongoOp(json: unknown): AnyMongoMigrationOperation;
|
|
49
|
+
declare function deserializeMongoOps(json: readonly unknown[]): AnyMongoMigrationOperation[];
|
|
50
|
+
declare function serializeMongoOps(ops: readonly AnyMongoMigrationOperation[]): string;
|
|
49
51
|
//#endregion
|
|
50
52
|
//#region src/core/mongo-planner.d.ts
|
|
51
53
|
type PlanCallsResult = {
|
|
@@ -102,6 +104,8 @@ interface MarkerOperations {
|
|
|
102
104
|
interface MongoRunnerDependencies {
|
|
103
105
|
readonly commandExecutor: MongoDdlCommandVisitor<Promise<void>>;
|
|
104
106
|
readonly inspectionExecutor: MongoInspectionCommandVisitor<Promise<Record<string, unknown>[]>>;
|
|
107
|
+
readonly adapter: MongoAdapter;
|
|
108
|
+
readonly driver: MongoDriver;
|
|
105
109
|
readonly markerOps: MarkerOperations;
|
|
106
110
|
}
|
|
107
111
|
declare class MongoMigrationRunner {
|
|
@@ -118,6 +122,8 @@ declare class MongoMigrationRunner {
|
|
|
118
122
|
readonly executionChecks?: MigrationRunnerExecutionChecks;
|
|
119
123
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'mongo', 'mongo'>>;
|
|
120
124
|
}): Promise<MigrationRunnerResult>;
|
|
125
|
+
private executeDataTransform;
|
|
126
|
+
private evaluateDataTransformChecks;
|
|
121
127
|
private evaluateChecks;
|
|
122
128
|
private allChecksSatisfied;
|
|
123
129
|
private enforcePolicyCompatibility;
|
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":"
|
|
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"}
|
package/dist/control.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as dropCollection, n as createCollection, o as dropIndex, r as createIndex, t as collMod } from "./migration-factories-gwi81C8u.mjs";
|
|
2
2
|
import { MongoSchemaCollection, MongoSchemaCollectionOptions, MongoSchemaIR, MongoSchemaIndex, MongoSchemaValidator, canonicalize, deepEqual } from "@prisma-next/mongo-schema-ir";
|
|
3
|
-
import { RawAggregateCommand, RawFindOneAndUpdateCommand, RawInsertOneCommand } from "@prisma-next/mongo-query-ast/execution";
|
|
3
|
+
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
4
|
import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr } from "@prisma-next/mongo-query-ast/control";
|
|
5
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
6
|
import { type } from "arktype";
|
|
6
7
|
import { Migration } from "@prisma-next/migration-tools/migration";
|
|
7
|
-
import { ifDefined } from "@prisma-next/utils/defined";
|
|
8
8
|
import { detectScaffoldRuntime, shebangLineFor } from "@prisma-next/migration-tools/migration-ts";
|
|
9
|
+
import { errorRunnerFailed } from "@prisma-next/errors/execution";
|
|
9
10
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
11
|
|
|
11
12
|
//#region src/core/contract-to-schema.ts
|
|
@@ -295,6 +296,76 @@ const ExistsFilterJson = type({
|
|
|
295
296
|
field: "string",
|
|
296
297
|
exists: "boolean"
|
|
297
298
|
});
|
|
299
|
+
const RawInsertOneJson = type({
|
|
300
|
+
kind: "\"rawInsertOne\"",
|
|
301
|
+
collection: "string",
|
|
302
|
+
document: "Record<string, unknown>"
|
|
303
|
+
});
|
|
304
|
+
const RawInsertManyJson = type({
|
|
305
|
+
kind: "\"rawInsertMany\"",
|
|
306
|
+
collection: "string",
|
|
307
|
+
documents: "Record<string, unknown>[]"
|
|
308
|
+
});
|
|
309
|
+
const RawUpdateOneJson = type({
|
|
310
|
+
kind: "\"rawUpdateOne\"",
|
|
311
|
+
collection: "string",
|
|
312
|
+
filter: "Record<string, unknown>",
|
|
313
|
+
update: "Record<string, unknown> | Record<string, unknown>[]"
|
|
314
|
+
});
|
|
315
|
+
const RawUpdateManyJson = type({
|
|
316
|
+
kind: "\"rawUpdateMany\"",
|
|
317
|
+
collection: "string",
|
|
318
|
+
filter: "Record<string, unknown>",
|
|
319
|
+
update: "Record<string, unknown> | Record<string, unknown>[]"
|
|
320
|
+
});
|
|
321
|
+
const RawDeleteOneJson = type({
|
|
322
|
+
kind: "\"rawDeleteOne\"",
|
|
323
|
+
collection: "string",
|
|
324
|
+
filter: "Record<string, unknown>"
|
|
325
|
+
});
|
|
326
|
+
const RawDeleteManyJson = type({
|
|
327
|
+
kind: "\"rawDeleteMany\"",
|
|
328
|
+
collection: "string",
|
|
329
|
+
filter: "Record<string, unknown>"
|
|
330
|
+
});
|
|
331
|
+
const RawAggregateJson = type({
|
|
332
|
+
kind: "\"rawAggregate\"",
|
|
333
|
+
collection: "string",
|
|
334
|
+
pipeline: "Record<string, unknown>[]"
|
|
335
|
+
});
|
|
336
|
+
const RawFindOneAndUpdateJson = type({
|
|
337
|
+
kind: "\"rawFindOneAndUpdate\"",
|
|
338
|
+
collection: "string",
|
|
339
|
+
filter: "Record<string, unknown>",
|
|
340
|
+
update: "Record<string, unknown> | Record<string, unknown>[]",
|
|
341
|
+
upsert: "boolean"
|
|
342
|
+
});
|
|
343
|
+
const RawFindOneAndDeleteJson = type({
|
|
344
|
+
kind: "\"rawFindOneAndDelete\"",
|
|
345
|
+
collection: "string",
|
|
346
|
+
filter: "Record<string, unknown>"
|
|
347
|
+
});
|
|
348
|
+
const TypedAggregateJson = type({
|
|
349
|
+
kind: "\"aggregate\"",
|
|
350
|
+
collection: "string",
|
|
351
|
+
pipeline: "Record<string, unknown>[]"
|
|
352
|
+
});
|
|
353
|
+
const QueryPlanJson = type({
|
|
354
|
+
collection: "string",
|
|
355
|
+
command: "Record<string, unknown>",
|
|
356
|
+
meta: type({
|
|
357
|
+
target: "string",
|
|
358
|
+
storageHash: "string",
|
|
359
|
+
lane: "string",
|
|
360
|
+
paramDescriptors: "unknown[]",
|
|
361
|
+
"targetFamily?": "string",
|
|
362
|
+
"profileHash?": "string",
|
|
363
|
+
"annotations?": "Record<string, unknown>",
|
|
364
|
+
"refs?": "Record<string, unknown>",
|
|
365
|
+
"projection?": "Record<string, string> | string[]",
|
|
366
|
+
"projectionTypes?": "Record<string, string>"
|
|
367
|
+
})
|
|
368
|
+
});
|
|
298
369
|
const CheckJson = type({
|
|
299
370
|
description: "string",
|
|
300
371
|
source: "Record<string, unknown>",
|
|
@@ -305,7 +376,7 @@ const StepJson = type({
|
|
|
305
376
|
description: "string",
|
|
306
377
|
command: "Record<string, unknown>"
|
|
307
378
|
});
|
|
308
|
-
const
|
|
379
|
+
const DdlOperationJson = type({
|
|
309
380
|
id: "string",
|
|
310
381
|
label: "string",
|
|
311
382
|
operationClass: "\"additive\" | \"widening\" | \"destructive\"",
|
|
@@ -313,6 +384,21 @@ const OperationJson = type({
|
|
|
313
384
|
execute: "Record<string, unknown>[]",
|
|
314
385
|
postcheck: "Record<string, unknown>[]"
|
|
315
386
|
});
|
|
387
|
+
const DataTransformCheckJson = type({
|
|
388
|
+
description: "string",
|
|
389
|
+
source: "Record<string, unknown>",
|
|
390
|
+
filter: "Record<string, unknown>",
|
|
391
|
+
expect: "\"exists\" | \"notExists\""
|
|
392
|
+
});
|
|
393
|
+
const DataTransformOperationJson = type({
|
|
394
|
+
id: "string",
|
|
395
|
+
label: "string",
|
|
396
|
+
operationClass: "\"data\"",
|
|
397
|
+
name: "string",
|
|
398
|
+
precheck: "Record<string, unknown>[]",
|
|
399
|
+
run: "Record<string, unknown>[]",
|
|
400
|
+
postcheck: "Record<string, unknown>[]"
|
|
401
|
+
});
|
|
316
402
|
function validate(schema, data, context) {
|
|
317
403
|
try {
|
|
318
404
|
return schema.assert(data);
|
|
@@ -353,6 +439,108 @@ function deserializeFilterExpr(json) {
|
|
|
353
439
|
default: throw new Error(`Unknown filter expression kind: ${kind}`);
|
|
354
440
|
}
|
|
355
441
|
}
|
|
442
|
+
function deserializePipelineStage(json) {
|
|
443
|
+
const record = json;
|
|
444
|
+
const kind = record["kind"];
|
|
445
|
+
switch (kind) {
|
|
446
|
+
case "match": return new MongoMatchStage(deserializeFilterExpr(record["filter"]));
|
|
447
|
+
case "limit": return new MongoLimitStage(record["limit"]);
|
|
448
|
+
case "sort": return new MongoSortStage(record["sort"]);
|
|
449
|
+
case "project": return new MongoProjectStage(record["projection"]);
|
|
450
|
+
case "addFields": return new MongoAddFieldsStage(record["fields"]);
|
|
451
|
+
case "lookup": {
|
|
452
|
+
const opts = {
|
|
453
|
+
from: record["from"],
|
|
454
|
+
as: record["as"]
|
|
455
|
+
};
|
|
456
|
+
if (record["localField"] !== void 0) opts.localField = record["localField"];
|
|
457
|
+
if (record["foreignField"] !== void 0) opts.foreignField = record["foreignField"];
|
|
458
|
+
if (record["pipeline"] !== void 0) opts.pipeline = record["pipeline"].map(deserializePipelineStage);
|
|
459
|
+
if (record["let_"] !== void 0) opts.let_ = record["let_"];
|
|
460
|
+
return new MongoLookupStage(opts);
|
|
461
|
+
}
|
|
462
|
+
case "merge": {
|
|
463
|
+
const opts = { into: record["into"] };
|
|
464
|
+
if (record["on"] !== void 0) opts.on = record["on"];
|
|
465
|
+
if (record["whenMatched"] !== void 0) {
|
|
466
|
+
const wm = record["whenMatched"];
|
|
467
|
+
opts.whenMatched = typeof wm === "string" ? wm : wm.map(deserializePipelineStage);
|
|
468
|
+
}
|
|
469
|
+
if (record["whenNotMatched"] !== void 0) opts.whenNotMatched = record["whenNotMatched"];
|
|
470
|
+
return new MongoMergeStage(opts);
|
|
471
|
+
}
|
|
472
|
+
default: throw new Error(`Unknown pipeline stage kind: ${kind}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function deserializeDmlCommand(json) {
|
|
476
|
+
const kind = json["kind"];
|
|
477
|
+
switch (kind) {
|
|
478
|
+
case "rawInsertOne": {
|
|
479
|
+
const data = validate(RawInsertOneJson, json, "rawInsertOne command");
|
|
480
|
+
return new RawInsertOneCommand(data.collection, data.document);
|
|
481
|
+
}
|
|
482
|
+
case "rawInsertMany": {
|
|
483
|
+
const data = validate(RawInsertManyJson, json, "rawInsertMany command");
|
|
484
|
+
return new RawInsertManyCommand(data.collection, data.documents);
|
|
485
|
+
}
|
|
486
|
+
case "rawUpdateOne": {
|
|
487
|
+
const data = validate(RawUpdateOneJson, json, "rawUpdateOne command");
|
|
488
|
+
return new RawUpdateOneCommand(data.collection, data.filter, data.update);
|
|
489
|
+
}
|
|
490
|
+
case "rawUpdateMany": {
|
|
491
|
+
const data = validate(RawUpdateManyJson, json, "rawUpdateMany command");
|
|
492
|
+
return new RawUpdateManyCommand(data.collection, data.filter, data.update);
|
|
493
|
+
}
|
|
494
|
+
case "rawDeleteOne": {
|
|
495
|
+
const data = validate(RawDeleteOneJson, json, "rawDeleteOne command");
|
|
496
|
+
return new RawDeleteOneCommand(data.collection, data.filter);
|
|
497
|
+
}
|
|
498
|
+
case "rawDeleteMany": {
|
|
499
|
+
const data = validate(RawDeleteManyJson, json, "rawDeleteMany command");
|
|
500
|
+
return new RawDeleteManyCommand(data.collection, data.filter);
|
|
501
|
+
}
|
|
502
|
+
case "rawAggregate": {
|
|
503
|
+
const data = validate(RawAggregateJson, json, "rawAggregate command");
|
|
504
|
+
return new RawAggregateCommand(data.collection, data.pipeline);
|
|
505
|
+
}
|
|
506
|
+
case "rawFindOneAndUpdate": {
|
|
507
|
+
const data = validate(RawFindOneAndUpdateJson, json, "rawFindOneAndUpdate command");
|
|
508
|
+
return new RawFindOneAndUpdateCommand(data.collection, data.filter, data.update, data.upsert);
|
|
509
|
+
}
|
|
510
|
+
case "rawFindOneAndDelete": {
|
|
511
|
+
const data = validate(RawFindOneAndDeleteJson, json, "rawFindOneAndDelete command");
|
|
512
|
+
return new RawFindOneAndDeleteCommand(data.collection, data.filter);
|
|
513
|
+
}
|
|
514
|
+
case "aggregate": {
|
|
515
|
+
const data = validate(TypedAggregateJson, json, "aggregate command");
|
|
516
|
+
const pipeline = data.pipeline.map(deserializePipelineStage);
|
|
517
|
+
return new AggregateCommand(data.collection, pipeline);
|
|
518
|
+
}
|
|
519
|
+
default: throw new Error(`Unknown DML command kind: ${kind}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function deserializeMongoQueryPlan(json) {
|
|
523
|
+
const data = validate(QueryPlanJson, json, "Mongo query plan");
|
|
524
|
+
const command = deserializeDmlCommand(data.command);
|
|
525
|
+
const m = data.meta;
|
|
526
|
+
const meta = {
|
|
527
|
+
target: m.target,
|
|
528
|
+
storageHash: m.storageHash,
|
|
529
|
+
lane: m.lane,
|
|
530
|
+
paramDescriptors: m.paramDescriptors,
|
|
531
|
+
...ifDefined("targetFamily", m.targetFamily),
|
|
532
|
+
...ifDefined("profileHash", m.profileHash),
|
|
533
|
+
...ifDefined("annotations", m.annotations),
|
|
534
|
+
...ifDefined("refs", m.refs),
|
|
535
|
+
...ifDefined("projection", m.projection),
|
|
536
|
+
...ifDefined("projectionTypes", m.projectionTypes)
|
|
537
|
+
};
|
|
538
|
+
return {
|
|
539
|
+
collection: data.collection,
|
|
540
|
+
command,
|
|
541
|
+
meta
|
|
542
|
+
};
|
|
543
|
+
}
|
|
356
544
|
function deserializeDdlCommand(json) {
|
|
357
545
|
const kind = json["kind"];
|
|
358
546
|
switch (kind) {
|
|
@@ -429,8 +617,11 @@ function deserializeStep(json) {
|
|
|
429
617
|
command: deserializeDdlCommand(data.command)
|
|
430
618
|
};
|
|
431
619
|
}
|
|
432
|
-
function
|
|
433
|
-
|
|
620
|
+
function isDataTransformJson(json) {
|
|
621
|
+
return typeof json === "object" && json !== null && json["operationClass"] === "data";
|
|
622
|
+
}
|
|
623
|
+
function deserializeDdlOp(json) {
|
|
624
|
+
const data = validate(DdlOperationJson, json, "migration operation");
|
|
434
625
|
return {
|
|
435
626
|
id: data.id,
|
|
436
627
|
label: data.label,
|
|
@@ -440,6 +631,31 @@ function deserializeMongoOp(json) {
|
|
|
440
631
|
postcheck: data.postcheck.map(deserializeCheck)
|
|
441
632
|
};
|
|
442
633
|
}
|
|
634
|
+
function deserializeDataTransformCheck(json) {
|
|
635
|
+
const data = validate(DataTransformCheckJson, json, "data transform check");
|
|
636
|
+
return {
|
|
637
|
+
description: data.description,
|
|
638
|
+
source: deserializeMongoQueryPlan(data.source),
|
|
639
|
+
filter: deserializeFilterExpr(data.filter),
|
|
640
|
+
expect: data.expect
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function deserializeDataTransformOp(json) {
|
|
644
|
+
const data = validate(DataTransformOperationJson, json, "data transform operation");
|
|
645
|
+
return {
|
|
646
|
+
id: data.id,
|
|
647
|
+
label: data.label,
|
|
648
|
+
operationClass: "data",
|
|
649
|
+
name: data.name,
|
|
650
|
+
precheck: data.precheck.map(deserializeDataTransformCheck),
|
|
651
|
+
run: data.run.map(deserializeMongoQueryPlan),
|
|
652
|
+
postcheck: data.postcheck.map(deserializeDataTransformCheck)
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
function deserializeMongoOp(json) {
|
|
656
|
+
if (isDataTransformJson(json)) return deserializeDataTransformOp(json);
|
|
657
|
+
return deserializeDdlOp(json);
|
|
658
|
+
}
|
|
443
659
|
function deserializeMongoOps(json) {
|
|
444
660
|
return json.map(deserializeMongoOp);
|
|
445
661
|
}
|
|
@@ -923,6 +1139,10 @@ function planMutableOptionsDiffCall(collName, origin, dest) {
|
|
|
923
1139
|
|
|
924
1140
|
//#endregion
|
|
925
1141
|
//#region src/core/mongo-runner.ts
|
|
1142
|
+
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
|
+
}
|
|
926
1146
|
function runnerFailure(code, summary, opts) {
|
|
927
1147
|
return notOk({
|
|
928
1148
|
code,
|
|
@@ -935,7 +1155,7 @@ var MongoMigrationRunner = class {
|
|
|
935
1155
|
this.deps = deps;
|
|
936
1156
|
}
|
|
937
1157
|
async execute(options) {
|
|
938
|
-
const { commandExecutor, inspectionExecutor, markerOps } = this.deps;
|
|
1158
|
+
const { commandExecutor, inspectionExecutor, adapter, driver, markerOps } = this.deps;
|
|
939
1159
|
const operations = deserializeMongoOps(options.plan.operations);
|
|
940
1160
|
const policyCheck = this.enforcePolicyCompatibility(options.policy, operations);
|
|
941
1161
|
if (policyCheck) return policyCheck;
|
|
@@ -951,15 +1171,22 @@ var MongoMigrationRunner = class {
|
|
|
951
1171
|
for (const operation of operations) {
|
|
952
1172
|
options.callbacks?.onOperationStart?.(operation);
|
|
953
1173
|
try {
|
|
1174
|
+
if (operation.operationClass === "data") {
|
|
1175
|
+
const result = await this.executeDataTransform(operation, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks);
|
|
1176
|
+
if (result.failure) return result.failure;
|
|
1177
|
+
if (result.executed) operationsExecuted += 1;
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
const ddlOp = operation;
|
|
954
1181
|
if (runPostchecks && runIdempotency) {
|
|
955
|
-
if (await this.allChecksSatisfied(
|
|
1182
|
+
if (await this.allChecksSatisfied(ddlOp.postcheck, inspectionExecutor, filterEvaluator)) continue;
|
|
956
1183
|
}
|
|
957
1184
|
if (runPrechecks) {
|
|
958
|
-
if (!await this.evaluateChecks(
|
|
1185
|
+
if (!await this.evaluateChecks(ddlOp.precheck, inspectionExecutor, filterEvaluator)) return runnerFailure("PRECHECK_FAILED", `Operation ${operation.id} failed during precheck`, { meta: { operationId: operation.id } });
|
|
959
1186
|
}
|
|
960
|
-
for (const step of
|
|
1187
|
+
for (const step of ddlOp.execute) await step.command.accept(commandExecutor);
|
|
961
1188
|
if (runPostchecks) {
|
|
962
|
-
if (!await this.evaluateChecks(
|
|
1189
|
+
if (!await this.evaluateChecks(ddlOp.postcheck, inspectionExecutor, filterEvaluator)) return runnerFailure("POSTCHECK_FAILED", `Operation ${operation.id} failed during postcheck`, { meta: { operationId: operation.id } });
|
|
963
1190
|
}
|
|
964
1191
|
operationsExecuted += 1;
|
|
965
1192
|
} finally {
|
|
@@ -967,7 +1194,7 @@ var MongoMigrationRunner = class {
|
|
|
967
1194
|
}
|
|
968
1195
|
}
|
|
969
1196
|
const destination = options.plan.destination;
|
|
970
|
-
const profileHash = options.destinationContract.profileHash
|
|
1197
|
+
const profileHash = hasProfileHash(options.destinationContract) ? options.destinationContract.profileHash : destination.storageHash;
|
|
971
1198
|
if (operationsExecuted === 0 && existingMarker?.storageHash === destination.storageHash && existingMarker.profileHash === profileHash) return ok({
|
|
972
1199
|
operationsPlanned: operations.length,
|
|
973
1200
|
operationsExecuted
|
|
@@ -995,6 +1222,56 @@ var MongoMigrationRunner = class {
|
|
|
995
1222
|
operationsExecuted
|
|
996
1223
|
});
|
|
997
1224
|
}
|
|
1225
|
+
async executeDataTransform(op, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks) {
|
|
1226
|
+
if (runPostchecks && runIdempotency && op.postcheck.length > 0) {
|
|
1227
|
+
if (await this.evaluateDataTransformChecks(op.postcheck, adapter, driver, filterEvaluator)) return { executed: false };
|
|
1228
|
+
}
|
|
1229
|
+
if (runPrechecks && op.precheck.length > 0) {
|
|
1230
|
+
if (!await this.evaluateDataTransformChecks(op.precheck, adapter, driver, filterEvaluator)) return {
|
|
1231
|
+
executed: false,
|
|
1232
|
+
failure: runnerFailure("PRECHECK_FAILED", `Operation ${op.id} failed during precheck`, { meta: {
|
|
1233
|
+
operationId: op.id,
|
|
1234
|
+
name: op.name
|
|
1235
|
+
} })
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
for (const plan of op.run) {
|
|
1239
|
+
const wireCommand = adapter.lower(plan);
|
|
1240
|
+
for await (const _ of driver.execute(wireCommand));
|
|
1241
|
+
}
|
|
1242
|
+
if (runPostchecks && op.postcheck.length > 0) {
|
|
1243
|
+
if (!await this.evaluateDataTransformChecks(op.postcheck, adapter, driver, filterEvaluator)) return {
|
|
1244
|
+
executed: false,
|
|
1245
|
+
failure: runnerFailure("POSTCHECK_FAILED", `Operation ${op.id} failed during postcheck`, { meta: {
|
|
1246
|
+
operationId: op.id,
|
|
1247
|
+
name: op.name
|
|
1248
|
+
} })
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
return { executed: true };
|
|
1252
|
+
}
|
|
1253
|
+
async evaluateDataTransformChecks(checks, adapter, driver, filterEvaluator) {
|
|
1254
|
+
for (const check of checks) {
|
|
1255
|
+
const commandKind = check.source.command.kind;
|
|
1256
|
+
if (!READ_ONLY_CHECK_COMMAND_KINDS.has(commandKind)) throw errorRunnerFailed(`Data-transform check rejected: command kind "${commandKind}" is not read-only`, {
|
|
1257
|
+
why: "Data-transform checks must use aggregate or rawAggregate commands so the pre/postcheck path cannot mutate the database.",
|
|
1258
|
+
fix: "Author the check.source as an aggregate pipeline (or rawAggregate) rather than a DML write command.",
|
|
1259
|
+
meta: {
|
|
1260
|
+
checkDescription: check.description,
|
|
1261
|
+
commandKind,
|
|
1262
|
+
collection: check.source.collection
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
const wireCommand = adapter.lower(check.source);
|
|
1266
|
+
let matchFound = false;
|
|
1267
|
+
for await (const row of driver.execute(wireCommand)) if (filterEvaluator.evaluate(check.filter, row)) {
|
|
1268
|
+
matchFound = true;
|
|
1269
|
+
break;
|
|
1270
|
+
}
|
|
1271
|
+
if (!(check.expect === "exists" ? matchFound : !matchFound)) return false;
|
|
1272
|
+
}
|
|
1273
|
+
return true;
|
|
1274
|
+
}
|
|
998
1275
|
async evaluateChecks(checks, inspectionExecutor, filterEvaluator) {
|
|
999
1276
|
for (const check of checks) {
|
|
1000
1277
|
const matchFound = (await check.source.accept(inspectionExecutor)).some((doc) => filterEvaluator.evaluate(check.filter, doc));
|