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
|
||||
(…) REFERENCES P(…)`; `check_fk_type_compat` loops pairs;
|
||||
bare-reference paths auto-expand to the full PK (D4) or refuse
|
||||
with the improved message (`db.rs`).
|
||||
6. **Display** — `RelationshipEnd` → column lists; `describe` /
|
||||
echo render `(a, b) → (x, y)` (`db.rs`, `echo.rs`).
|
||||
7. **Tests** — parse (DSL + SQL, single still works, multi parses,
|
||||
arity mismatch errors); worker round-trip (declare a 2-col FK,
|
||||
rebuild, FK enforced, type-mismatch refused); persistence
|
||||
round-trip (yaml `columns:` reads + writes; a legacy
|
||||
single-column yaml still loads); display.
|
||||
with the improved message; the default relationship-name
|
||||
generator (`db.rs:6850`) joins the column lists; `--create-fk`
|
||||
creates one child column per parent PK column (`db.rs`).
|
||||
6. **Display** — `RelationshipEnd` → column lists; `describe`
|
||||
renders `(a, b) → (x, y)` symmetrically (outbound + inbound,
|
||||
ADR-0013) (`db.rs`, `output_render.rs`).
|
||||
7. **Teaching echo (ADR-0038)** — `render_add_relationship` and
|
||||
`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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user