5438ba6a47
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.
193 lines
9.0 KiB
Markdown
193 lines
9.0 KiB
Markdown
# 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` ~954–1014) — the advanced-mode branch echoes
|
||
the input with `advanced_mode.not_implemented` (~996–1012)
|
||
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 1–2; 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`.
|