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
+18 -3
View File
@@ -182,7 +182,15 @@ const FK_PARENT_COLUMN: Node = Node::Ident {
writes_cte_name: false,
writes_projection_alias: false,
};
static FK_PARENT_COL_NODES: &[Node] = &[Node::Punct('('), FK_PARENT_COLUMN, Node::Punct(')')];
// `( a [, b]* )` — a compound FK references multiple parent columns
// (ADR-0043). The `Repeated` separator handles the commas; a
// single-column FK is the one-element case.
const FK_PARENT_COL_LIST: Node = Node::Repeated {
inner: &FK_PARENT_COLUMN,
separator: Some(&Node::Punct(',')),
min: 1,
};
static FK_PARENT_COL_NODES: &[Node] = &[Node::Punct('('), FK_PARENT_COL_LIST, Node::Punct(')')];
const FK_PARENT_COL_OPT: Node = Node::Optional(&Node::Seq(FK_PARENT_COL_NODES));
// `REFERENCES <parent> [ ( <col> ) ] [on delete/update …]` — the inline
@@ -333,6 +341,13 @@ const FK_CHILD_COLUMN: Node = Node::Ident {
writes_cte_name: false,
writes_projection_alias: false,
};
// `( a [, b]* )` — a compound FK lists multiple child columns
// (ADR-0043); single-column is the one-element case.
const FK_CHILD_COL_LIST: Node = Node::Repeated {
inner: &FK_CHILD_COLUMN,
separator: Some(&Node::Punct(',')),
min: 1,
};
const FK_NAME: Node = Node::Ident {
source: IdentSource::NewName,
role: "fk_name",
@@ -354,7 +369,7 @@ static FOREIGN_KEY_BODY_NODES: &[Node] = &[
Node::Word(Word::keyword("foreign")),
Node::Word(Word::keyword("key")),
Node::Punct('('),
FK_CHILD_COLUMN,
FK_CHILD_COL_LIST,
Node::Punct(')'),
Node::Word(Word::keyword("references")),
FK_PARENT_TABLE,
@@ -374,7 +389,7 @@ static TABLE_FK_NAMED_NODES: &[Node] = &[
Node::Word(Word::keyword("foreign")),
Node::Word(Word::keyword("key")),
Node::Punct('('),
FK_CHILD_COLUMN,
FK_CHILD_COL_LIST,
Node::Punct(')'),
Node::Word(Word::keyword("references")),
FK_PARENT_TABLE,