refactor(framework): collapse the single/multi-space runner split into one MigrationRunner (TML-2464, TML-2476, TML-2478)#655
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (78)
📝 WalkthroughWalkthroughRefactors migration execution to a unified per-space execute({ driver, perSpaceOptions }) API. Updates core runner types/results, SQL/Postgres/SQLite/Mongo runners, CLI operations/output types, docs, and tests. Renames aggregate/multi-space terminology to per-space across the codebase. ChangesPer-space Execution Protocol
Sequence Diagram(s)sequenceDiagram
participant CLI
participant Planner as planMigration
participant Apply as applyMigration
participant Runner as MigrationRunner.execute
participant DB
CLI->>Planner: compute PerSpacePlan map
Planner-->>CLI: PlannerOutput (applyOrder, plans)
CLI->>Apply: { plans, order, driver, capability }
Apply->>Runner: execute({ driver, perSpaceOptions[] })
loop each space (ordered)
Runner->>DB: apply plan, verify, write marker
DB-->>Runner: per-space outcome
end
Runner-->>Apply: { perSpaceResults }
Apply-->>CLI: formatted per-space summary
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
@prisma-next/extension-author-tools
@prisma-next/mongo-runtime
@prisma-next/family-mongo
@prisma-next/sql-runtime
@prisma-next/family-sql
@prisma-next/extension-arktype-json
@prisma-next/middleware-cache
@prisma-next/mongo
@prisma-next/extension-paradedb
@prisma-next/extension-pgvector
@prisma-next/extension-postgis
@prisma-next/postgres
@prisma-next/sql-orm-client
@prisma-next/sqlite
@prisma-next/target-mongo
@prisma-next/adapter-mongo
@prisma-next/driver-mongo
@prisma-next/contract
@prisma-next/utils
@prisma-next/config
@prisma-next/errors
@prisma-next/framework-components
@prisma-next/operations
@prisma-next/ts-render
@prisma-next/contract-authoring
@prisma-next/ids
@prisma-next/psl-parser
@prisma-next/psl-printer
@prisma-next/cli
@prisma-next/cli-telemetry
@prisma-next/emitter
@prisma-next/migration-tools
prisma-next
@prisma-next/vite-plugin-contract-emit
@prisma-next/mongo-codec
@prisma-next/mongo-contract
@prisma-next/mongo-value
@prisma-next/mongo-contract-psl
@prisma-next/mongo-contract-ts
@prisma-next/mongo-emitter
@prisma-next/mongo-schema-ir
@prisma-next/mongo-query-ast
@prisma-next/mongo-orm
@prisma-next/mongo-query-builder
@prisma-next/mongo-lowering
@prisma-next/mongo-wire
@prisma-next/sql-contract
@prisma-next/sql-errors
@prisma-next/sql-operations
@prisma-next/sql-schema-ir
@prisma-next/sql-contract-psl
@prisma-next/sql-contract-ts
@prisma-next/sql-contract-emitter
@prisma-next/sql-lane-query-builder
@prisma-next/sql-relational-core
@prisma-next/sql-builder
@prisma-next/target-postgres
@prisma-next/target-sqlite
@prisma-next/adapter-postgres
@prisma-next/adapter-sqlite
@prisma-next/driver-postgres
@prisma-next/driver-sqlite
commit: |
size-limit report 📦
|
Unify per-space execution on MigrationRunner.execute with MigrationRunnerPerSpaceOptions (including strictVerification and context), fold aggregate success/failure types into the framework runner result shapes, and remove the hasMultiSpaceRunner guard plus MultiSpaceCapableRunner. Sql, Postgres, SQLite, and Mongo runners now implement the single execute entry point; apply-aggregate calls it directly without casts. Signed-off-by: Will Madden <madden@prisma.io>
Wrap single-space SqlMigrationRunner integration tests in a one-element perSpaceOptions list, rename multi-space tests to execute, and align CLI mocks with MigrationRunnerResult. Signed-off-by: Will Madden <madden@prisma.io>
…ecute The package-test run did not cover test/integration or the sqlite e2e harness, so they still referenced the deleted hasMultiSpaceRunner guard, MultiSpaceRunnerPerSpaceOptions, and runner.executeAcrossSpaces after the MigrationRunner collapse. Migrate them to the unified runner.execute per-space API, read results via perSpaceResults, and tidy the stray blank lines and stale executeAcrossSpaces comments left by the rewrap. Signed-off-by: Will Madden <madden@prisma.io>
…ly surfaces TML-2464 AC8. The Aggregate qualifier named the migration planner/apply path, which no longer has a non-aggregate counterpart, so it carries no information on the public surface. Drop it from the planner and apply families while keeping the ContractSpaceAggregate / ContractSpaceMember data shapes (and the AggregateCurrentDBState / AggregateMigrationEdgeRef value types) that describe what a value is. Renames: planAggregate -> planMigration; executeAggregateApply -> executeApply (+ ExecuteApplyOptions); applyAggregate -> applyMigration (+ ApplyMigrationInputs/Value/Result, ApplyAction, ApplyRunnerFailure); AggregatePerSpacePlan -> PerSpacePlan; AggregatePerSpaceExecutionEntry -> PerSpaceExecutionEntry; AggregatePlannerInput/Output/Success/Error -> Planner*; files db-apply-aggregate.ts -> db-apply.ts and apply-aggregate.ts -> apply.ts (+ their test files). Hard rename, no compat aliases. The aggregate verifier surface (verifyAggregate / AggregateVerifier*) is left as-is: no verifier symbol is in the AC8 rename set, so it stays out of this pass to avoid unsanctioned scope. Signed-off-by: Will Madden <madden@prisma.io>
TML-2464 AC8 follow-up. D2 dropped the Aggregate path-qualifier from the planner and apply surfaces but left the verifier surface qualified, an incoherent half-renamed public API. Every verifier symbol names the verify path (no non-aggregate counterpart), so drop the qualifier consistently with the renamed planMigration / applyMigration siblings: verifyAggregate -> verifyMigration; runVerifyAggregate -> runVerifyMigration; AggregateVerifierInput/Output/Success/Error -> Verifier*. The ContractSpaceAggregate / ContractSpaceMember data shapes the verifier operates over keep their names. Also fix the stale "Aggregate planner output" throw string in the renamed apply primitive. Hard rename, no compat aliases. Signed-off-by: Will Madden <madden@prisma.io>
The runner API was unified onto a single per-space `execute` entry point, so the single-space vs multi-space distinction no longer exists. Sweep active docstrings, comments, and test descriptions to treat aggregate / per-space as the only mode: drop "single-space" / "multi-space" mode framing, rephrase descriptive uses to "across spaces" / "per-space", and the n=1 case to "one space" / "app-only". Rename the runner test files that carried the now-redundant qualifier: - test/integration/test/mongo/multi-space-runner.test.ts -> runner.test.ts - examples/multi-extension-monorepo/test/multi-space.e2e.integration.test.ts -> e2e.integration.test.ts - adapters/postgres .../runner.multi-space.integration.test.ts -> runner.across-spaces.integration.test.ts - adapters/sqlite .../runner.multi-space.test.ts -> runner.across-spaces.test.ts Update the three active subsystem docs (Migration System, Adapters & Targets, MongoDB Family) to the unified `execute` surface and aggregate-only framing; ADR 212 is left untouched as historical record. Prose / comments / test descriptions / file renames only; no behaviour change. Signed-off-by: Will Madden <madden@prisma.io>
…ion ID
Four review follow-ups, prose/comments only:
- drop the stray AM4 acceptance-criterion prefix on the pg db-init-update
docblock bullet (describe the rollback property directly).
- mongo-runner projectSchema docblock: drop single-space/pre-aggregate
framing, matching its sibling docblock.
- example e2e overview: drop redundant "Multi-space " ("across three
spaces" already carries it).
- cli migrations formatter: reword the two "Single-space fallback"
comments to "app-only / no-aggregate-breakdown fallback" (branch kept).
Signed-off-by: Will Madden <madden@prisma.io>
…s (TML-2478) Lock the M6 restructure that routes pre-flight loading failures through structured-error paths instead of throwing past handleResult: - buildReadAggregate terminal catch: a non-MigrationToolsError raised during pre-flight assembly returns errorUnexpected (notOk), and a MigrationToolsError maps via mapMigrationToolsError — neither propagates. - migrate command contract read: a missing top-level contract.json yields errorFileNotFound (PN-CLI-4004) and an unparseable one yields errorContractValidationFailed (PN-CLI-4003), distinct from the corrupt target-bundle end-contract.json case already covered. Test-only; no production code changed. Signed-off-by: Will Madden <madden@prisma.io>
81f546f to
e1310ae
Compare
The decision: there is now exactly one migration runner. The transitional split between a "single-space" runner and a "multi-space" runner — selected at the call site by a capability guard — is gone. Applying a migration is one method,
MigrationRunner.execute, and the app-only case is just a one-member list.Here is the entire change, at the call site that applies a migration across contract spaces:
Why this is safe now
The two-runner split was never a design we wanted — it was scaffolding for a migration in progress. When contract spaces landed, only some targets understood the "apply across many spaces" shape; the rest still spoke the old single-space shape. The
hasMultiSpaceRunnerguard let the framework tolerate both at once: route to the new path when the target supported it, fall back otherwise.That migration is now complete. Every target speaks the aggregate shape — Postgres, SQLite (TML-2463), and Mongo (TML-2408). With no target left on the old path, the guard, the fallback, and the separate "multi-space" interface no longer distinguish anything. They just leave a phantom "other runner" in every reader's mental model. This PR deletes that phantom.
What collapses
MultiSpaceCapableRunner,MultiSpaceRunnerResult, andMultiSpaceRunnerPerSpaceOptionsfold directly intoMigrationRunner,MigrationRunnerResult, andMigrationRunnerPerSpaceOptions— not preserved as aliases.executeAcrossSpacesbecomes the oneMigrationRunner.execute({ driver, perSpaceOptions }); the former single-space callers pass a one-member list. (executeOnConnectionstays — it is the intra-transaction fan-out primitive, not a second public entry point.)Aggregate…qualifier on the public surface describes nothing, so it drops:planAggregate→plan,executeAggregateApply→executeApply,AggregatePerSpacePlan→PerSpacePlan,AggregatePlannerError→PlannerError,apply-aggregate.ts→apply.ts.ContractSpaceAggregateandContractSpaceMemberare kept — they name a data shape, not a code path, so the qualifier still carries information.*.multi-space.test.tsfiles merge into their canonical counterparts. ADRs that document the transition are left untouched, as an immutable record.The two fold-ins
The before/after above also resolves TML-2476: those two
as-casts existed becauseMultiSpaceRunnerPerSpaceOptionswas a strict subset that omittedstrictVerificationandcontext. Unifying the option type — it now declaresstrictVerification?: booleanandcontext?: OperationContext— removes the reason for the casts, so they go too. Shipping 2476 on its own would have meant editing a type this PR then deletes.TML-2478 asked for structured CLI error envelopes on migrate pre-flight filesystem failures. Re-checking the code showed the M6 restructure already routes those failures through
errorUnexpected+notOkrather than throwing pasthandleResult— the gap the ticket described is already closed. So this PR adds regression tests that pin that behaviour, and 2478 closes as fixed-by-restructure.Scope
Pure refactor plus test hardening. Migration execution behaviour is unchanged: the app-only case runs through exactly the same code as the multi-member case (
extensions = []).verifySchema, the canonical family schema-verification primitive, predates this PR and is untouched.Test plan
pnpm typecheck(clean locally)pnpm test:packagespnpm test:integrationpnpm test:e2epnpm lint:depsCI is the gate. Locally,
test:packagesshowed intermittent infra flakiness (Postgres connection churn under parallel vitest; acli-telemetryPATH issue in recursive exec) unrelated to these changes; targeted reruns of the migration / apply / framework / cli suites passed.Alternatives considered
MultiSpaceCapableRunneras a deprecated alias. Rejected: an alias preserves the phantom "other runner" the PR exists to remove. The value is in there being one shape, not in a soft landing.Aggregate…qualifier. Rejected: with no non-aggregate counterpart, it distinguishes nothing on the public surface. (Kept onContractSpaceAggregate/ContractSpaceMember, where it names data rather than a path.)handleResultgap; a "fix" would be a no-op, so the honest deliverable is a regression test.Closes TML-2464
Closes TML-2476
Closes TML-2478
Summary by CodeRabbit
Release Notes