Foreign-key relationships, rebuild-table, polish round

DSL:
- add 1:n relationship [as <name>] from <P>.<col> to <C>.<col>
  [on delete <action>] [on update <action>] [--create-fk]
- drop relationship <name> | from <P>.<col> to <C>.<col>
- show table <name> for re-displaying a structure on demand

Database (ADR-0013):
- Rebuild-table primitive following SQLite's
  ALTER-via-rebuild recipe (foreign_keys=OFF outside tx,
  copy-by-name, foreign_key_check before commit). Reusable for
  B2 (column drops/renames/type changes).
- ReferentialAction enum (no action / restrict / set null /
  cascade); SET DEFAULT awaits column DEFAULTs.
- __rdbms_playground_relationships metadata table -- names,
  auto-generated as <Parent>_<pcol>_to_<Child>_<ccol>.
- Type::fk_target_type() validation at declaration; friendly
  errors for type mismatch, non-PK target, missing column,
  duplicate name.
- describe_table populates symmetric outbound + inbound
  relationship lists. drop_table refuses while inbound
  references exist; outbound metadata cleaned up alongside drop.

App / UI:
- In-line cursor editing in the input field: Left, Right,
  Home, End, Delete, Backspace honoring UTF-8 boundaries.
- PageUp / PageDown scrolls the output buffer; viewport row
  count fed back from the renderer via App::note_output_viewport
  so scroll is capped against the actual visible area
  (regression-tested) and snaps to the bottom on new output.
- Failure messages quote the command portion ("verb target"
  failed: ...) for visual clarity; RelationshipSelector has a
  proper Display impl so "no such relationship" reads cleanly.
- Structure rendering shows References / Referenced by sections.

Docs:
- ADR-0013 covers naming, metadata table, symmetric view, and
  the rebuild-table strategy.
- requirements.md updates: C3 (FK done), B2 (primitive in),
  T3 (compound-PK FK still pending). New entries: I1a (cursor
  editing -- landed), I1b (Ctrl-A/E and readline shortcuts --
  pending), V4 partial scroll, V5 (show family), C3a (modify
  relationship -- deferred).

Tests: 154 passing (140 lib + 14 integration), 0 skipped.
Clippy clean with nursery enabled.
This commit is contained in:
claude@clouddev1
2026-05-07 14:52:51 +00:00
parent c1e52920eb
commit 165068269b
12 changed files with 2632 additions and 56 deletions
+36 -3
View File
@@ -61,6 +61,17 @@ against it.
- [ ] **I1** Multi-line entry that auto-expands; Ctrl-Enter (or
equivalent) submits, plain Enter inserts a newline.
- [ ] **I1a** In-line cursor editing in the input field: Left /
Right arrows move the cursor by character (UTF-8 boundaries
honoured), Home / End jump to the extremes, Delete removes the
character at the cursor, Backspace removes the character
before. Insertion happens at the cursor position. *(Implemented;
multi-line editing per I1 still pending.)*
- [ ] **I1b** Readline-style cursor shortcuts: Ctrl-A / Ctrl-E
as aliases for Home / End for users on keyboards without those
keys (and for ergonomics in command-driven workflows). Likely
followed by Ctrl-W (delete previous word), Ctrl-K (delete to
end), Ctrl-U (delete to start). Pending.
- [ ] **I2** Persistent navigable input history (project-scoped,
with a global rolling history also available).
*(Progress: in-memory navigable history (Up/Down arrows, draft
@@ -108,7 +119,16 @@ against it.
compound), foreign key with `ON DELETE` / `ON UPDATE` referential
actions, indexes, `NOT NULL`, `UNIQUE`, `CHECK`, `DEFAULT`.
*(Progress: PK including compound done at create-table time;
FK/index/NOT NULL/UNIQUE/CHECK/DEFAULT pending.)*
FK with `ON DELETE` / `ON UPDATE` actions done (ADR-0013) —
declared via `add 1:n relationship`; symmetric outbound +
inbound view in the structure renderer; type compatibility
validated at declaration via `Type::fk_target_type()`. Index,
`NOT NULL`, `UNIQUE`, `CHECK`, `DEFAULT` still pending.)*
- [~] **C3a** Modify relationship: `modify relationship <name>
[on delete <action>] [on update <action>]`. Users can achieve
the same via drop + add today; one-step modify is a small
follow-up using the existing rebuild-table machinery. ADR
pending.
- [ ] **C4** Convenience: `create m:n relationship from <T1> to
<T2>` produces an auto-named junction table the user can rename;
pulls primary keys and FK definitions automatically.
@@ -135,6 +155,10 @@ against it.
through a dedicated worker thread per ADR-0010.)*
- [ ] **B2** Schema evolution uses the rebuild-table technique
internally where SQLite `ALTER TABLE` cannot.
*(Progress: rebuild-table primitive landed (ADR-0013) and is
used by `add_relationship` / `drop_relationship`. Reuse for
column drops/renames/type changes pending; the primitive is
designed to support those without further architectural work.)*
- [ ] **B3** Query timeout and cancellation supported (no
cartesian-join-of-doom can hang the app).
*(Progress: the worker-thread architecture is in place; the
@@ -153,8 +177,9 @@ against it.
- [ ] **T3** Compound primary keys handled end-to-end (DSL,
storage, display, FK reference).
*(Progress: DSL grammar (`with pk a:int,b:int`), storage, and
table-info description are all present; pretty display of the
PK in the structure view and FK reference still pending.)*
table-info description are all present; the FK iteration
references single-column PKs only — compound-key FK references
remain pending.)*
## Visualizations
@@ -179,6 +204,14 @@ against it.
based on dimensions; the log is exportable to Markdown so
learners can keep a record of their session. Design and ADR
pending before any implementation.
*(Partial: PageUp / PageDown scrolling of the existing line
buffer is in, with new output snapping the view to the most
recent. The full V4 scope — smart structure rendering, log
styling, Markdown export, scroll indicator — remains pending.)*
- [ ] **V5** `show <kind> [<name>]` family of commands for
redisplaying schema info on demand. *(Progress: `show table
<name>` implemented and reuses the structure-render pipeline;
`show tables`, `show relationships`, etc. pending.)*
## Project lifecycle (per ADR-0004)