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.
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user