@prisma/orm-target-mongo 8.0.0-rc.19-dev.2 → 8.0.0-rc.19-dev.3

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.
@@ -156,16 +156,24 @@ interface MongoMigrationRunnerExecuteOptions {
156
156
  readonly scopeVerifyResult?: (result: VerifyDatabaseSchemaResult) => VerifyDatabaseSchemaResult;
157
157
  /** Per-edge breakdown from graph-walk planning; drives per-edge ledger writes. */
158
158
  readonly migrationEdges: readonly AggregateMigrationEdgeRef[];
159
+ /** Whether an earlier space of the same apply already changed the database. */
160
+ readonly databaseChangedBefore?: boolean;
159
161
  }
160
162
  /** A failure of the Mongo runner: one of the codes it returns. */
161
163
  interface MongoMigrationRunnerFailure extends MigrationRunnerFailure {
162
164
  readonly code: MongoMigrationRunnerErrorCode;
163
165
  }
164
- type MongoMigrationRunnerResult = Result<MigrationRunnerPerSpaceSuccessValue, MongoMigrationRunnerFailure>;
166
+ /** A space's apply: what the framework reports, and whether it changed the database, its marker and ledger included. */
167
+ interface MongoSpaceSuccessValue extends MigrationRunnerPerSpaceSuccessValue {
168
+ readonly changedDatabase: boolean;
169
+ }
170
+ type MongoMigrationRunnerResult = Result<MongoSpaceSuccessValue, MongoMigrationRunnerFailure>;
165
171
  declare class MongoMigrationRunner {
166
172
  private readonly deps;
167
173
  constructor(deps: MongoRunnerDependencies);
168
174
  execute(options: MongoMigrationRunnerExecuteOptions): Promise<MongoMigrationRunnerResult>;
175
+ /** Applies the plan, calling `wrote` after each command that changes the database. */
176
+ private apply;
169
177
  private recordLedgerEntries;
170
178
  private executeDmlOperation;
171
179
  private evaluateDmlChecks;
@@ -339,4 +347,4 @@ declare class MongoTargetUnboundDatabase extends MongoTargetDatabase {
339
347
  }
340
348
  //#endregion
341
349
  export { deserializeMongoOps as _, MongoMigrationRunnerExecuteOptions as a, renderOps as b, MongoTargetContract as c, MongoTargetSchemaVerifier as d, MongoTargetUnboundDatabase as f, deserializeMongoOp as g, RenderMigrationMeta as h, MongoMigrationRunnerErrorCode as i, MongoTargetContractSerializer as l, PlannerProducedMongoMigration as m, MongoMigrationPlanner as n, MongoMigrationRunnerFailure as o, PlanCallsResult as p, MongoMigrationRunner as r, MongoMigrationRunnerResult as s, FilterEvaluator as t, MongoTargetDatabase as u, mongoTargetDescriptor as v, serializeMongoOps as x, renderCallsToTypeScript as y };
342
- //# sourceMappingURL=control-Poy33Wpm.d.mts.map
350
+ //# sourceMappingURL=control-BjaiAXAN.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-BjaiAXAN.d.mts","names":[],"sources":["../../../../3-mongo-target/1-mongo-target/dist/control.d.mts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6BK,sBAAsB,KAAK;WACrB,SAAS;;;;;;;;;;;;;;cAcN,uBAAuB,6BAA6B;;;cAGpD,2BAA2B;UAC/B;EACR,SAAS,QAAQ,iBAAiB,KAAK;EACvC,MAAM,MAAM;EACZ,IAAI,MAAM;EACV,GAAG,MAAM;EACT,IAAI,MAAM;EACV,OAAO,MAAM;EACb,KAAK,OAAO;;;;iBAIG,mBAAmB,gBAAgB;iBACnC,oBAAoB,2BAA2B;iBAC/C,kBAAkB,cAAc;;;;;;;;UAQvC;WACC,QAAQ;;WAER,4BAA4B;;WAE5B,oBAAoB,kBAAkB;;;;KAI5C;WACM;WACA,OAAO;;WAEP,mBAAmB;;WAEnB;WACA,WAAW;;cAER,iCAAiC;EAC7C,UAAU;aACC;aACA;aACA,QAAQ;aACR,qBAAqB,cAAc;;aAEnC,cAAc;;aAEd,iBAAiB;MACxB;EACJ,KAAK;aACM;aACA;aACA,QAAQ;;aAER,cAAc;;aAEd,QAAQ;;aAER,qBAAqB;aACrB,qBAAqB,cAAc;;;;;;aAMnC;MACP;;;;;;;;;;EAUJ,eAAe,SAAS,2BAA2B;;;;;KAKhD;;;UAGK;WACC,MAAM;WACN,qBAAqB;WACrB,QAAQ;WACR;IACP,kBAAkB,IAAI;IACtB,qBAAqB,IAAI;;WAElB,kBAAkB;WAClB,qBAAqB,cAAc;WACnC;WACA,UAAU;;;;;;;;;;;WAWV,qBAAqB,QAAQ,+BAA+B;;WAE5D,yBAAyB;;WAEzB;;;UAGD,oCAAoC;WACnC,MAAM;;;UAGP,+BAA+B;WAC9B;;KAEN,6BAA6B,OAAO,wBAAwB;cACnD;mBACK;EACjB,YAAY,MAAM;EAClB,QAAQ,SAAS,qCAAqC,QAAQ;;UAEtD;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;;;;;;;;;;;;;;;;;;;;;;;;cAyBI,kCAAkC,wBAAwB,qBAAqB;YACjF,gBAAgB;aACf,UAAU;aACV,QAAQ;aACR;aACA,WAAW;eACT;YACH,uBAAuB,UAAU,oBAAoB,qBAAqB,0BAA0B;;;;;;;;;;;;;;;;;;;cAmBlG,sCAAsC,UAAU,uCAAuC;mBAClF;mBACA;mBACA;WACR;EACT,YAAY,gBAAgB,mBAAiB,MAAM,eAAe;MAC9D,uBAAuB;EAC3B,YAAY;EACZ,iBAAiB,wBAAwB;;;;iBAI1B,UAAU,OAAO,cAAc,mBAAiB;;;UAGvD;WACC;WACA;;WAEA;;;;;;;WAOA,yBAAyB;;;;;;;;;;;;;;;;;;;iBAmBnB,wBAAwB,OAAO,cAAc,kBAAgB,MAAM;;;cAGtE,sCAAsC,4BAA4B;YACpE,wBAAwB,WAAW,gBAAgB;EAC7D,kBAAkB,UAAU,sBAAsB;;;;UAI1C;WACC;WACA,UAAU,SAAS,eAAe,SAAS;aACzC,aAAa,SAAS,eAAe;aACrC,WAAW,SAAS,eAAe;;;;;;;;;;;;;;;;;cAiBlC,4BAA4B;WAC/B;WACA;WACA,SAAS;EAClB,YAAY,OAAO;MACf,cAAc,SAAS,eAAe;;;;;EAK1C;;;;;;;EAOA,kBAAkB;;;;;;;;;;;;;;;cAeN,mCAAmC;kBAC/B,UAAU;UAClB;EACR;EACA,kBAAkB"}
@@ -1,6 +1,6 @@
1
1
  import { t as mongoTargetError } from "./mongo-target-errors-Btf3ML1w-B5EMYbz1.mjs";
2
2
  import { t as mongoTargetDescriptorMeta } from "./descriptor-meta-Dtl7SqQv-D50zqWiV.mjs";
3
- import { a as dropCollection, c as renameField, d as unsetField, n as createCollection, o as dropIndex, r as createIndex, s as renameCollection, t as collMod, u as unrewritableFieldNameReason } from "./migration-factories-jwrORVMV-BGqJk_WT.mjs";
3
+ import { a as dropCollection, c as renameField, d as unsetField, n as createCollection, o as dropIndex, r as createIndex, s as renameCollection, t as collMod, u as unrewritableFieldNameReason } from "./migration-factories-BqROEHRs-C4K_DHy7.mjs";
4
4
  import { blindCast } from "@prisma/orm-framework/utils/casts";
5
5
  import { type } from "arktype";
6
6
  import { ifDefined } from "@prisma/orm-framework/utils/defined";
@@ -9,7 +9,7 @@ import { MongoSchemaCollection, MongoSchemaIR, canonicalize, deepEqual, indexLoo
9
9
  import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoAndExpr, MongoExistsExpr, MongoFieldFilter, MongoNotExpr, MongoOrExpr, RenameCollectionCommand, isMongoDmlOperation } from "@prisma/orm-family-mongo/query-ast/control";
10
10
  import { AggregateCommand, MongoAddFieldsStage, MongoLimitStage, MongoLookupStage, MongoMatchStage, MongoMergeStage, MongoProjectStage, MongoSortStage, RawAggregateCommand, RawDeleteManyCommand, RawDeleteOneCommand, RawFindOneAndDeleteCommand, RawFindOneAndUpdateCommand, RawInsertManyCommand, RawInsertOneCommand, RawUpdateManyCommand, RawUpdateOneCommand } from "@prisma/orm-family-mongo/query-ast/execution";
11
11
  import { canonicalizeSchemasForVerification, contractToMongoSchemaIR, diffMongoSchemas, fieldRewriteOf } from "@prisma/orm-family-mongo/family/control";
12
- import { APP_SPACE_ID, VERIFY_CODE_SCHEMA_FAILURE, contractSnapshotJsonSpecifier, contractSnapshotTypesSpecifier, describeMigrationStatement, failedPrecheckWhy, issueOutcome, migrationRunnerFailure, modelDisplayName, schemaCheckWhy, withFailingSpace } from "@prisma/orm-framework/components/control";
12
+ import { APP_SPACE_ID, VERIFY_CODE_SCHEMA_FAILURE, contractSnapshotJsonSpecifier, contractSnapshotTypesSpecifier, describeMigrationStatement, expectAbsent, expectPresent, failedPostcheckWhy, failedPrecheckWhy, issueOutcome, migrationRunnerFailure, modelDisplayName, schemaCheckWhy, withDatabaseUnchanged, withFailingSpace } from "@prisma/orm-framework/components/control";
13
13
  import { notOk, ok } from "@prisma/orm-framework/utils/result";
14
14
  import { MongoContractSerializerBase, MongoSchemaVerifierBase } from "@prisma/orm-family-mongo/family/ir";
15
15
  import { MongoCollection, MongoStorage, collectionControlPoliciesOf, collectionControlPolicyOf, collectionRootModelsOf, hasOwnFieldStoredAs, modelAndBasesOf, mongoModelsOf, ownEmbedStoredNamesOf, ownStoredNameOf, ownStoredNamesOf, validatorFieldNamesOf, validatorRootShapesOf } from "@prisma/orm-family-mongo/contract";
@@ -1595,7 +1595,8 @@ const CheckJson = type({
1595
1595
  description: "string",
1596
1596
  source: "Record<string, unknown>",
1597
1597
  filter: "Record<string, unknown>",
1598
- expect: "\"exists\" | \"notExists\""
1598
+ expect: "\"exists\" | \"notExists\"",
1599
+ "object?": "string > 0"
1599
1600
  });
1600
1601
  const StepJson = type({
1601
1602
  description: "string",
@@ -1894,7 +1895,8 @@ function deserializeCheck(json) {
1894
1895
  description: data.description,
1895
1896
  source: deserializeInspectionCommand(data.source),
1896
1897
  filter: deserializeFilterExpr(data.filter),
1897
- expect: data.expect
1898
+ expect: data.expect,
1899
+ ...ifDefined("object", data.object)
1898
1900
  };
1899
1901
  }
1900
1902
  function deserializeStep(json) {
@@ -1950,6 +1952,26 @@ function serializeMongoOps(ops) {
1950
1952
  return JSON.stringify(ops, null, 2);
1951
1953
  }
1952
1954
  const READ_ONLY_CHECK_COMMAND_KINDS = /* @__PURE__ */ new Set(["aggregate", "rawAggregate"]);
1955
+ const CHANGED_DOCUMENT_COUNTS = [
1956
+ "insertedCount",
1957
+ "modifiedCount",
1958
+ "upsertedCount",
1959
+ "deletedCount"
1960
+ ];
1961
+ /** Whether a write command's result row says it changed no document: every count it carries is zero. */
1962
+ function reportsNoChangedDocuments(row) {
1963
+ if (typeof row !== "object" || row === null) return false;
1964
+ const counts = CHANGED_DOCUMENT_COUNTS.map((field) => Reflect.get(row, field)).filter((count) => count !== void 0);
1965
+ return counts.length > 0 && counts.every((count) => count === 0);
1966
+ }
1967
+ function failedCheckOf(operationId, phase, check) {
1968
+ return {
1969
+ operationId,
1970
+ phase,
1971
+ description: check.description,
1972
+ ...ifDefined("expectation", check.object === void 0 ? void 0 : check.expect === "exists" ? expectPresent(check.object) : expectAbsent(check.object))
1973
+ };
1974
+ }
1953
1975
  function runnerFailure(code, summary, options) {
1954
1976
  return notOk(migrationRunnerFailure(code, summary, options));
1955
1977
  }
@@ -1968,7 +1990,7 @@ function renameOverwriteRefusal(op) {
1968
1990
  const match = source instanceof RawAggregateCommand ? Reflect.get(source.pipeline[0] ?? {}, "$match") : void 0;
1969
1991
  const find = `db.getCollection(${JSON.stringify(rewrite.collection)}).find(${JSON.stringify(match ?? {})})`;
1970
1992
  return runnerFailure("MIGRATION.PRECHECK_FAILED", `Operation ${op.id} stopped: some documents in collection ${rewrite.collection} already hold ${to} as well as ${rewrite.field}`, {
1971
- why: `Renaming ${rewrite.field} to ${to} would overwrite their ${to}. Find them with ${find} in mongosh, and move or remove one of the two values in each. Nothing was renamed. The operations before this one in the plan already ran, such as dropping an index on ${rewrite.field}; once the documents are fixed, run the command again and the plan finishes from here.`,
1993
+ why: `Renaming ${rewrite.field} to ${to} would overwrite their ${to}. Find them with ${find} in mongosh, and move or remove one of the two values in each. Nothing was renamed. Once the documents are fixed, run the command again; operations that already ran are skipped.`,
1972
1994
  meta: {
1973
1995
  operationId: op.id,
1974
1996
  name: op.name
@@ -2012,6 +2034,17 @@ var MongoMigrationRunner = class {
2012
2034
  this.deps = deps;
2013
2035
  }
2014
2036
  async execute(options) {
2037
+ let changedDatabase = false;
2038
+ const result = await this.apply(options, () => {
2039
+ changedDatabase = true;
2040
+ });
2041
+ return result.ok ? ok({
2042
+ ...result.value,
2043
+ changedDatabase
2044
+ }) : notOk(withDatabaseUnchanged(result.failure, options.databaseChangedBefore !== true && !changedDatabase));
2045
+ }
2046
+ /** Applies the plan, calling `wrote` after each command that changes the database. */
2047
+ async apply(options, wrote) {
2015
2048
  const { inspectionExecutor, adapter, driver, executeDdl, markerOps } = this.deps;
2016
2049
  const operations = deserializeMongoOps(blindCast(options.plan.operations));
2017
2050
  const space = options.plan.spaceId ?? APP_SPACE_ID;
@@ -2030,7 +2063,7 @@ var MongoMigrationRunner = class {
2030
2063
  options.callbacks?.onOperationStart?.(operation);
2031
2064
  try {
2032
2065
  if (isMongoDmlOperation(operation)) {
2033
- const result = await this.executeDmlOperation(operation, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks);
2066
+ const result = await this.executeDmlOperation(operation, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks, wrote);
2034
2067
  if (result.failure) return result.failure;
2035
2068
  if (result.executed) operationsExecuted += 1;
2036
2069
  continue;
@@ -2039,22 +2072,31 @@ var MongoMigrationRunner = class {
2039
2072
  if (await this.allChecksSatisfied(operation.postcheck, inspectionExecutor, filterEvaluator)) continue;
2040
2073
  }
2041
2074
  if (runPrechecks) {
2042
- const failed = await this.firstFailingCheck(operation.precheck, inspectionExecutor, filterEvaluator);
2043
- if (failed !== void 0) {
2044
- const failedCheck = {
2045
- operationId: operation.id,
2046
- phase: "precheck",
2047
- description: failed.description
2048
- };
2049
- return renameTargetExistsRefusal(operation, failed) ?? runnerFailure("MIGRATION.PRECHECK_FAILED", `Operation ${operation.id} failed during precheck: ${failed.description}`, {
2075
+ const failing = await this.firstFailingCheck(operation.precheck, inspectionExecutor, filterEvaluator);
2076
+ if (failing !== void 0) {
2077
+ const failedCheck = failedCheckOf(operation.id, "precheck", failing);
2078
+ return renameTargetExistsRefusal(operation, failing) ?? runnerFailure("MIGRATION.PRECHECK_FAILED", `Operation ${operation.id} failed during precheck: ${failing.description}`, {
2050
2079
  why: failedPrecheckWhy(failedCheck),
2051
2080
  meta: { failedCheck }
2052
2081
  });
2053
2082
  }
2054
2083
  }
2055
- for (const step of operation.execute) await executeDdl(step.command);
2084
+ for (const step of operation.execute) {
2085
+ await executeDdl(step.command);
2086
+ wrote();
2087
+ }
2056
2088
  if (runPostchecks) {
2057
- if (!await this.evaluateChecks(operation.postcheck, inspectionExecutor, filterEvaluator)) return runnerFailure("MIGRATION.POSTCHECK_FAILED", `Operation ${operation.id} failed during postcheck`, { meta: { operationId: operation.id } });
2089
+ const failing = await this.firstFailingCheck(operation.postcheck, inspectionExecutor, filterEvaluator);
2090
+ if (failing !== void 0) {
2091
+ const failedCheck = failedCheckOf(operation.id, "postcheck", failing);
2092
+ return runnerFailure("MIGRATION.POSTCHECK_FAILED", `Operation ${operation.id} failed during postcheck: ${failing.description}`, {
2093
+ why: failedPostcheckWhy(failedCheck),
2094
+ meta: {
2095
+ operationId: operation.id,
2096
+ failedCheck
2097
+ }
2098
+ });
2099
+ }
2058
2100
  }
2059
2101
  operationsExecuted += 1;
2060
2102
  } finally {
@@ -2100,6 +2142,7 @@ var MongoMigrationRunner = class {
2100
2142
  profileHash,
2101
2143
  invariants: incomingInvariants
2102
2144
  });
2145
+ wrote();
2103
2146
  await this.recordLedgerEntries(markerOps, space, options);
2104
2147
  }
2105
2148
  return ok({
@@ -2126,7 +2169,7 @@ var MongoMigrationRunner = class {
2126
2169
  });
2127
2170
  }
2128
2171
  }
2129
- async executeDmlOperation(op, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks) {
2172
+ async executeDmlOperation(op, adapter, driver, filterEvaluator, runIdempotency, runPrechecks, runPostchecks, wrote) {
2130
2173
  if (runPostchecks && runIdempotency && op.postcheck.length > 0) {
2131
2174
  if (await this.evaluateDmlChecks(op.postcheck, adapter, driver, filterEvaluator)) return { executed: false };
2132
2175
  }
@@ -2142,7 +2185,11 @@ var MongoMigrationRunner = class {
2142
2185
  for (const plan of op.run) {
2143
2186
  const wireCommand = await adapter.lower(plan, {});
2144
2187
  try {
2145
- for await (const _ of driver.execute(wireCommand));
2188
+ let reportedNoChange = false;
2189
+ let reportedChange = false;
2190
+ for await (const row of driver.execute(wireCommand)) if (reportsNoChangedDocuments(row)) reportedNoChange = true;
2191
+ else reportedChange = true;
2192
+ if (reportedChange || !reportedNoChange) wrote();
2146
2193
  } catch (error) {
2147
2194
  const refusal = bypassValidationRefusal(op, plan, error);
2148
2195
  if (refusal === void 0) throw error;
@@ -2331,6 +2378,7 @@ const mongoTargetDescriptor = {
2331
2378
  return { async execute({ driver, perSpaceOptions }) {
2332
2379
  const contracts = perSpaceOptions.map((opts) => blindCast(opts.destinationContract));
2333
2380
  const perSpaceResults = [];
2381
+ let changedDatabase = false;
2334
2382
  for (let i = 0; i < perSpaceOptions.length; i++) {
2335
2383
  const spaceOptions = perSpaceOptions[i];
2336
2384
  if (!spaceOptions) continue;
@@ -2339,12 +2387,15 @@ const mongoTargetDescriptor = {
2339
2387
  const { space, ...runnerOptions } = spaceOptions;
2340
2388
  const result = await runMongo(driver, {
2341
2389
  ...runnerOptions,
2342
- scopeVerifyResult
2390
+ scopeVerifyResult,
2391
+ databaseChangedBefore: changedDatabase
2343
2392
  });
2344
2393
  if (!result.ok) return notOk(withFailingSpace(result.failure, space));
2394
+ const { changedDatabase: spaceChanged, ...value } = result.value;
2395
+ changedDatabase ||= spaceChanged;
2345
2396
  perSpaceResults.push({
2346
2397
  space,
2347
- value: result.value
2398
+ value
2348
2399
  });
2349
2400
  }
2350
2401
  return ok({ perSpaceResults });
@@ -2364,4 +2415,4 @@ const mongoTargetDescriptor = {
2364
2415
  //#endregion
2365
2416
  export { schemaIndexToCreateIndexOptions as C, schemaCollectionToCreateCollectionOptions as S, deserializeMongoOp as _, DropIndexCall as a, renderCallsToTypeScript as b, MongoMigrationRunner as c, MongoTargetSchemaVerifier as d, MongoTargetUnboundDatabase as f, UnsetFieldCall as g, RenameFieldCall as h, DropCollectionCall as i, MongoTargetContractSerializer as l, RenameCollectionCall as m, CreateCollectionCall as n, FilterEvaluator as o, PlannerProducedMongoMigration as p, CreateIndexCall as r, MongoMigrationPlanner as s, CollModCall as t, MongoTargetDatabase as u, deserializeMongoOps as v, serializeMongoOps as w, renderOps as x, mongoTargetDescriptor as y };
2366
2417
 
2367
- //# sourceMappingURL=control-zGCK2Hnz.mjs.map
2418
+ //# sourceMappingURL=control-CYS8H_t4.mjs.map