feat: show relationship <name> renders a styled two-table diagram (ADR-0044)

The first wired slice of relationship visualization (V1). `show
relationship <name>` now renders the relationship as two full
structure boxes joined by a width-jogging connector (child-left /
parent-right, n…1 cardinality, on delete/update actions), styled
App-side, with a vertical-stack fallback for narrow terminals.

- db.rs: RelationshipDiagramData + show_relationship worker path
  (structured data: the relationship + both endpoint TableDescriptions)
- runtime.rs: named relationships route to the structured outcome
  (boxed); other show <kind> forms stay prose
- app.rs/event.rs/ui.rs: DslShowRelationshipSucceeded rendered App-side;
  new diagram OutputStyleClass variants; App::last_output_width from ui.rs
- output_render.rs: styled Seg layout engine (boxes, connector routing,
  side-by-side + vertical), composing the ADR-0016 box primitives

Tests: 4 unit + 4 integration; full suite 2201 pass / 0 fail / 1 ignored;
clippy nursery clean. requirements.md V1 stays [/] (show table diagrams,
compound routing, DDL-echo wiring remain).
This commit is contained in:
claude@clouddev1
2026-06-09 22:27:39 +00:00
parent bb02dfb752
commit cad90ec4a5
8 changed files with 756 additions and 1 deletions
+20
View File
@@ -1407,6 +1407,12 @@ fn spawn_dsl_dispatch(
command: command.clone(),
lines,
},
Ok(CommandOutcome::ShowRelationship(data)) => {
AppEvent::DslShowRelationshipSucceeded {
command: command.clone(),
data: data.map(|b| *b),
}
}
Ok(CommandOutcome::QueryPlan(plan)) => AppEvent::DslExplainSucceeded {
command: command.clone(),
plan,
@@ -2252,6 +2258,10 @@ enum CommandOutcome {
/// the worker (table / relationship / index names). Pure
/// display, no schema change.
ShowList(Vec<String>),
/// Structured data for one relationship's diagram (ADR-0044),
/// rendered App-side; `None` when the named relationship is absent.
/// Boxed — two full `TableDescription`s dwarf the other variants.
ShowRelationship(Option<Box<crate::db::RelationshipDiagramData>>),
QueryPlan(QueryPlan),
Insert(InsertResult),
Update(UpdateResult),
@@ -2774,6 +2784,16 @@ async fn execute_command_typed(
.describe_table(name, src)
.await
.map(|d| CommandOutcome::Schema(Some(d))),
// ADR-0044: a named relationship renders as a diagram (App-side),
// so it returns structured data; every other `show <kind>` form
// stays the worker-formatted prose list.
Command::ShowList {
kind: crate::dsl::command::ShowListKind::Relationships,
name: Some(name),
} => database
.show_relationship(name)
.await
.map(|opt| CommandOutcome::ShowRelationship(opt.map(Box::new))),
Command::ShowList { kind, name } => database
.show_list(kind, name)
.await