feat(examples): regenerate the diamond migration fixture as a complete, renderable set#677
feat(examples): regenerate the diamond migration fixture as a complete, renderable set#677wmadden-electric wants to merge 3 commits into
Conversation
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.
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>
📝 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
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Summary
The
examples/prisma-next-demo/migration-fixtures/diamondfixture was topology-only — each node had justmigration.json+ops.jsonwith synthetic hashes and no contract snapshots — so the live read/graph path (readGraphNodeEndContract) couldn't load it (missing destination contract snapshot). Because the hashes were synthetic with no backing contract content, the only correct fix was to regenerate the whole fixture so every artifact agrees.This regenerates
diamondoffline (viaprisma-next migration plan, no DB) into a complete, internally-consistent diamond and adds a dedicated demo config so it renders via--configwithout touching the main demo config.migration.json,ops.json,end-contract.json,end-contract.d.ts,migration.ts; branched/merge nodes also carrystart-contract.*, matching theshowcasefixture).∅ → C1(init)C1 → C2(alice_add_phone, +phone) /C1 → C3(bob_add_avatar, +avatar)C2 → C5(merge_alice) /C3 → C5(merge_bob) — both land on C5refs/prod.json → C5vectorextension, so there are no extension-space packages.prisma-next.diamond.config.ts(mirrorsprisma-next.showcase.config.ts); the mainprisma-next.config.tsis untouched.Rendered graph (
migration graph --config ./prisma-next.diamond.config.ts)Test plan
prisma-next migration check --config ./prisma-next.diamond.config.ts→{ ok: true, "All checks passed" }prisma-next migration graph --config ./prisma-next.diamond.config.ts(default +--tree) renders a clean 5-node/5-edge diamond, no errorsend-contractstorageHash matches itsmigration.jsonto;merge_alice.to == merge_bob.to == refs/prod.json.hashdiamond-contract/**,prisma-next.diamond.config.ts,migration-fixtures/diamond/**Summary by CodeRabbit
New Features
Chores