docs: ADR-0043 implementation-readiness notes from /runda DA pass
DA pass found three change sites the first sketch missed (teaching-echo renderers, --create-fk per-column creation, the auto-name generator) and made explicit the rules the forks left implicit: SQLite FK precondition (compound PK provides the unique index), explicit parent cols must be the PK set (any order, positional), arity/empty/inline-rejection wording, single-in-parens accepted, --create-fk per-column typed to fk_target_type. Expanded the test plan to cover enforcement, auto-expand, undo, round-trip. Fixed a stale 'legacy yaml loads' test line (no back-compat).
This commit is contained in:
@@ -221,14 +221,79 @@ Grouped; each lands behind tests. No migration step.
|
|||||||
column lists; `schema_to_ddl` emits multi-column `FOREIGN KEY
|
column lists; `schema_to_ddl` emits multi-column `FOREIGN KEY
|
||||||
(…) REFERENCES P(…)`; `check_fk_type_compat` loops pairs;
|
(…) REFERENCES P(…)`; `check_fk_type_compat` loops pairs;
|
||||||
bare-reference paths auto-expand to the full PK (D4) or refuse
|
bare-reference paths auto-expand to the full PK (D4) or refuse
|
||||||
with the improved message (`db.rs`).
|
with the improved message; the default relationship-name
|
||||||
6. **Display** — `RelationshipEnd` → column lists; `describe` /
|
generator (`db.rs:6850`) joins the column lists; `--create-fk`
|
||||||
echo render `(a, b) → (x, y)` (`db.rs`, `echo.rs`).
|
creates one child column per parent PK column (`db.rs`).
|
||||||
7. **Tests** — parse (DSL + SQL, single still works, multi parses,
|
6. **Display** — `RelationshipEnd` → column lists; `describe`
|
||||||
arity mismatch errors); worker round-trip (declare a 2-col FK,
|
renders `(a, b) → (x, y)` symmetrically (outbound + inbound,
|
||||||
rebuild, FK enforced, type-mismatch refused); persistence
|
ADR-0013) (`db.rs`, `output_render.rs`).
|
||||||
round-trip (yaml `columns:` reads + writes; a legacy
|
7. **Teaching echo (ADR-0038)** — `render_add_relationship` and
|
||||||
single-column yaml still loads); display.
|
`render_add_relationship_create_fk` (`echo.rs`) go multi-column:
|
||||||
|
the FK line emits `FOREIGN KEY (a, b) REFERENCES P (x, y)`, and
|
||||||
|
`--create-fk` emits **one `ADD COLUMN` line per newly-created
|
||||||
|
child column** (each typed to the matching parent PK column's
|
||||||
|
`fk_target_type`) before the FK line. Copy-paste contract
|
||||||
|
(ADR-0038) holds: every echoed line is runnable advanced SQL.
|
||||||
|
8. **Tests** — parse (DSL + SQL: single-col still works; multi
|
||||||
|
parses; arity mismatch errors; empty `()` rejected; inline
|
||||||
|
`col REFERENCES P(a,b)` rejected with the table-level pointer);
|
||||||
|
worker round-trip (declare a 2-col FK, rebuild, the FK is
|
||||||
|
**enforced** — an insert violating it is refused; per-pair
|
||||||
|
type-mismatch refused; bare-FK **auto-expand** to the parent PK;
|
||||||
|
`--create-fk` creates both child columns); persistence
|
||||||
|
round-trip (a single-col relationship writes `columns: [id]` and
|
||||||
|
reads back; a 2-col writes `columns: [a, b]` and reads back;
|
||||||
|
full save→rebuild reconstructs the FK); **undo** (add a 2-col
|
||||||
|
relationship, undo, it is gone — one step); display
|
||||||
|
(`describe` shows `(a, b) → (x, y)` both directions).
|
||||||
|
|
||||||
|
## Implementation-readiness notes (DA pass, 2026-06-09)
|
||||||
|
|
||||||
|
Verified against the code before build; folded in so the plan is
|
||||||
|
complete.
|
||||||
|
|
||||||
|
- **SQLite precondition holds.** A FK's parent columns must be a
|
||||||
|
PK or a UNIQUE-indexed set. A SQLite `PRIMARY KEY (a, b)` creates
|
||||||
|
the requisite unique index, so `FOREIGN KEY (x, y) REFERENCES
|
||||||
|
P(a, b)` is valid against a compound PK with no extra index.
|
||||||
|
STRICT tables do not change FK rules. (F-A's "full PK" therefore
|
||||||
|
always targets a valid key; a subset would not be unique — the
|
||||||
|
reason F-A excludes it.)
|
||||||
|
- **Explicit parent columns must be exactly the PK set.** Under
|
||||||
|
F-A, `REFERENCES P(<cols>)` is accepted iff `<cols>` is the
|
||||||
|
parent's PK column **set**; any ordering is accepted and maps
|
||||||
|
positionally to the child list (SQLite matches the set to the
|
||||||
|
unique index; the child↔parent pairing is positional). A
|
||||||
|
non-PK, partial, or super-set list is refused with a friendly
|
||||||
|
message naming the parent's actual PK (subset/UNIQUE targets are
|
||||||
|
OOS).
|
||||||
|
- **Arity + emptiness.** Child and parent lists must be equal,
|
||||||
|
non-zero length; a mismatch reports both counts
|
||||||
|
("N child column(s) but M in `P`'s key"). An empty `()` list is
|
||||||
|
a parse error. Inline single-column `col REFERENCES P(a, b)` is
|
||||||
|
refused (one inline column can't satisfy a 2-column key) with a
|
||||||
|
pointer to the table-level `FOREIGN KEY (…)` form (D4).
|
||||||
|
- **DSL `from P.(a)` (single in parens)** is accepted — equivalent
|
||||||
|
to bare `from P.a` — so the parenthesized form is uniform across
|
||||||
|
arities; the bare form stays the idiomatic single-column
|
||||||
|
spelling.
|
||||||
|
- **`--create-fk` is per-column.** When child columns are missing,
|
||||||
|
one is created per parent PK column, each typed to that parent
|
||||||
|
column's `fk_target_type` (ADR-0011) — generalising today's
|
||||||
|
single-column behaviour; the echo mirrors this (sketch step 7).
|
||||||
|
- **Metadata identity unchanged.** `PRIMARY KEY (child_table,
|
||||||
|
child_column)` still holds with the JSON-array string as the
|
||||||
|
key — so a child column **set** still participates in at most one
|
||||||
|
relationship (pre-existing behaviour, now per-set). Distinct
|
||||||
|
sets on the same child table are distinct keys.
|
||||||
|
- **Auto-name generation** (`db.rs:6850`, the `[as <name>]`-less
|
||||||
|
default) is single-column today
|
||||||
|
(`{parent_table}_{parent_column}_to_{child_table}_{child_column}`)
|
||||||
|
— it must join the column lists (e.g.
|
||||||
|
`Orders_a_b_to_Customers_x_y`). A found change site the first
|
||||||
|
sketch missed; added to the executor step.
|
||||||
|
- **Undo / batch unchanged.** One `add 1:n relationship` is one
|
||||||
|
rebuild = one undo step (ADR-0013/0006), independent of arity.
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user