feat: DSL→SQL teaching echo — Bucket B renderer (ADR-0038 Phase 2)

Expands the renderer to Bucket B — resolved-name single-statement
echoes plus the two category-2 multi-statement forms. Every catalogue
row round-trips per line through the advanced-mode walker (the §1
copy-paste contract; §6 category 2 holds the contract per line):

  add index [as N] on T (cols)           → CREATE INDEX <name> ON T (cols)
  drop index on T (cols) (positional)    → DROP INDEX <name>
  add 1:n relationship [as N] …          → ALTER TABLE C ADD CONSTRAINT
                                            <name> FOREIGN KEY (cc)
                                            REFERENCES P (pc) [ON …]
  drop relationship (endpoints or named) → ALTER TABLE C DROP CONSTRAINT
                                            <name>
  drop column T.c --cascade              → DROP INDEX <ix1> ⏎ … ⏎
                                            ALTER TABLE T DROP COLUMN c
  add relationship … --create-fk         → ALTER TABLE C ADD COLUMN cc <ty>
   (child column newly created)            ⏎ ALTER TABLE … ADD CONSTRAINT
   (already existed) collapses to a single-line FK echo

Refactors the echo payload from Option<String> to Option<Vec<String>>
across the 7 success events + arms + render path — one entry per
statement; the Bucket A single-line echoes wrap as Some(vec![s]). Plain
rendering repeats `Executing SQL:` per line; the de-emphasised
styled-runs polish (ADR-0038 §4) will refine it later.

Adds the two echo build paths the handoff §5 ⚠️ gotcha foreshadowed:

* collect_echo_lookups (pre-execution, runtime): resolves names the
  dropped thing or not-yet-created column would erase post-execution —
  drop index (positional), drop relationship (both endpoints and named
  selectors, the latter via a list_tables scan acceptable for teaching-
  playground schemas), and the --create-fk pre-state (whether the child
  column existed + the parent PK type to derive the new column type via
  Type::fk_target_type).
* build_schema_echo (post-execution, runtime): subsumes the Bucket A
  pure-Command schema cases and renders Bucket B from the description +
  the lookups.

The DropColumn arm gains build_drop_column_cascade_echo, which reads
DropColumnResult.dropped_indexes to emit the multi-line cascade echo;
non-cascade falls through to the pre-execution Bucket A echo unchanged.

Tests: 2013 passed / 0 failed / 1 ignored (pre-existing); clippy clean
(`--all-targets -D warnings`, nursery). Two end-to-end runtime tests
exercise the resolved-name and multi-statement flows against a real
worker (auto-named index, both drop-relationship selector forms, both
--create-fk branches). One app-level test pins the multi-line rendering
(one Executing SQL: per statement, in order, beneath [ok]).

Phase 3 (category-3 prose — shortid generation, type-conversion
transforms, `change column --dont-convert` caveat) and the §4
de-emphasised styled-runs rendering polish remain per ADR-0038 §8
phasing.
This commit is contained in:
claude@clouddev1
2026-05-28 07:54:05 +00:00
parent 558cfae151
commit 275c726ad4
4 changed files with 1112 additions and 53 deletions
+7 -7
View File
@@ -32,7 +32,7 @@ pub enum AppEvent {
/// advanced effective mode (ADR-0037). `None` when no echo applies
/// (simple mode, SQL-entered, or a form with no echo). The App
/// renders it beneath `[ok]`.
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// A SQL `CREATE TABLE IF NOT EXISTS` matched an existing table —
/// a no-op (ADR-0035 §4). Renders the existing structure plus an
@@ -68,7 +68,7 @@ pub enum AppEvent {
DslDataSucceeded {
command: Command,
data: DataResult,
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// An `explain …` command succeeded (ADR-0028). `plan`
/// carries the captured query plan; nothing was executed.
@@ -83,7 +83,7 @@ pub enum AppEvent {
/// The DSL → SQL teaching echo (ADR-0038): `UPDATE T SET …` for an
/// `update … --all-rows` fall-through. `None` for a SQL-entered
/// `UPDATE` or any simple-mode submission.
echo: Option<String>,
echo: Option<Vec<String>>,
},
DslDeleteSucceeded {
command: Command,
@@ -91,7 +91,7 @@ pub enum AppEvent {
/// The DSL → SQL teaching echo (ADR-0038): `DELETE FROM T` for a
/// `delete … --all-rows` fall-through. `None` for a SQL-entered
/// `DELETE` or any simple-mode submission.
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// A `change column …` succeeded. `result` carries both the
/// post-rebuild description (for the auto-show) and the
@@ -102,7 +102,7 @@ pub enum AppEvent {
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T ALTER
/// COLUMN c SET DATA TYPE …`. `None` in simple mode. (The
/// `--dont-convert` caveat line is category-3, a later slice.)
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// An `add column …` succeeded. `result` carries the
/// post-add description plus any `[client-side]` notes
@@ -112,7 +112,7 @@ pub enum AppEvent {
result: AddColumnResult,
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T ADD
/// COLUMN c <ty> …`. `None` in simple mode.
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// A `drop column …` succeeded. `result` carries the
/// post-drop description plus the names of any indexes
@@ -123,7 +123,7 @@ pub enum AppEvent {
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T DROP
/// COLUMN c` for a plain (non-`--cascade`) drop. `None` in simple
/// mode, and for `--cascade` (a multi-statement echo, Phase 2).
echo: Option<String>,
echo: Option<Vec<String>>,
},
/// A DSL command failed. `error` is the structured
/// payload, `facts` is the runtime-built schema-resolved