migrate/supabase: translate composite UNIQUE(a,b) instead of silently dropping it (conformance M1) - #309
migrate/supabase: translate composite UNIQUE(a,b) instead of silently dropping it (conformance M1)#309Sorcecoder wants to merge 2 commits into
Conversation
…tly dropping it apply_table_constraint only handled single-column UNIQUE; a table-level UNIQUE(a, b) fell through and vanished, so the migrated app permitted duplicate rows the source forbade — violating the migrator's never-silently-drop promise (docs/ai/19-migrate-supabase.md:7). Capture multi-column groups into PgTable.composite_uniques and emit them as the entity's composite `unique` (issue #115), mapping source columns to the entity's field / belongs_to fk-column names (the shape JC0559 accepts). If a group's column dropped out (e.g. an unmappable-type column), raise a blocking gap for that constraint instead of dropping it — the promise holds either way. Covers both the inline CREATE TABLE constraint and the pg_dump ALTER TABLE ... ADD CONSTRAINT ... UNIQUE(a,b) form (both route through apply_table_constraint).
|
Held for 0.8.0 — not a 0.7.x patch. The semver gate correctly flags this: |
Docs↔codegen conformance sweep — code-wrong bucket. The migrator's headline promise (19-migrate-supabase.md:7) is 'never silently drop — untranslatable becomes a gap.' But a multi-column
UNIQUE(a,b)fell through the single-column guard inapply_table_constraint(pgmodel.rs) andentities.rshardcodedunique: vec![]— so the constraint vanished and the migrated app allowed duplicate rows the source forbade, silently, staying green (no test probed it).Fix: capture multi-column table UNIQUE into
PgTable.composite_uniquesand translate to the entity's compositeunique(reusing the #115Vec<Vec<String>>representation — column mapping is identity). If a column didn't survive translation, raise a Blocking gap instead of dropping — the 'never silently drop' promise holds either way. Covers both inlineUNIQUE(a,b)andALTER TABLE ADD CONSTRAINTforms.Test:
composite_unique_survives_translation_and_an_unrepresentable_one_gaps. No version bump.Follow-up (M1b, not in this PR): a multi-column
CREATE UNIQUE INDEX ON t(a,b)is a separate parse node (CreateIndex) and still drops the same way — same class, tracked separately.