feat(examples): audit & consolidate demo migration fixtures (regenerate survivors, prune redundant)#677
Conversation
|
Important Review skippedToo many files! This PR contains 276 files, which is 126 over the limit of 150. To get a review, narrow the scope: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (276)
You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR adds a comprehensive Prisma-Next demo fixture set illustrating contract evolution and parallel schema migrations. It includes five contract variants (c1–c5) with progressive field additions, initial table creation, two parallel migration branches adding phone and avatar columns, and merge operations combining those changes. ChangesDiamond Demo Fixtures and Configuration
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
size-limit report 📦
|
@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: |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/migration.ts`:
- Around line 14-19: The migration in merge_bob incorrectly adds a "phone"
column; update the addColumn call in migration.ts (the addColumn('__unbound__',
'user', {...}) invocation inside the merge_bob migration) to add Bob's "avatar"
column instead of "phone" — i.e., change the name field to 'avatar' and keep the
same typeSql/defaultSql/nullable settings (or adjust if avatar has different
constraints) so the merge_bob migration applies Bob's avatar onto Alice's branch
that already has phone.
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/ops.json`:
- Around line 3-12: In the merge_bob migration ops.json entry, replace the
incorrect "phone" references with "avatar": update the operation "id" from
"column.user.phone" to "column.user.avatar", change the "label" from 'Add column
"phone" to "user"' to 'Add column "avatar" to "user"', and set
target.details.name to "avatar"; then update any corresponding SQL statements
(the CREATE/ALTER column references named "phone") in the migration
SQL/migration.ts that applied this op so they create/alter "avatar" instead of
"phone" (ensure the migration file for 20260303T1100_merge_bob and any function
handling this op use "column.user.avatar").
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/start-contract.d.ts`:
- Around line 47-60: The start contract's types (FieldOutputTypes and
FieldInputTypes) currently include `avatar` and lack `phone`, which is inverted
for merge_bob; update both FieldOutputTypes.user and FieldInputTypes.user to
replace the `avatar` field with `phone` using the appropriate CodecTypes entries
(for output use CodecTypes['pg/text@1']['output'] | null and for input use
CodecTypes['pg/text@1']['input'] | null) so the contract starts from Alice's
branch (with phone) and then merge_bob can add avatar.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 9c69f723-33df-4c8e-9080-b5caa7298098
⛔ Files ignored due to path filters (2)
projects/migration-graph-rendering/slices/diamond-fixture-regeneration/code-review.mdis excluded by!projects/**projects/migration-graph-rendering/slices/diamond-fixture-regeneration/spec.mdis excluded by!projects/**
📒 Files selected for processing (47)
examples/prisma-next-demo/diamond-contract/c1.d.tsexamples/prisma-next-demo/diamond-contract/c1.jsonexamples/prisma-next-demo/diamond-contract/c1.prismaexamples/prisma-next-demo/diamond-contract/c2.d.tsexamples/prisma-next-demo/diamond-contract/c2.jsonexamples/prisma-next-demo/diamond-contract/c2.prismaexamples/prisma-next-demo/diamond-contract/c3.d.tsexamples/prisma-next-demo/diamond-contract/c3.jsonexamples/prisma-next-demo/diamond-contract/c3.prismaexamples/prisma-next-demo/diamond-contract/c5.d.tsexamples/prisma-next-demo/diamond-contract/c5.jsonexamples/prisma-next-demo/diamond-contract/c5.prismaexamples/prisma-next-demo/migration-fixtures/diamond/app/20260301T1000_init/end-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260301T1000_init/end-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260301T1000_init/migration.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260301T1000_init/migration.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260301T1000_init/ops.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/end-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/end-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/migration.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/migration.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/ops.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/start-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1000_alice_add_phone/start-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/end-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/end-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/migration.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/migration.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/ops.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/start-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260302T1100_bob_add_avatar/start-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/end-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/end-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/migration.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/migration.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/ops.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/start-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1000_merge_alice/start-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/end-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/end-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/migration.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/migration.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/ops.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/start-contract.d.tsexamples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/start-contract.jsonexamples/prisma-next-demo/migration-fixtures/diamond/app/refs/prod.jsonexamples/prisma-next-demo/prisma-next.diamond.config.ts
| addColumn('__unbound__', 'user', { | ||
| name: 'phone', | ||
| typeSql: 'text', | ||
| defaultSql: '', | ||
| nullable: true, | ||
| }), |
There was a problem hiding this comment.
Critical: Wrong column name in merge_bob migration.
This migration adds a phone column, but merge_bob should add the avatar column (Bob's change) onto Alice's branch (which already has phone). The diamond topology requires:
- Alice's branch (C2): has
phone - Bob's branch (C3): has
avatar - merge_bob: takes Alice's branch (with
phone) + adds Bob'savatar - merge_alice: takes Bob's branch (with
avatar) + adds Alice'sphone
🐛 Proposed fix
addColumn('__unbound__', 'user', {
- name: 'phone',
+ name: 'avatar',
typeSql: 'text',
defaultSql: '',
nullable: true,
}),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/migration.ts`
around lines 14 - 19, The migration in merge_bob incorrectly adds a "phone"
column; update the addColumn call in migration.ts (the addColumn('__unbound__',
'user', {...}) invocation inside the merge_bob migration) to add Bob's "avatar"
column instead of "phone" — i.e., change the name field to 'avatar' and keep the
same typeSql/defaultSql/nullable settings (or adjust if avatar has different
constraints) so the merge_bob migration applies Bob's avatar onto Alice's branch
that already has phone.
| "id": "column.user.phone", | ||
| "label": "Add column phone to user", | ||
| "summary": "Adds column phone to table user", | ||
| "label": "Add column \"phone\" to \"user\"", | ||
| "operationClass": "additive", | ||
| "target": { | ||
| "id": "postgres", | ||
| "details": { | ||
| "schema": "public", | ||
| "objectType": "table", | ||
| "name": "user" | ||
| "schema": "__unbound__", | ||
| "objectType": "column", | ||
| "name": "phone", | ||
| "table": "user" |
There was a problem hiding this comment.
Critical: Wrong column name in ops.json.
Consistent with the issue in migration.ts, this operation adds phone but should add avatar. The operation ID, label, and column name must all reference avatar for the merge_bob migration.
🐛 Proposed fix
{
- "id": "column.user.phone",
- "label": "Add column \"phone\" to \"user\"",
+ "id": "column.user.avatar",
+ "label": "Add column \"avatar\" to \"user\"",
"operationClass": "additive",
"target": {
"id": "postgres",
"details": {
"schema": "__unbound__",
"objectType": "column",
- "name": "phone",
+ "name": "avatar",
"table": "user"
}
},And update the SQL statements:
"precheck": [
{
- "description": "ensure column \"phone\" is missing",
- "sql": "SELECT NOT EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n AND table_name = 'user'\n AND column_name = 'phone'\n)"
+ "description": "ensure column \"avatar\" is missing",
+ "sql": "SELECT NOT EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n AND table_name = 'user'\n AND column_name = 'avatar'\n)"
}
],
"execute": [
{
- "description": "add column \"phone\"",
- "sql": "ALTER TABLE \"user\" ADD COLUMN \"phone\" text"
+ "description": "add column \"avatar\"",
+ "sql": "ALTER TABLE \"user\" ADD COLUMN \"avatar\" text"
}
],
"postcheck": [
{
- "description": "verify column \"phone\" exists",
- "sql": "SELECT EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n AND table_name = 'user'\n AND column_name = 'phone'\n)"
+ "description": "verify column \"avatar\" exists",
+ "sql": "SELECT EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = current_schema()\n AND table_name = 'user'\n AND column_name = 'avatar'\n)"
}
]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/ops.json`
around lines 3 - 12, In the merge_bob migration ops.json entry, replace the
incorrect "phone" references with "avatar": update the operation "id" from
"column.user.phone" to "column.user.avatar", change the "label" from 'Add column
"phone" to "user"' to 'Add column "avatar" to "user"', and set
target.details.name to "avatar"; then update any corresponding SQL statements
(the CREATE/ALTER column references named "phone") in the migration
SQL/migration.ts that applied this op so they create/alter "avatar" instead of
"phone" (ensure the migration file for 20260303T1100_merge_bob and any function
handling this op use "column.user.avatar").
| export type FieldOutputTypes = { | ||
| readonly user: { | ||
| readonly id: Char<36>; | ||
| readonly email: CodecTypes['pg/text@1']['output']; | ||
| readonly avatar: CodecTypes['pg/text@1']['output'] | null; | ||
| }; | ||
| }; | ||
| export type FieldInputTypes = { | ||
| readonly user: { | ||
| readonly id: CodecTypes['sql/char@1']['input']; | ||
| readonly email: CodecTypes['pg/text@1']['input']; | ||
| readonly avatar: CodecTypes['pg/text@1']['input'] | null; | ||
| }; | ||
| }; |
There was a problem hiding this comment.
Critical: start-contract has wrong fields for merge_bob.
The start contract includes avatar but no phone, indicating this starts from Bob's branch (C3). However, merge_bob should start from Alice's branch (C2, which has phone) and add Bob's avatar.
This confirms the entire migration is inverted:
- Current: starts with
avatar, addsphone→ this is merge_alice behavior - Expected: starts with
phone, addsavatar→ correct merge_bob behavior
This start-contract should have phone instead of avatar, matching Alice's branch as the starting point.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@examples/prisma-next-demo/migration-fixtures/diamond/app/20260303T1100_merge_bob/start-contract.d.ts`
around lines 47 - 60, The start contract's types (FieldOutputTypes and
FieldInputTypes) currently include `avatar` and lack `phone`, which is inverted
for merge_bob; update both FieldOutputTypes.user and FieldInputTypes.user to
replace the `avatar` field with `phone` using the appropriate CodecTypes entries
(for output use CodecTypes['pg/text@1']['output'] | null and for input use
CodecTypes['pg/text@1']['input'] | null) so the contract starts from Alice's
branch (with phone) and then merge_bob can add avatar.
The on-disk diamond fixture is topology-only with synthetic hashes, so it can't be loaded by the live read/graph path. Spec a full offline regeneration via `migration plan` plus a dedicated demo config. Signed-off-by: Will Madden <madden@prisma.io>
Replace topology-only synthetic hashes with full migration packages planned from diamond-contract sources so migration graph and check work via prisma-next.diamond.config.ts. Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: Will Madden <madden@prisma.io>
Most demo migration fixtures are topology-only (unrenderable) and overlap in scenario coverage now that showcase + the renderer exist. Spec keeps a minimal distinctive set, regenerates the survivors offline, and deletes the rest. Signed-off-by: Will Madden <madden@prisma.io>
Delete ten redundant topology-only fixtures and regenerate the five survivors offline via migration plan with full contract snapshots, per-fixture configs, and contract sources. Multi-branch parallel edges are distinct migration packages (different migrationHash, same from/to contract). Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: Will Madden <madden@prisma.io>
The regenerated fixtures committed every intermediate contract state (.prisma + emitted .json/.d.ts) plus per-node start-contract.* — all of it only needed while planning the fixtures, not at render/check time. Keep just the one head .prisma each config references; the graph/check pipeline emits on the fly. Verified: all six fixtures still pass `migration check` and render unchanged. Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: Will Madden <madden@prisma.io>
Each demo graph fixture is now self-contained at fixtures/<name>/ with contract.prisma, migrations/app, and a config-relative prisma-next.config.ts. Removes scattered migration-fixtures/, *-contract/, and per-fixture top-level configs. Signed-off-by: Will Madden <madden@prisma.io>
a0ecf79 to
1adc50b
Compare
Summary
Audits the demo
migration graphfixtures. They are manual QA scenarios (no test wires them), but 15 of 17 were topology-only (synthetic hashes, noend-contract.*) and therefore unrenderable — pointing the CLI at them threw "missing destination contract snapshot" — and most overlapped in scenario coverage now thatshowcase(the comprehensive fixture) and the renderer exist.This regenerates the distinctive survivors so they actually render, and deletes the redundant ones. All regeneration is offline (
prisma-next migration plan, no DB) into complete, hash-consistent fixtures, each with its ownprisma-next.<name>.config.ts.Kept + regenerated (renderable now)
diamond— clean divergence/convergence (regenerated first; reviewed SATISFIED).wide-fan— one node -> 5 children (fan-out width).converging-branches— 3 branches fan in to one node (N-way convergence).skip-rollback— node-skipping rollbacks => crossing back-arcs.long-spine— long vertical spine + late branch (height).multi-branch— 3-way fork + 4 parallel edges (identical from->to, distinct migration hashes).Kept as-is
showcase— the all-in-one (only fixture with forward cross-link, self-edge, disjoint cycle).Deleted (10 redundant)
linear,single-branch,sub-branches,rollback,rollback-continue,multi-rollback-branch,diamond-sub-branch,complex,kitchen-sink,sequential-diamonds— each either a strict subset of a kept fixture (linearinlong-spine,single-branchinmulti-branch,rollbackinskip-rollback) or a combination subsumed byshowcase.Test plan
--tree) via its config with no errors and the intended shapeprisma-next migration checkpasses for every survivor (eachend-contractstorageHash matches itsmigration.jsonto)multi-branch: 4 parallel packages share from->to with distinctmigrationHash, render as 4 parallel edges, no collisionshowcase,diamond, mainprisma-next.config.ts, CLI/packages, andtest-graphs.tsuntouched