feat: ADR-0035 4b — foreign keys in CREATE TABLE
Add foreign keys to advanced-mode SQL CREATE TABLE — the SQL spelling of an ADR-0013 named relationship, created in the same transaction as the table (one undo step). - Grammar: inline `<col> … REFERENCES <parent>[(<col>)] [ON DELETE/UPDATE …]` (a new column constraint) and table-level `[CONSTRAINT <name>] FOREIGN KEY (<col>) REFERENCES …` (two new element branches — both start on a concrete keyword, never a leading Optional, which would abort the element Choice). Referential clauses reuse shared::REFERENTIAL_CLAUSES. - Builder: greedy FK-clause consumption (parens consumed internally so they don't perturb the 4a.3 element-boundary depth tracker); inline FK auto-named, table FK takes an optional CONSTRAINT name. - Worker: do_create_table resolves + validates each FK before building the DDL (self-ref validates against the in-statement columns/PK; bare REFERENCES resolves to the parent's single-column PK, composite -> error; PK-target + Type::fk_target_type compatibility), emits the FOREIGN KEY clause identically to schema_to_ddl, and writes the relationship metadata in the create transaction. - Reuse: name/uniqueness/metadata-insert/type-compat factored into shared helpers; do_add_relationship refactored to use them. - FKs round-trip via the existing relationship plumbing (no new persistence structures); describe surfaces the relationship. Self-references and bare `REFERENCES <parent>` supported (user-confirmed). Self-ref pre-submit indicator wrinkle deferred to 4i (tracked in ADR §13, a code comment, and the plan). DA/runda round added cross-cutting probes (FK survives the add-column rebuild + a later rebuild_from_text; referential actions survive rebuild; drop-child clears the relationship; drop-parent refused; bare self-ref resolves to own PK) — all green, no fixes needed. 27 new tests (grammar/builder + Tier-3). Docs: ADR-0035 Status/§13, README, requirements.md Q1. Tests: 1795 passing, 0 failing, 1 ignored. Clippy clean.
This commit is contained in:
@@ -3,12 +3,13 @@
|
||||
## Status
|
||||
|
||||
Accepted. Design agreed with the user (2026-05-24); the approach is
|
||||
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3** (`CREATE TABLE`
|
||||
with column- and table-level constraints, implemented 2026-05-25 —
|
||||
plans `docs/plans/20260524-adr-0035-sql-ddl-4a.md`,
|
||||
`…-4a2.md`, `…-4a3.md`), so the decision is accepted while the remaining
|
||||
sub-phases (**4b–4i**, §13) continue. This is **Phase 4** of the
|
||||
ADR-0030 roadmap (the
|
||||
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3 / 4b**
|
||||
(`CREATE TABLE` with column- and table-level constraints and foreign
|
||||
keys, implemented 2026-05-25 — plans
|
||||
`docs/plans/20260524-adr-0035-sql-ddl-4a.md`, `…-4a2.md`, `…-4a3.md`,
|
||||
`docs/plans/20260525-adr-0035-sql-ddl-4b.md`), so the decision is
|
||||
accepted while the remaining sub-phases (**4c–4i**, §13) continue. This
|
||||
is **Phase 4** of the ADR-0030 roadmap (the
|
||||
advanced-mode SQL surface), the peer of ADR-0031 (expression grammar),
|
||||
ADR-0032 (`SELECT`), and ADR-0033 (DML). It **clarifies ADR-0030 §4**
|
||||
on how DDL is represented and executed.
|
||||
@@ -351,8 +352,21 @@ ADR-0033's structure:
|
||||
introduces a structure simple mode could never produce, or an
|
||||
expression the structural helper cannot consume — cf. the
|
||||
`UNIQUE`-index flag in 4d and the rename op in 4h.)
|
||||
- **4b — Foreign keys in `CREATE TABLE`.** Inline `REFERENCES` +
|
||||
table-level `FOREIGN KEY` → relationship metadata, one undo step.
|
||||
- **4b — Foreign keys in `CREATE TABLE`.** *(Implemented 2026-05-25 —
|
||||
plan `docs/plans/20260525-adr-0035-sql-ddl-4b.md`.)* Inline
|
||||
`REFERENCES <parent>[(<col>)] [ON DELETE/UPDATE …]` + table-level
|
||||
`[CONSTRAINT <name>] FOREIGN KEY (<col>) REFERENCES …` → ADR-0013
|
||||
relationship metadata, written in the create transaction (one undo
|
||||
step). Reuses the relationship name/uniqueness/metadata helpers
|
||||
shared with `add relationship`; `do_create_table` emits the
|
||||
`FOREIGN KEY` clause identically to `schema_to_ddl`. **Self-references**
|
||||
(parent = the table being created, validated against the in-statement
|
||||
columns/PK) and the **bare `REFERENCES <parent>`** form (resolves to
|
||||
the parent's single-column PK; composite → error) are both supported
|
||||
(user-confirmed). Inline FKs are auto-named; only the table-level form
|
||||
takes `CONSTRAINT <name>`. PK-target only (UNIQUE-target deferred with
|
||||
`add relationship`); `Type::fk_target_type` (ADR-0011) governs type
|
||||
compatibility.
|
||||
- **4c — `DROP TABLE [IF EXISTS]`** → `SqlDropTable` (cascade parity;
|
||||
`IF EXISTS` no-op-with-note, §4).
|
||||
- **4d — `CREATE [UNIQUE] INDEX` / `DROP INDEX`** → `SqlCreateIndex`
|
||||
@@ -370,7 +384,17 @@ ADR-0033's structure:
|
||||
- **4h — `ALTER TABLE … RENAME TO`** (the §6 new low-level op).
|
||||
- **4i — Verification sweep.** Typing-surface + matrix coverage,
|
||||
engine-neutral error pass, undo-parity check (one step per
|
||||
statement), `help`/usage for the new forms.
|
||||
statement), `help`/usage for the new forms. **Carried in from earlier
|
||||
slices:** (a) refresh the `CREATE TABLE` help/usage skeleton for the
|
||||
4a.2 `DEFAULT`/`CHECK`/composite-`UNIQUE`, 4a.3 table-`CHECK`, and 4b
|
||||
FK forms (deferred from each); (b) `describe` display of table-level
|
||||
constraints (composite `UNIQUE` + table `CHECK`); (c) **4b self-ref
|
||||
FK indicator** — a `CREATE TABLE` with a self-referencing FK
|
||||
(`references <self>`) parses + executes correctly, but the pre-submit
|
||||
schema-existence diagnostic falsely flags the not-yet-created self
|
||||
table as unknown (the FK parent slot is `IdentSource::Tables`). Make
|
||||
the diagnostic treat a FK parent equal to the `CREATE TABLE` target as
|
||||
valid, so the indicator stops lying for self-references.
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user