diff --git a/docs/adr/0016-pretty-table-rendering.md b/docs/adr/0016-pretty-table-rendering.md index 3a2b3d8..26dfc10 100644 --- a/docs/adr/0016-pretty-table-rendering.md +++ b/docs/adr/0016-pretty-table-rendering.md @@ -197,6 +197,16 @@ Referenced by: The relationship sections retain today's plain-text format to leave room for the future relationship-rendering ADR. +> **Superseded.** ADR-0044 replaced this prose block with compact +> diagrams on relationship-subject surfaces (`show table`, +> `add`/`drop relationship`). **ADR-0050 (2026-06-12, issue #28)** then +> removed the relationship block entirely from incidental-DDL structure +> echoes (`create table`, `add`/`drop`/`rename`/`change column`, +> `add`/`drop index`) — those render structure only — and **deleted the +> prose renderer**. The `References:` / `Referenced by:` format above is +> retained here as documentation/provenance should the OOS-7 +> always-prose display setting ever be built. + ### 6. Theme integration Theme colors apply to the box-drawing characters via the diff --git a/docs/adr/0044-relationship-visualization.md b/docs/adr/0044-relationship-visualization.md index 1210646..dfbb203 100644 --- a/docs/adr/0044-relationship-visualization.md +++ b/docs/adr/0044-relationship-visualization.md @@ -103,6 +103,10 @@ Prose-retained surfaces (**unchanged** from ADR-0016 §5): `add`/`drop index` — keep the terse `References:` / `Referenced by:` prose. A simple `add column` on a heavily-related table should not print a wall of diagrams. + *(**Superseded 2026-06-12 by ADR-0050** (issue #28): these incidental + DDL echoes now render **structure only** — no relationship block at + all, neither prose nor diagram. The prose renderer was deleted. The + diagram surfaces below are unchanged.)* So this **partially supersedes ADR-0016 §5**: the prose block is replaced by diagrams on the relationship-subject surfaces and diff --git a/docs/adr/0050-incidental-ddl-confirmations-omit-relationships.md b/docs/adr/0050-incidental-ddl-confirmations-omit-relationships.md new file mode 100644 index 0000000..c67e6fc --- /dev/null +++ b/docs/adr/0050-incidental-ddl-confirmations-omit-relationships.md @@ -0,0 +1,119 @@ +# ADR-0050: Incidental-DDL confirmations omit relationship info (structure-only) + +## Status + +**Accepted + implemented 2026-06-12 (issue #28).** Closes Gitea **#28**. +Both forks below were escalated to the user and user-chosen before any +code was written; implemented test-first. **Supersedes** the +incidental-DDL clause of **ADR-0044 §1** and the part of **ADR-0016 §5** +that placed a relationship block under every structure echo. The +diagram behaviour ADR-0044 introduced for relationship-subject surfaces +is unchanged. + +## Context + +ADR-0016 §5 rendered a structure box followed by a plain-text +`References:` / `Referenced by:` relationship block under **every** +structure echo. ADR-0044 §1 split that by surface: + +- **Relationship-subject surfaces** — `show table `, + `add 1:n relationship`, `drop relationship`, `show relationship ` + — render relationships as compact **diagrams** (the user asked for, or + acted on, a relationship). +- **Incidental DDL auto-shows** — `create table`, `add`/`drop`/`rename`/ + `change column`, `add`/`drop index` — kept the terse **prose** block, + with the rationale *"a simple `add column` on a heavily-related table + should not print a wall of diagrams."* + +Issue #28 reconsiders the deeper question ADR-0044 did not ask: should +an incidental-DDL confirmation show relationship information **at all**? +Owner preference: **no.** A confirmation echo should focus on the change +just made — the new / updated structure — not re-print the table's +relationships, which the user did not touch. The terse prose was the +lesser of "prose vs diagram", but the right answer for these surfaces is +**neither**. + +## Decision + +**Incidental-DDL confirmation echoes render the structure only** — the +table-name header, the column / type / constraints box, the `Indexes:` +section, and the constraint section — with **no relationship section** +(neither prose nor diagram). + +- **Scope: all incidental DDL** (user-chosen, over "just `add column`"): + `create table`, `add column`, `drop column`, `rename column`, + `change column`, `add index`, `drop index`. The rule is uniform — a + structural edit confirms structure, never relationships. (For a + freshly `create`d table the relationship section was empty anyway; the + rule still applies for consistency of the mental model.) +- **Relationship-subject surfaces are unchanged.** `show table`, + `add`/`drop relationship`, and `show relationship ` still render + diagrams. Relationships appear **only** when the user asks for them + (`show table` / `show relationship`) or acts on one + (`add`/`drop relationship`). +- **No information is lost.** Anything dropped from an incidental echo is + one `show table ` away. + +### Mechanism + +The `handle_dsl_success` routing (`app.rs`) is **unchanged**: it still +sends relationship-subject commands to the diagram renderer and +everything else to `render_structure`. The change is entirely inside +`render_structure` (`output_render.rs`): it no longer appends the +relationship block — `render_structure` = structure box + indexes + +constraints. All of `render_structure`'s callers are incidental DDL +(verified), so this single edit covers the whole scope with no +per-command branching. + +### Prose renderer disposition + +The orphaned prose renderer (`relationship_prose_lines`, and its +sole helper `cols_disp`) is **deleted** (user-chosen, over retaining it +dormant). After this change no shipped surface renders the prose form, +so keeping it would be dead code. The prose format remains documented in +**ADR-0016 §5** and in git history; if ADR-0044's OOS-7 user-configurable +"always-prose" display setting is ever built, it re-introduces the ~30 +lines from that provenance. + +## Forks (all user-chosen) + +- **Scope:** *all incidental DDL*, not just `add column` — the owner's + rationale ("confirm the change, not untouched relationships") applies + uniformly, gives a clean mental model, and is the simpler edit (remove + one call vs a per-command flag). +- **Prose renderer:** *delete* it — no dead code — over retaining a + public, tested-but-uncalled renderer for the speculative OOS-7 setting. + +## Consequences + +- Incidental confirmations are shorter and on-topic; a heavily-related + table no longer prints a relationship wall after `add column`. +- One relationship renderer (prose) leaves the codebase; the diagram + renderer (ADR-0044) is the only relationship render path that ships. +- `requirements.md` is unaffected (this is an ADR-tracked refinement of a + decided area, like ADR-0044 itself); the change is cross-referenced + from the commit + this ADR. + +## Tests + +- **Unit (`output_render.rs`):** the prose-asserting test + `render_structure_with_relationships` (+ its snapshot) is removed; a + new test asserts `render_structure` on a description **carrying** both + inbound and outbound relationships emits the structure box but **no** + `References:` / `Referenced by:` lines. The box/index/constraint tests + are unaffected (their descriptions have no relationships). +- **Integration (`walking_skeleton.rs`):** the misnamed + `add_relationship_flow_shows_inbound_section_on_parent` (which sends an + `AddColumn` and asserted the inbound prose) is inverted + renamed to + assert the add-column confirmation shows the structure but **omits** + the relationship prose. +- **Unchanged:** the diagram tests (`show_list.rs` `show table`, + `walking_skeleton.rs` `add relationship`) still pass — they already + assert prose is absent and diagrams are present. + +## Out of scope + +- The diagram form and its per-surface defaults (ADR-0044) — unchanged. +- The OOS-7 user-configurable display setting (always-prose / -diagram / + auto-by-width) — still a future follow-up; this ADR removes the prose + *renderer*, not the *idea* of a prose mode. diff --git a/docs/adr/README.md b/docs/adr/README.md index 9176b14..97253f2 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -55,3 +55,4 @@ This directory contains the project's ADRs, recorded per - [ADR-0047 — Demonstration overlay layer (keystroke badges + step captions)](0047-demonstration-overlay-layer.md) — **Accepted 2026-06-10; implemented 2026-06-11, phased A→B→C (closes Gitea #22)** (commits `f879d54`→`2d0f4b2`; no `requirements.md` item — tracked by issue + ADR per convention; all forks user-confirmed + a pre-build `/runda` pass that produced 10 tightening findings and a whole-implementation `/runda` pass that returned PASS, no blockers). An in-app **demonstration mode** (`--demo` flag / `RDBMS_PLAYGROUND_DEMO` env, **off by default, zero footprint when off**) that renders two transient overlays so `autocast` screencasts — and live teaching, and a future guided-lesson system — can show otherwise-invisible interactions. **Keystroke badges** (`[TAB]`, `[ENTER]`, `[UP]`, …): **automatic, app-detected** over a fixed set of glyph-less keys (the app already sees every key, so it re-records for free), label via a pure `demo_badge_label(&KeyEvent)`; the badge **auto-expires on a ~1.5 s timer** that extends the runtime's existing time-boxed-`recv` arm condition (`debounce.is_armed() || badge_pending`; expiry `Instant` in the runtime, `App.demo_badge` the render mirror — mirroring the `input` vs `input_indicator` split). **Step captions**: a **stealth, control-code-delimited input buffer** toggled by **`Ctrl+]`** (byte `0x1D` → arrives as `Char('5')+CONTROL`, verified against crossterm 0.29 `parse.rs:110-113`; chosen over `Ctrl+!`, which is **not a single ASCII byte so autocast cannot send it** — the same wall as arrow keys, R4) — typed characters accumulate **invisibly** (prompt untouched, no echo/history), `Backspace` edits, other keys inert, a second `Ctrl+]` **commits** to the caption box (empty commit dismisses); lives in pure-sync `App::update()`, **intercepted before the modal gate** so captions/badges work **over the load picker** (the `#24` projects cast). Both render as **floating flat black-on-yellow rectangles** (solid fill, **no border glyphs** — a one-cell text margin, deliberately unlike the app's bordered panels; user decision post-build, `2d0f4b2`) **at the output panel's inner bottom-right**, drawn **last over modals**, badge **stacked above** the caption, **no layout reflow**; caption **word-wraps to ≤ 3 lines** (3–5 rows), badge fixed 3 rows; clamp/skip guard for tiny terminals; a new **`App.last_output_area: Rect`** (set in `render_output_panel`) gives the top-level draw the anchor. Caption persists **until the next keystroke**; badge suppressed while capturing. Forks all user-chosen: `--demo` activation (vs hidden command / chord); automatic badges (vs scripted); stealth buffer (vs typed-command / preloaded-file); floating bottom-right boxes (vs HUD / banner / subtitle); `Ctrl+]` trigger; wrap-to-3-line captions; ~1.5 s badge / next-keystroke caption timing. Tested test-first across Tier 1 (label fn, capture state machine incl. over-modal + demo-off gate, nearest-deadline helper), Tier 2 (insta snapshots: badge/caption/both-stacked at 90×26 light+dark, short-terminal clamp), Tier 3 (`--demo` plumbing, badge set/suppressed, caption-without-input wiring), CLI (`--demo` parse + env fallback) — with an **honest limit** noted: the `tokio` timer wiring inside `run_loop` is exercised via the pure pieces + Tier-3 plumbing, not a standalone integration test of the timeout (same posture as the existing `IndicatorDebounce`). One intentional, user-acknowledged behaviour: `Ctrl-C` is inert while capturing (every non-`Ctrl+]` key is, by spec). Final tally **2290 passing / 0 failing / 0 skipped** (1 long-standing ignored doctest), clippy clean. OOS: scripted/manual badge push; badges for glyph keys; configurable styling/placement; the guided-lesson system itself (own ADR); cross-session/-switch persistence; localised caption content; arrow-only cast interactions (output-pane scroll); wiring the overlays into the website `casts.mjs` scripts (website-branch follow-up). Implementation phased **A** (`--demo` plumbing) → **B** (badges) → **C** (captions) + a flat-rectangle restyle - [ADR-0048 — `seed` fake-data generation command](0048-seed-fake-data-generation.md) — **Accepted 2026-06-11; Phase 1 + Phase 2 implemented 2026-06-11** (Phase 1 commits `202e25a`→`fbd219b`; design settled with the user across an extended fork dialogue, hardened by a pre-build `/runda` pass (six blockers folded in), a post-implementation `/runda` pass (eight gaps closed — FK/shortid determinism so **D4 holds with no exceptions**, plus six untested ADR decisions), and a Phase-2 pre-build `/runda` pass (which caught the no-date-literal-token reality → the D2 quoted-dates amendment), and a post-implementation `/runda` pass (which added a friendly error for a bounded override on a UNIQUE column — see D2); **2400 tests pass, clippy clean**). Closes `requirements.md` **SD1** and the core of **SD2**; closes the `seed` half of **A1**. **Phase 1 shipped:** whole-row `seed [count] [--seed ]` with realistic name-aware generation (the `fake` crate + a type-gated heuristic catalogue, table-context name disambiguation, hand-rolled `product` generator, bounded dates), identifier + constraint uniqueness incl. junction distinct-combos, FK sampling from existing parent rows (empty-parent error), `IN`-CHECK derivation + complex-CHECK advisory, a required-column block guard, `--seed` reproducibility (serial/FK/shortid all deterministic), undo as one batch step, replay as a data write, a capped auto-show preview, the enum/CHECK advisory, and an O(N) single-transaction insert path. **Phase 2 shipped (2026-06-11):** the `set` override clause (D2 — fixed value / pick-list / `as ` / `between` range, **quoted** dates per the D2 amendment, type-aware, override drops the column from the advisory) and the `
.` column-fill form (D1 form 2 — an UPDATE over existing rows, refusing PK/autogen targets, empty-table no-op, FK/unique-respecting, one undo step), with the new `KNOWN_GENERATORS` vocabulary (D9), a range `Generator`, full completion/highlight (`HighlightClass::Function`)/validity (`IdentSource::Generators`)/help/pedagogy wiring, and the D13 advisory's Phase-2/3 wording. Further SD2 increments (custom generators, NULL injection, multi-locale, recursive auto-seed) out of scope. Closes `requirements.md` **SD1** and the core of **SD2**; closes the `seed` half of **A1** (the other being `hint`/**H2**). A dedicated `seed` command (own AST variant + `do_seed` executor, **both modes**) generating **realistic, name-aware** fake data. Two forms: **`seed
[count]`** (new rows, default **20**, capped) and **`seed
.`** (fill a column on existing rows, an UPDATE). Generation adds the **`fake` crate** (v5, English) driven by a **type-gated, token-matched name-heuristic catalogue** (~30 patterns, documented false-positive guards), with **table-context** disambiguating the `name`/`title` family (`products.name`→product, `users.name`→person, `vendors.name`→company), a **hand-rolled `product` generator** (`fake` has no commerce module), **bounded dates** (`date`/`timestamp`/`dob`/`*_at` recognised, recent windows — never "all of history"), the **identifier family** (`id`/`code`/`ref`/`number`, non-FK/non-PK) → **unique sequential**, and **enum-ish names** (`role`/`status`/`type`/…) left generic + a **post-seed Hint advisory** pointing at `set … in (…)`. A **`set` override clause** — `= value` / `in (a,b,c)` / `as ` / `between a and b` (numeric **and** date), reusing ADR-0026 operators — answers the heuristic-miss case. **`--seed `** makes runs reproducible (and enables exact-value tests). **FK** columns sampled uniformly from existing parent rows (**empty parent → friendly error**, no recursion v1); **junction/compound-PK** tables seeded with **distinct combinations**, capped + noted (SD1). A **required-column block guard** refuses rather than NULL-violate a `NOT NULL` column it can't fill (e.g. `NOT NULL blob`). Full ambient wiring (completion incl. a new generator-name vocabulary highlighted as `tok_function`, hints, `help seed`, ADR-0042 near-miss matrix, ADR-0027 validity); **no DSL→SQL teaching echo** (seed is a utility command, not a SQL twin). Honours **X5** — `do_seed` reuses insert/update *mechanics as helpers*, not by emitting `Command::Insert`. Implementation phased: (1) core whole-row seed → (2) `set` overrides → (3) column-fill. Deferred (future SD2): recursive auto-seed, NULL injection, multi-locale, user-defined custom generators, full per-column report. **Amendment 1, 2026-06-12** (issues #33/#34): two additive D7 catalogue rules — **year-as-int** (`year`/`*_year`/`published`/`founded` → a bounded `int` year, 1950–2025, or the `dob`-style birth window 1945–2007 for `birth`/`born`/`dob`; fixes nonsense like `9419`; `int`-gated, after the quantity rule so `year_count` stays a count; two new `YearRecent`/`YearBirth` generators, *not* added to the D9 vocabulary) and **conventional choice sets** (`priority`/`prio`, `severity`, `rating`/`stars` → type-gated built-in `PickFrom` value sets reusing the existing generator; `priority` leaves `ENUM_TOKENS`). `status` is **deliberately excluded** (user-confirmed — values too domain-specific; keeps the D12 "don't guess" + advisory); a user `IN`-CHECK still wins. Website `seed` cast re-record tracked on the `website` branch - [ADR-0049 — Input-field readline keymap: Esc-clear + Ctrl-A/E/W/K/U (I1b)](0049-input-field-readline-keymap.md) — **Accepted + implemented 2026-06-12 (issue #29)**, closes Gitea **#29** and the deferred **I1b** readline requirement. **Amends ADR-0046**, which listed "readline shortcuts (I1b)" as out-of-scope — that item is now in scope and decided here; orthogonal to ADR-0003's input-*mode* model and extends the I1a single-line cursor editing already shipped. Binds, in the input field (non-modal, non-nav, both modes): **`Esc`** clears a partly-typed command (empty buffer, cursor→0, scroll→0); **`Ctrl-A`/`Ctrl-E`** alias Home/End (line start/end); **`Ctrl-W`** deletes the previous word (readline-style — eats trailing whitespace then the preceding non-whitespace run, UTF-8-safe on char boundaries, only back to the cursor); **`Ctrl-K`** kills to end of line; **`Ctrl-U`** kills to start. **Esc precedence:** a live Tab-completion memo still wins (Esc undoes the completion first, ADR-0022; Esc clears only when no memo) — Esc-once backs out the completion, Esc-again clears. Forks all user-chosen: **single-Esc-clears** (not double-Esc — discoverable over accident-proof; an unsubmitted draft can be lost, a submitted line is always in history); the **full I1b set** (not just the issue's literal Ctrl-A/E + Esc); a **new ADR** (not an ADR-0046 amendment / no-ADR). Cursor-only keys (Ctrl-A/E) leave history navigation intact like Home/End; buffer-mutating keys (Esc-clear, Ctrl-W/K/U) end it like Backspace. Helpers `clear_input`/`delete_prev_word`/`kill_to_end`/`kill_to_start` in `src/app.rs`; **22 new Tier-1 tests, 2458 pass / 0 fail / 0 skip (1 ignored), clippy clean**. OOS: on-screen keybinding hints (issue #27 owns surfacing per-focus keybindings in the bottom status line — this ADR makes the keys *work*, #27 makes them *discoverable*); demo-mode badges for the new chords (ADR-0047 follow-up — Esc already badges `[ESC]`, the glyph-less Ctrl-chords are flagged but not added); multi-line input (I1); word-wise cursor motion (Alt-B/F) / transpose / yank +- [ADR-0050 — Incidental-DDL confirmations omit relationship info (structure-only)](0050-incidental-ddl-confirmations-omit-relationships.md) — **Accepted + implemented 2026-06-12 (issue #28)**, closes Gitea **#28**. **Supersedes** the incidental-DDL clause of **ADR-0044 §1** and the relationship-block half of **ADR-0016 §5**. Incidental-DDL confirmation echoes (`create table`, `add`/`drop`/`rename`/`change column`, `add`/`drop index`) now render **structure only** — header + column box + `Indexes:` + constraints — with **no `References:` / `Referenced by:` block** (neither prose nor diagram), even when the table carries relationships the user did not touch. Rationale (owner): a confirmation echo reports the change just made, not untouched relationships; ADR-0044's terse prose was the lesser of "prose vs diagram", but the right answer for these surfaces is **neither**. **Relationship-subject surfaces are unchanged** — `show table`, `add`/`drop relationship`, `show relationship` still render ADR-0044 diagrams; relationships appear only when the user asks for (`show table`) or acts on (`add`/`drop relationship`) one, and are one `show table ` away — **no information lost**. Forks both user-chosen: **scope = all incidental DDL** (not just `add column` — the rationale is uniform, the mental model clean, and it's the simpler edit) and **delete the prose renderer** (not retain it dormant — no dead code). **Mechanism:** the `handle_dsl_success` `matches!` routing is unchanged (relationship-subject → diagrams; else → `render_structure`); the change is one line inside `render_structure` (`output_render.rs` — drop the relationship-block call) since all its callers are incidental DDL, plus deletion of the orphaned `relationship_prose_lines` + `cols_disp` helpers. The prose format survives in ADR-0016 §5 + git history for a future OOS-7 always-prose setting. **Tests:** the prose-presence unit test + its snapshot removed; a new unit test asserts `render_structure` on a description carrying **both** inbound and outbound relationships emits the box but no prose; the misnamed `add_relationship_flow_shows_inbound_section_on_parent` integration test (which sent an `AddColumn`) inverted + renamed to assert the add-column echo omits the prose; the diagram tests (`show table`, `add relationship`) unaffected. **2458 pass / 0 fail / 0 skip (1 ignored), clippy clean**. `requirements.md` unaffected (ADR-tracked refinement of a decided area, like ADR-0044 itself) diff --git a/src/app.rs b/src/app.rs index e9c3e74..e414642 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2110,8 +2110,10 @@ impl App { // ADR-0044 §1 "relationship-relevant" reach: when a // relationship is the subject of the command (`show table`, // `add`/`drop relationship`), render the table's - // relationships as compact diagrams; every other DDL echo - // keeps the prose `References:` / `Referenced by:` form. + // relationships as compact diagrams. Every other (incidental + // DDL) echo renders structure only — no relationship block + // at all (ADR-0050, issue #28; supersedes ADR-0044 §1's + // prose retention for these surfaces). if matches!( command, Command::ShowTable { .. } diff --git a/src/output_render.rs b/src/output_render.rs index 24554c4..ed00a6d 100644 --- a/src/output_render.rs +++ b/src/output_render.rs @@ -71,27 +71,22 @@ pub fn render_data_table(data: &DataResult) -> Vec { render_table(&header_cells, &body, &alignments) } -/// Render a table-structure listing. +/// Render an incidental-DDL structure echo (ADR-0050, issue #28). /// -/// Produces a header line (``), the schema table -/// itself, and — for a structure that has FK relationships -/// — `References:` / `Referenced by:` blocks below as plain -/// indented text (relationship visualization is its own -/// future ADR per §5 OOS-1). -/// Display a relationship-endpoint column list (ADR-0043): the bare -/// column for a single-column FK, `(a, b)` for a compound one. -fn cols_disp(cols: &[String]) -> String { - if cols.len() == 1 { - cols[0].clone() - } else { - format!("({})", cols.join(", ")) - } -} - +/// Produces a header line (``), the schema table, the +/// `Indexes:` section, and the constraint section — **structure only**. +/// Relationship information is deliberately omitted: a confirmation +/// echo for a structural edit (`create table`, `add`/`drop`/`rename`/ +/// `change column`, `add`/`drop index`) reports the change just made, +/// not the table's relationships, which the user did not touch. The +/// relationship-subject surfaces (`show table`, `add`/`drop +/// relationship`) render diagrams via [`render_structure_with_diagrams`] +/// instead; relationships are one `show table ` away. ADR-0050 +/// supersedes ADR-0044 §1's "incidental DDL keeps prose" and the +/// relationship-block half of ADR-0016 §5. #[must_use] pub fn render_structure(desc: &TableDescription) -> Vec { let mut out = structure_box_lines(desc); - out.extend(relationship_prose_lines(desc)); out.extend(index_lines(desc)); out.extend(constraint_lines(desc)); out @@ -118,41 +113,6 @@ fn structure_box_lines(desc: &TableDescription) -> Vec { out } -/// The `References:` / `Referenced by:` prose blocks (ADR-0016 §5), -/// retained for the incidental DDL echoes (ADR-0044 §1). -fn relationship_prose_lines(desc: &TableDescription) -> Vec { - let mut out: Vec = Vec::new(); - if !desc.outbound_relationships.is_empty() { - out.push("References:".to_string()); - for r in &desc.outbound_relationships { - out.push(format!( - " {} → {}.{} ({}, on delete {}, on update {})", - cols_disp(&r.local_columns), - r.other_table, - cols_disp(&r.other_columns), - r.name, - r.on_delete, - r.on_update, - )); - } - } - if !desc.inbound_relationships.is_empty() { - out.push("Referenced by:".to_string()); - for r in &desc.inbound_relationships { - out.push(format!( - " {}.{} → {} ({}, on delete {}, on update {})", - r.other_table, - cols_disp(&r.other_columns), - cols_disp(&r.local_columns), - r.name, - r.on_delete, - r.on_update, - )); - } - } - out -} - /// Indexes section (ADR-0025), only when the table carries a /// user-created index. A UNIQUE index is marked `[unique]` (ADR-0035 /// §4d). @@ -1591,11 +1551,23 @@ mod tests { } #[test] - fn render_structure_with_relationships() { + fn render_structure_omits_relationship_prose() { + // ADR-0050 (issue #28): the incidental-DDL structure echo never + // carries the `References:` / `Referenced by:` block, even when + // the description carries both inbound and outbound + // relationships. (Relationship-subject surfaces render diagrams + // via `render_structure_with_diagrams`, not this function.) let desc = TableDescription { name: "Customers".to_string(), columns: vec![col("id", Type::Serial, true, false)], - outbound_relationships: Vec::new(), + outbound_relationships: vec![RelationshipEnd { + name: "cust_region".to_string(), + other_table: "Regions".to_string(), + other_columns: vec!["id".to_string()], + local_columns: vec!["region_id".to_string()], + on_delete: ReferentialAction::NoAction, + on_update: ReferentialAction::NoAction, + }], inbound_relationships: vec![RelationshipEnd { name: "cust_orders".to_string(), other_table: "Orders".to_string(), @@ -1609,15 +1581,14 @@ mod tests { check_constraints: Vec::new(), }; let out = render_structure(&desc).join("\n"); - assert!( - out.contains("Referenced by:"), - "expected inbound relationship section:\n{out}", - ); - assert!( - out.contains("Orders.cust_id → id"), - "expected inbound relationship line:\n{out}", - ); - assert_snapshot!(out); + // The structure box still renders. + assert!(out.contains("Customers"), "structure header:\n{out}"); + assert!(out.contains("│ id"), "column row:\n{out}"); + // No relationship block in either direction. + assert!(!out.contains("References:"), "no outbound prose:\n{out}"); + assert!(!out.contains("Referenced by:"), "no inbound prose:\n{out}"); + assert!(!out.contains("Orders.cust_id"), "no prose line:\n{out}"); + assert!(!out.contains("Regions"), "no prose line:\n{out}"); } #[test] diff --git a/src/snapshots/rdbms_playground__output_render__tests__render_structure_with_relationships.snap b/src/snapshots/rdbms_playground__output_render__tests__render_structure_with_relationships.snap deleted file mode 100644 index f0d764c..0000000 --- a/src/snapshots/rdbms_playground__output_render__tests__render_structure_with_relationships.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: src/output_render.rs -expression: out ---- -Customers -┌──────┬────────┬─────────────┐ -│ Name │ Type │ Constraints │ -├──────┼────────┼─────────────┤ -│ id │ serial │ PK │ -└──────┴────────┴─────────────┘ -Referenced by: - Orders.cust_id → id (cust_orders, on delete cascade, on update no action) diff --git a/tests/it/walking_skeleton.rs b/tests/it/walking_skeleton.rs index 98b8400..5793393 100644 --- a/tests/it/walking_skeleton.rs +++ b/tests/it/walking_skeleton.rs @@ -494,7 +494,12 @@ fn add_relationship_flow_shows_parent_side_with_inbound_section() { } #[test] -fn add_relationship_flow_shows_inbound_section_on_parent() { +fn add_column_confirmation_omits_relationship_prose() { + // ADR-0050 (issue #28): an incidental-DDL confirmation echo (here + // `add column`) renders the structure only — never the + // `References:` / `Referenced by:` relationship block — even when + // the table carries relationships the user did not touch. The + // relationships remain one `show table` away. let mut app = App::new(); let customers = TableDescription { name: "Customers".to_string(), @@ -535,8 +540,17 @@ fn add_relationship_flow_shows_inbound_section_on_parent() { echo: None, }); let rendered = rendered_text(&mut app, &Theme::dark(), 80, 24); - assert!(rendered.contains("Referenced by:"), "{rendered}"); - assert!(rendered.contains("Orders.CustId → Id"), "{rendered}"); + // The structure box still renders (table name + the column box from + // the returned description). + assert!(rendered.contains("Customers"), "structure header:\n{rendered}"); + assert!(rendered.contains("Constraints"), "structure box:\n{rendered}"); + // The relationship block is gone — neither prose heading nor line. + assert!(!rendered.contains("Referenced by:"), "no prose heading:\n{rendered}"); + assert!(!rendered.contains("References:"), "no prose heading:\n{rendered}"); + assert!( + !rendered.contains("Orders.CustId → Id"), + "no prose line:\n{rendered}", + ); } #[test]