Skip to content

Commit ee7b756

Browse files
dmealingclaude
andcommitted
refactor(views): unify view DDL into the single schema-diff path
The schema-diff now owns ALL view DDL for every dialect, replacing the parallel computeProjectionMigrations / source-aware-diff emitter. One generator (emitViewDdl via buildProjectionViews) produces every CREATE VIEW; the diff produces create/drop/replace plus a dependency-recreate pass; each dialect renderer emits it. - migrate-ts: port view rendering into the sqlite/d1 emitter, drop the postgres-only guard; add diff Pass 2c (drop+recreate a view around a column-altering change to a table it reads), driven by a new ViewDescriptor.dependsOn; sqlite STAGE_ORDER drop-view=0 (before the recreate-and-copy, mirroring postgres); introspectD1 reads view bodies. - codegen-ts: buildProjectionViews is the single expected-view source (name/body/schema/dependsOn); emitViewDdl gains bodyOnly; resolve JOIN FK/PK to physical columns (naming strategy + @column) instead of a hardcoded snake_case guess; quote identifiers that need it so literal/ kebab columns survive postgres case-folding. - cli: emit all diff changes (tables + views) through one path; delete computeProjectionMigrations + the view-diff stack. Deletes source-aware-diff, view-diff, view-ddl-{postgres,sqlite}, expected-views, projection-migrations and their tests; removes the corresponding migrate-ts barrel exports. Validated: full unit suites green, postgres persistence-conformance (incl. a new recreate-view-on-column-type-change scenario), and a live from-empty platform migrate emitting exactly one correct CREATE VIEW. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 61493b1 commit ee7b756

43 files changed

Lines changed: 742 additions & 1269 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: recreate-view-on-column-type-change
2+
description: |
3+
A view (projection) reads programs.title. Widening title VARCHAR(200) → VARCHAR(500)
4+
is a column-type change postgres REFUSES while a view depends on the column
5+
("cannot alter type of a column used by a view"). The schema-diff's dependency
6+
pass (Pass 2c) must drop the view BEFORE the ALTER and recreate it AFTER, so the
7+
whole migration applies cleanly and the view still returns rows. This pins the one
8+
emission path owning view DDL — no separate view-migration emitter.
9+
10+
seed-metadata: ./states/program-view-v1/
11+
seed-data: |
12+
INSERT INTO "programs" ("id", "title") VALUES (1, 'Foundations'), (2, 'Strength');
13+
14+
target-metadata: ./states/program-view-v2/
15+
16+
expect:
17+
blocked: []
18+
up-contains:
19+
- 'DROP VIEW'
20+
- 'v_program'
21+
- 'ALTER TABLE "programs"'
22+
- 'CREATE VIEW'
23+
apply-up-then-query:
24+
sql: SELECT "id", "title" FROM "v_program" ORDER BY "id"
25+
rows:
26+
- { id: "1", title: "Foundations" }
27+
- { id: "2", title: "Strength" }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"metadata.root": {
3+
"package": "fitness",
4+
"children": [
5+
{ "object.entity": {
6+
"name": "Program",
7+
"children": [
8+
{ "source.rdb": { "@table": "programs" } },
9+
{ "field.long": { "name": "id" } },
10+
{ "field.string": { "name": "title", "@required": true, "@maxLength": 200 } },
11+
{ "identity.primary": { "name": "id", "@fields": "id", "@generation": "increment" } }
12+
]
13+
}},
14+
{ "object.projection": {
15+
"name": "ProgramView",
16+
"children": [
17+
{ "source.rdb": { "@kind": "view", "@table": "v_program" } },
18+
{ "field.long": { "name": "id", "extends": "fitness::Program.id" } },
19+
{ "field.string": { "name": "title", "children": [ { "origin.passthrough": { "@from": "fitness::Program.title" } } ] } },
20+
{ "identity.primary": { "name": "id", "extends": "fitness::Program.id" } }
21+
]
22+
}}
23+
]
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"metadata.root": {
3+
"package": "fitness",
4+
"children": [
5+
{ "object.entity": {
6+
"name": "Program",
7+
"children": [
8+
{ "source.rdb": { "@table": "programs" } },
9+
{ "field.long": { "name": "id" } },
10+
{ "field.string": { "name": "title", "@required": true, "@maxLength": 500 } },
11+
{ "identity.primary": { "name": "id", "@fields": "id", "@generation": "increment" } }
12+
]
13+
}},
14+
{ "object.projection": {
15+
"name": "ProgramView",
16+
"children": [
17+
{ "source.rdb": { "@kind": "view", "@table": "v_program" } },
18+
{ "field.long": { "name": "id", "extends": "fitness::Program.id" } },
19+
{ "field.string": { "name": "title", "children": [ { "origin.passthrough": { "@from": "fitness::Program.title" } } ] } },
20+
{ "identity.primary": { "name": "id", "extends": "fitness::Program.id" } }
21+
]
22+
}}
23+
]
24+
}
25+
}

0 commit comments

Comments
 (0)