feat: compound-PK foreign-key references — grammar + tests (ADR-0043)

Multi-column FK parsing on both surfaces: DSL from P.(a, b) to
C.(x, y) (parenthesized endpoint; single bare form unchanged) and
SQL FOREIGN KEY (a, b) REFERENCES P(x, y) incl. bare-reference
auto-expand. consume_fk_reference + the table-level/ALTER FK
parsers collect column lists; the from P. completion now offers
( (snapshots updated). 12 integration tests in
tests/it/compound_fk.rs cover parse (both surfaces), engine-enforced
FK, arity + partial-PK + per-pair-type-mismatch refusal,
--create-fk per-column, save->rebuild round-trip, undo (one step),
and single-column preservation. Mark T3 [x]; ADR-0043 implemented.
This commit is contained in:
claude@clouddev1
2026-06-09 18:44:37 +00:00
parent b14f0199e9
commit 4752ba29a0
9 changed files with 737 additions and 81 deletions
+21 -23
View File
@@ -399,30 +399,28 @@ since ADR-0027.)
*(Implemented per ADR-0014; auto-fills omitted shortid
columns and validates user-supplied values against the same
alphabet and length range.)*
- [/] **T3** Compound primary keys handled end-to-end (DSL,
- [x] **T3** Compound primary keys handled end-to-end (DSL,
storage, display, FK reference).
*(Partial, verified 2026-06-07: compound-PK **declaration**
(`with pk a(int),b(int)`), **storage** (`primary_key:
Vec<String>`), and **display** are present and tested.
**Missing: a FK that *references* a compound PK** —
`db.rs` resolve/alter FK paths enforce a single
`parent_column: String`; a bare `REFERENCES parent` on a
compound-PK table is refused as ambiguous, and multi-column FK
target syntax is not in the grammar. This is the one open
end-to-end leg of T3 — but a **codebase audit (2026-06-09)
found it is not a small finish**: single-column FK is woven
through ~1520 sites across 6+ files — the
`__rdbms_playground_relationships` table schema, the
`RelationshipSchema` struct, the **`project.yaml` relationship
format** (`RawEndpoint { column }`), both grammar surfaces
(`add 1:n relationship` + SQL `FOREIGN KEY`), the executor's FK
DDL emission, and the per-column type-compat check. It needs a
**migration** (the metadata-table + yaml-format change, F3) and
an **ADR** to settle the design forks: compound-PK matching
policy (must an FK reference *all* PK columns, or a subset?),
per-pair type-compat semantics, the yaml multi-column shape, and
back-compat for existing single-column projects. So this leg is
ADR-first, not a sweep item.)*
*(Done 2026-06-09 via **ADR-0043**: the FK-reference leg now
works on both surfaces — DSL `add 1:n relationship from
P.(a, b) to C.(x, y)` and SQL `FOREIGN KEY (a, b) REFERENCES
P(x, y)` (bare `REFERENCES P` auto-expands to the full PK).
References the parent's full compound PK matched positionally,
per-pair type-compat (ADR-0011); the FK is engine-enforced,
persisted (`columns: [a, b]` in `project.yaml`, comma-joined in
metadata), shown symmetrically by `describe`, and `--create-fk`
creates one child column per parent PK column. The relationship
model went list-based through all six layers, single-column
behaviour preserved (commit `b14f019`); 12 integration tests in
`tests/it/compound_fk.rs` plus the existing single-column suite
as the regression net. The earlier-noted (2026-06-07) breakdown:*
*compound-PK **declaration** (`with pk a(int),b(int)`),
**storage** (`primary_key: Vec<String>`), and **display** were
already present and tested. The FK-reference leg — once an
ADR-first ~1520-site change across the relationship model — is
what ADR-0043 delivered (back-compat dropped by user decision, so
no migration was needed). Subset / non-PK (UNIQUE-target) FK
references stay out of scope.)*
## Visualizations