Files
rdbms-playground/docs/handoff/20260519-handoff-24.md
claude@clouddev1 5438ba6a47 docs: ADR-0030 — advanced mode standard-SQL surface
Decides the architecture for SQL in advanced mode (Q1/Q2/Q4):
SQL is authored as grammar within the unified grammar tree
(ADR-0024) and parsed by the existing walker — not a separate
batch parser — so SQL gets the same completion, highlighting,
hints, and parse-error reporting as the DSL. Mode gates the
SQL forms. DDL routes through the typed Command executor
(metadata and the playground type vocabulary preserved); DML
and SELECT execute as validated SQL. Engine-neutral posture;
DSL→SQL teaching echo; phased plan.

Supersedes ADR-0001's sqlparser-rs reservation. Ticks Q4;
updates the ADR index and the Q1/Q2 notes. handoff-24 orients
the implementation session at Phase 1.
2026-05-19 20:09:58 +00:00

193 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Session handoff — 2026-05-19 (24)
Twenty-fourth handover. A **design-only** session: it wrote and
accepted **ADR-0030 — Advanced mode: the standard-SQL surface**.
No code changed. A fresh session implements ADR-0030 from this
file + the ADR, starting at Phase 1.
## §1. State at handoff
**Branch:** `main`. Working tree clean (after this docs
commit). The session's commits since handoff-23 are docs-only —
ADR-0030, the ADR index, the `requirements.md` updates, and
this handoff. All local; push asynchronously, not blocking.
**Tests:** unchanged — **1240 passing, 0 failing, 1 ignored**
as of `a049ff9` (ADR-0029 complete). This session touched no
code. **Clippy:** clean as of the same commit.
## §2. What was decided — ADR-0030
Read **`docs/adr/0030-advanced-mode-sql-surface.md`** — the
spec, complete and accepted. Its shape, and *why* it landed
where it did (the design went through two rounds of user
input — §3 records the reasoning so it is not relitigated):
- **SQL is grammar in the unified tree, not a separate parser
(§1).** SQL statements are authored as `CommandNode` /
`Node` grammar in the ADR-0024 tree and parsed by the
existing walker. `sqlparser-rs` is **not** used —
ADR-0001's reservation is superseded. The reason is
decisive: a batch SQL parser produces an AST and nothing
else; it cannot drive completion, highlighting, or hints.
The user requires SQL to have the *same* ambient assistance
as the DSL — and that assistance comes only from the
unified grammar tree (ADR-0022/0023/0024). So SQL must live
in the tree.
- **Mode gates the grammar (§2).** One grammar tree; simple
mode exposes the DSL subset, advanced mode adds the SQL
forms. Shared entry words (`create`, `insert`, …) get a
`Choice` of DSL + SQL forms under one `CommandNode` (how
`add` already holds four sub-commands); `select` is a new
SQL-only entry word.
- **Execution split (§4).** DDL → a typed `Command` → the
existing executor, so metadata, the playground type
vocabulary, and `STRICT` are preserved. DML and `SELECT`
executed as **validated SQL** (they change no schema, so a
typed `Command` buys nothing); the worker re-persists the
affected table after DML.
- **Engine-neutral (§5, §7).** Playground type vocabulary,
never engine storage types; no `STRICT` surfaced;
engine-neutral errors. Advanced mode is *standard SQL*, not
an engine console.
- **Assistance for free (§8).** Because SQL is in the tree,
the walker gives SQL completion, highlighting, hint prose,
the `[ERR]`/`[WRN]` indicator, and parse-error usage — the
same as the DSL, no SQL-specific assistance code.
- **The DSL→SQL teaching echo (§10).** A DSL command run in
advanced mode also prints its equivalent SQL.
- **Persistence / replay (§11).** DDL via `Command` keeps
`project.yaml` correct; DML re-persists its table;
`history.log` stores the literal line; replay re-runs lines
through the one walker.
### §3. Decisions the user made (do not relitigate)
1. **Full SQL scope** — DDL + DML + the full `SELECT` query
surface (joins, aggregates, `GROUP BY`/`HAVING`,
subqueries, `UNION`, CTEs). No pre-emptive cuts; if a slice
proves *genuinely* overwhelming, cutting it is an explicit
escalation to the user, never a silent trim.
2. **No fallback to engine types** — advanced DDL keeps the
playground's rich type vocabulary. The `SQL → Command`
path for DDL is what guarantees this.
3. **Advanced mode is standard SQL, engine-independent** — not
a SQLite console; no engine-specifics surface.
4. **SQL lives in the unified grammar tree** (not a separate
batch parser) — chosen specifically so SQL gets full
completion / highlighting / hints. The user understood and
accepted that this means authoring a SQL grammar
ourselves; `sqlparser-rs` is dropped.
5. **`Command` only where it pays.** DDL → `Command` (buys
metadata + types); DML / `SELECT` → validated SQL (a
`Command` buys nothing).
6. **The DSL→SQL echo shows in advanced mode only.**
7. The persisted / replayable representation must be
app-enterable syntax — `history.log` already stores the
literal line, so this holds.
## §4. The phased implementation plan
ADR-0030 §Implementation is canonical. Each phase is
independently shippable and test-guarded. The two large
grammar slices each warrant their **own focused ADR** when
taken up (precedent: ADR-0026 for the `WHERE` grammar).
1. **Foundations + first `SELECT`.** Mode-gate the grammar
(advanced unlocks the SQL nodes). Author the core SQL
**expression grammar** — the ADR-0026 superset
(arithmetic, function calls, `CASE`, the predicate set) —
*its own ADR*. A single-table `SELECT` (projection,
`WHERE`, `ORDER BY`, `LIMIT`) as a SQL `CommandNode`
`Command::Select` → worker `RunSelect` → the existing
data-table renderer. Replace the placeholder echo; add the
simple-mode "this is SQL" hint. Proves the path end to end
*with full walker assistance*.
2. **`SELECT` — full.** `JOIN`s, `GROUP BY`/`HAVING`,
aggregates, subqueries, `UNION`, CTEs — *its own ADR*.
3. **DML.** `INSERT`/`UPDATE`/`DELETE` grammar; the
execute-as-validated-SQL path; the worker re-persist step;
settle multi-row `INSERT` and `shortid` auto-fill on a SQL
`INSERT`.
4. **DDL.** `CREATE`/`DROP`/`ALTER TABLE`, `CREATE`/`DROP
INDEX` grammar → `Command`; the §5 type-name map; FK
clauses → `AddRelationship`; may land table-rename (`C1`).
5. **The DSL→SQL teaching echo** (§10).
6. **Polish** — `help sql`; engine-neutral error sweep;
typing-surface / matrix coverage; the `DOC1` SQL-surface
reference page.
## §5. Seams for the implementer (from a code survey)
Anchors for Phase 1:
- **The placeholder to replace:** `App::submit`
(`src/app.rs` ~9541014) — the advanced-mode branch echoes
the input with `advanced_mode.not_implemented` (~9961012)
and sends nothing to the worker. The DSL dispatch path
(`dispatch_dsl`, ~1089) is what advanced SQL joins.
- **The grammar tree:** `src/dsl/grammar/` — `mod.rs` holds
`Node`, `CommandNode`, the `REGISTRY`; `ddl.rs` / `data.rs`
hold the DSL command grammars; `expr.rs` holds the ADR-0026
expression grammar (the seed for the SQL expression
grammar); `shared.rs` shared fragments. The walker is in
`src/dsl/walker/`. SQL grammar is authored here; mode-gating
is added to the `REGISTRY` / walker.
- **Command core:** `Command` in `src/dsl/command.rs` — add a
`Select` variant. **Gotcha:** every exhaustive `match
Command` breaks (`verb` / `target_table` / `display_subject`
in `command.rs`; `execute_command_typed` in `runtime.rs`;
`build_translate_context` in `app.rs`; `command_kind_label`
in `tests/typing_surface/mod.rs`) — the ADR-0028/0029
pattern.
- **Worker:** `Request` enum + `handle_request` + the
`Database` method wrappers in `src/db.rs` (~444 on) — add
`RunSelect` (returns `DataResult`), and later a "run
validated DML + re-persist" request.
- **Result rendering:** a `Select` outcome →
`CommandOutcome::Query` → `AppEvent::DslDataSucceeded` →
`output_render::render_data_table` — all reused from `show
data`.
- **Mode:** `src/mode.rs` (`Mode::Simple`/`Advanced`);
`App::effective_mode` and the `:`-strip in `App::submit`
already work — the mode-gated grammar view plugs in there.
- **`sqlparser-rs` is not used** — do not add it (an
implementer may keep it only as a test oracle, off the
execution path).
- **Risk:** the `Node` taxonomy / walker may need extension to
carry SQL's grammar (deeper recursion for subqueries /
CTEs). Expect node-taxonomy work in Phases 12; ADR-0030
flags this.
## §6. How to take over
1. **Read this file, then `docs/adr/0030-advanced-mode-sql-
surface.md`** (the spec). Then `CLAUDE.md` (working-style
rules), `docs/requirements.md` (`Q4` ticked; `Q1`/`Q2`
unblocked), and skim `docs/simple-mode-limitations.md` —
ADR-0030 §4 commits advanced mode to lifting the
expression limits that file records.
2. **Run `cargo test`** — 1240 passing, 0 failing, 1 ignored.
3. **Run `cargo clippy --all-targets -- -D warnings`** —
clean.
4. **Start ADR-0030 Phase 1.** First sub-step is the SQL
**expression grammar** — write its focused ADR before
authoring it (ADR-0026 is the model and the seed). Then the
single-table `SELECT` end to end. Land the `Command::
Select` match-arm sweep with the worker request in one
commit (the exhaustive-match breakage forces it).
5. Escalate, do not guess, on anything ADR-0030 left per-phase
— multi-row `INSERT`, `shortid` on SQL `INSERT`, any
`Node`-taxonomy extension that changes the walker's
contract.
## §7. What else is open
ADR-0030 is the active design. Other open clusters, unchanged
from handoff-23 §5 (prioritisation is a **user decision**):
snapshot/undo `U`-series (ADR-0006 written, unbuilt); m:n
convenience `C4`; modify-relationship `C3a`; the `show` family
`V5`; rename-table `C1` (may fall out of ADR-0030 Phase 4);
friendly-error sweep `H1`; CI `TT5`; session-log / Markdown
export `V4`.