diff --git a/docs/adr/0030-advanced-mode-sql-surface.md b/docs/adr/0030-advanced-mode-sql-surface.md new file mode 100644 index 0000000..dd9c872 --- /dev/null +++ b/docs/adr/0030-advanced-mode-sql-surface.md @@ -0,0 +1,382 @@ +# ADR-0030: Advanced mode — the standard-SQL surface + +## Status + +Accepted + +## Context + +ADR-0003 split the input field into two modes. **Simple mode** +(the default) takes the teaching DSL; **advanced mode** was +specified to take "raw SQL, including DDL and queries". The DSL +half is fully built (ADR-0009, ADR-0023/0024, and everything +since); advanced mode is still a **placeholder** — a submitted +line is echoed back unexecuted. + +Requirement `Q1` commits to a *defined* SQL subset, `Q2` to +rejecting out-of-subset syntax clearly, `Q4` is the subset +specification — this ADR. Two constraints shape every decision +below; both come from how this project already works. + +1. **The engine is an implementation detail.** ADR-0002 + established that the database product is never named in + user-facing strings. Advanced mode must *extend* that + posture: it is a way to work with **standard SQL**, as + independent of the storage engine as we can make it — not a + console onto the engine. The engine's type names, its + `STRICT` keyword, its dialect quirks, and its raw error text + must not surface. And handing typed text straight to the + engine would bypass the typed executor that keeps the + internal metadata tables (ADR-0012/0013) in sync, writes + `project.yaml` + CSV (ADR-0015), and preserves the + playground's rich type vocabulary (ADR-0005). + +2. **Assistance comes from one place.** Completion, syntax + highlighting, hint-panel prose, the `[ERR]`/`[WRN]` + indicator, and per-command parse-error usage all derive + from a single **unified grammar tree** walked incrementally + (ADR-0022/0023/0024 — explicitly "the single source of + truth"). A *batch* SQL parser — the kind `sqlparser-rs` + (reserved in ADR-0001) is — produces an AST and nothing + else: it cannot say what is valid at the cursor, cannot + drive completion, highlighting, or hints. Parsing SQL with + such a library would leave advanced mode either *without* + the ambient assistance the DSL has, or dependent on a + second, parallel assistance system — both contrary to + ADR-0023/0024. + +The decision: **SQL is not parsed by a separate library. SQL +becomes additional grammar within the unified tree**, walked by +the same walker as the DSL. Advanced mode is not a different +parser — it is the same parser with more grammar unlocked. + +## Decision + +### 1. SQL lives in the unified grammar tree + +SQL statements are authored as `CommandNode` / `Node` grammar +in the ADR-0024 tree and parsed by the existing walker. The +consequence is the whole point: completion, highlighting, +hint prose, the validity indicator, and parse-error usage +**work for SQL exactly as for the DSL, for free**, because +they are all walker outputs (§8). + +`sqlparser-rs` is therefore *not* used as the parser; +ADR-0001's reservation of it is superseded. (An implementer +may retain it narrowly as a test oracle — parse the same SQL, +compare — but it is not on the execution path.) + +The honest cost: the supported SQL is exactly what we author +into the tree — we are, in effect, writing a SQL grammar. This +is the project's largest single feature to date. The target is +the full teaching-relevant standard-SQL surface (§3); scope is +cut only on *demonstrated* difficulty, as a deliberate +escalation to the user, never silently. + +### 2. Mode gates the grammar + +There is one grammar tree. **Simple mode** exposes the DSL +subset of it; **advanced mode** additionally exposes the SQL +forms. + +- Shared entry words — `create`, `drop`, `insert`, `update`, + `delete` — carry both a DSL form and a SQL form as `Choice` + branches under one `CommandNode` (mechanically how `add` + already holds four sub-commands today). `select` is a new, + SQL-only entry word. +- SQL branches are mode-tagged; the walker presents the + DSL-only view in simple mode and the full view in advanced. +- The `:` one-shot escape and `mode advanced` unlock the SQL + view for a line / persistently — unchanged from ADR-0003. +- Because the grammar *knows* a node is SQL (it is tagged, + merely gated), a simple-mode line that matches a gated SQL + form yields a precise hint — "this is SQL; switch with `mode + advanced`, or prefix the line with `:`" — rather than a + generic parse error. This satisfies `M1`'s "recognised as + SQL" promise. + +The DSL stays usable in advanced mode (the superset rule): +nothing a learner already knows stops working. + +### 3. The supported SQL surface (`Q4`) + +The target is the teaching-relevant standard-SQL surface, +authored into the tree with **no pre-emptive cuts**: + +- **`SELECT`** — the full query surface: projection, `WHERE`, + inner/outer `JOIN`s, `GROUP BY` / `HAVING`, aggregate + functions, `ORDER BY`, `LIMIT` / `OFFSET`, scalar and + correlated subqueries, `UNION` / `INTERSECT` / `EXCEPT`, and + common table expressions (`WITH`). +- **`INSERT`** (single- and multi-row), **`UPDATE`**, + **`DELETE`**. +- **`CREATE` / `DROP` / `ALTER TABLE`**, **`CREATE` / `DROP + INDEX`**. +- A **SQL expression grammar** — arithmetic, function calls, + `CASE`, the comparison / `LIKE` / `IN` / `BETWEEN` / `IS + NULL` predicate set, subquery expressions — the superset of + ADR-0026's `WHERE` grammar, shared by `WHERE`, `HAVING`, + `CHECK`, `SELECT` projections, and `DEFAULT`. + +Out of the surface: views, triggers, transaction control +(`BEGIN`/`COMMIT`/…), `PRAGMA`, `ATTACH`/`DETACH`, `VACUUM`, +virtual tables, multi-statement batches. One statement per +submission; a trailing `;` is tolerated. + +The **SQL expression grammar** and the **full `SELECT` +grammar** are each large enough to warrant their own focused +ADR when implemented — the precedent is ADR-0026 for the +`WHERE` grammar. ADR-0030 fixes the *architecture*; those +ADRs fix the detailed grammar. + +### 4. Execution — DDL through `Command`, DML and `SELECT` as validated SQL + +The walker parsing a SQL statement yields a matched parse. +From it: + +- **DDL** → a `Command` (`CreateTable`, `DropTable`, + `AddColumn`, `AddConstraint`, `AddIndex`, …). DDL *must* run + the typed executor, because that is what keeps the metadata + tables, the playground type vocabulary, and `STRICT` intact. + The `CommandNode`'s `ast_builder` is the SQL → `Command` + translator. +- **DML and `SELECT`** → executed as the **validated SQL + itself** (re-rendered canonically from the matched parse, or + the validated original text). They change no schema, so + modelling them as a typed `Command` buys nothing. For DML + the worker — knowing the statement kind and target table + from the parse — runs the statement and re-persists that + table's CSV; `SELECT` is read-only, run and rendered (§6). + +This split is also what makes advanced mode genuinely *full*. +Because DML / `SELECT` / `CHECK` expressions are **not** +lowered into the DSL's deliberately-limited `Expr` (ADR-0026), +advanced mode delivers the full SQL expression surface — +arithmetic, functions, subqueries, nested boolean operands — +that `docs/simple-mode-limitations.md` records as the inverse +of the simple-mode subset. The DSL `Expr` is the *DSL's* +representation; the SQL surface does not round-trip through it. + +### 5. Type vocabulary — the playground's, not the engine's + +Advanced-mode DDL uses the playground's own ten-type +vocabulary (ADR-0005). There is **no fallback to engine +storage types**: a column created in advanced mode is a +first-class `serial` / `decimal` / `date` / … exactly as a +DSL-created one, with the same metadata row. + +The type-name slot accepts the playground keywords directly +(`text`, `int`, `real`, `decimal`, `bool`, `date`, +`datetime`, `blob`, `serial`, `shortid`) and standard-SQL +aliases that map onto them — `integer`/`smallint`/`bigint` → +`int`; `varchar`/`char` → `text`; `boolean` → `bool`; +`timestamp` → `datetime`; `numeric` → `decimal`; +`float`/`double precision` → `real`; `binary`/`varbinary` → +`blob`. A length / precision argument (`varchar(255)`) is +accepted and ignored — the playground's types are +unparameterised. The engine's own type names are an internal +mapping and are neither accepted as input nor shown. + +### 6. `SELECT` — the read-only query path + +`SELECT` touches no metadata, no persistence, no types. It is +carried as `Command::Select` holding the validated SQL; the +worker (`Request::RunSelect`) prepares and runs it, producing +the existing `DataResult`, which renders through the existing +data-table renderer (the one `show data` uses, ADR-0016). +Columns that carry no playground type — computed expressions, +joined columns — render with neutral alignment; the result is +capped like `show data`, with `LIMIT` suggested for large +outputs. A reference to an internal `__rdbms_*` table is +rejected by the grammar (those tables are not in scope). + +### 7. Engine neutrality + +- **No engine type names** in or out (§5). +- **No `STRICT`**, no storage options. `STRICT` is applied + internally by `do_create_table`; the user neither writes nor + sees it. It is simply not part of the authored grammar, so + typing it is an ordinary parse error — not a SQLite feature + surfaced to the learner. +- **Engine-neutral errors.** SQL parse errors, out-of-subset + refusals, and execution failures all route through the + friendly-error layer (ADR-0019); the engine's raw message + and product name never appear. +- **Honest limitation.** The grammar enforces the *structural* + subset exactly. *Expression-level* neutrality is best-effort: + an exotic engine-specific function the grammar admits and the + engine then rejects surfaces an engine-neutral error rather + than being caught up front. A function allowlist is a + possible future hardening (§13). + +### 8. Ambient assistance comes for free + +Because SQL is grammar in the unified tree (§1), the walker +gives SQL — with no SQL-specific assistance code — the same as +the DSL: + +- **Syntax highlighting** of SQL keywords, identifiers, + literals. +- **Tab completion** of SQL keywords, and of schema names + (tables, columns) drawn from the same `SchemaCache` the DSL + completion already uses. +- **Hint-panel prose** at each grammar slot. +- The **`[ERR]`/`[WRN]` validity indicator** (ADR-0027). +- **Per-command parse-error usage** (ADR-0021). + +This is the reason for §1: assistance and a batch parser are +incompatible; assistance and the unified grammar tree are the +same thing. + +### 9. Parse errors and the unsupported surface (`Q2`) + +A construct not in the authored grammar is an ordinary walker +parse error; the ADR-0021 per-command usage machinery and the +ADR-0027 indicator apply, with engine-neutral wording. There +is no separate "valid SQL but unsupported" classifier — that +would require the batch parser §1 dropped; the walker's +expected-set drives the message instead. + +### 10. The DSL → SQL teaching bridge + +When a **DSL** command runs **in advanced mode**, its output +includes the equivalent SQL — so a learner who knows the +simple-mode form reads off how to express it in SQL. + +- It is a `Command` → SQL renderer: the inverse of §4's DDL + translator. +- It fires only for commands entered via the DSL form, and + only in advanced mode (a command the user already typed as + SQL is not echoed back; simple mode is left uncluttered). +- It renders as a distinct, de-emphasised output line beneath + the `[ok]` summary, using the `OutputLine` styled-runs + mechanism (ADR-0028). +- App-level commands have no SQL form and are not echoed. + +### 11. Persistence, metadata, history, replay + +- **DDL** → `Command` → the typed executor, so `project.yaml`, + the metadata tables, and `history.log` stay correct with no + new code (§4). +- **DML** → the worker re-persists the affected table's CSV + after running the statement. +- **`history.log`** records the **literal submitted line** — a + statement typed as SQL is logged as that SQL. The replay + format is therefore app-enterable syntax, no divergence. +- **Replay** re-runs each log line through the one walker with + the advanced view active, so a project whose history mixes + DSL and SQL replays faithfully. +- **`project.yaml`** stays a structured schema snapshot; its + embedded expressions (a column `CHECK`) are stored as SQL + the user could re-enter in advanced mode — one syntax, not a + third. + +### 12. Safety in advanced mode + +Advanced mode carries **fewer rails** by design. The DSL's +`WHERE`-or-`--all-rows` guard on `update`/`delete` (ADR-0014) +is a simple-mode teaching aid; a SQL `DELETE FROM t` with no +`WHERE` executes as written. The safety net is the +auto-snapshot before destructive operations (ADR-0006), which +fires regardless of which surface produced the statement; the +mode's visual distinction (ADR-0003) is the user's signal +until then. + +### 13. Out of scope + +- **OOS-1.** `CREATE VIEW` / `TRIGGER`. Views are anticipated + by the items panel's design (`S2`) but need their own model. +- **OOS-2.** `EXPLAIN` of advanced-mode SQL queries. The DSL + `explain` (ADR-0028) still works for what it already wraps. +- **OOS-3.** A function/expression allowlist for full + expression-level engine neutrality (§7) — best-effort now. +- **OOS-4.** Multi-statement batches and transaction control. +- **OOS-5.** A SQL → DSL echo (the reverse of §10). + +## Consequences + +- The unified grammar tree gains a large body of SQL grammar. + The `Node` taxonomy and the walker may need extension to + carry it (e.g. deeper recursion for subqueries / CTEs) — a + known risk, addressed per phase. +- `sqlparser-rs` is **not** adopted as the parser; ADR-0001's + reservation is superseded. `Q1`'s wording ("SQL parsed via + `sqlparser-rs`") is superseded — SQL is parsed by the + unified walker. +- `Command` gains a `Select` variant; every exhaustive `match + Command` gains an arm (the recurring ADR-0028/0029 gotcha). +- The `Database` worker gains a `RunSelect` request and a + "run validated DML, re-persist the table" request; DDL + reuses the existing typed requests unchanged. +- Mode-gating is added to the grammar / walker. +- The metadata, persistence, and type machinery is reused + unchanged for DDL — the payoff of routing DDL through + `Command`. +- This is the project's largest single feature so far. The + phased plan keeps each step independently shippable; + scope-cutting, if a slice proves disproportionate, is an + explicit escalation, never a silent trim. +- `Q4` is satisfied by this ADR; `Q1` / `Q2` are unblocked and + reframed around the unified walker; `M1` gains its + "recognised as SQL" hint. + +## Implementation notes + +Phased; each phase independently shippable and test-guarded. +The two large grammar slices each warrant their own focused +ADR when taken up (ADR-0026-style). + +1. **Foundations + first `SELECT`.** Mode-gate the grammar + (advanced unlocks the SQL nodes). Author the core SQL + **expression grammar** — the ADR-0026 superset — as its own + ADR. A single-table `SELECT` (projection, `WHERE`, `ORDER + BY`, `LIMIT`) as a SQL `CommandNode` → `Command::Select` → + worker `RunSelect` → the existing renderer. Replace the + placeholder echo; add the simple-mode "this is SQL" hint. + This proves the path end-to-end *with full walker + assistance*. +2. **`SELECT` — full.** `JOIN`s, `GROUP BY`/`HAVING`, + aggregates, subqueries, `UNION`, CTEs. The big grammar + phase — 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`; an engine-neutral error sweep; + typing-surface / matrix coverage; the `DOC1` SQL-surface + reference page. + +## See also + +- ADR-0001 — reserved `sqlparser-rs`; that reservation is + superseded here (§1). +- ADR-0002 — the engine is an implementation detail; "no + engine name in user-facing strings" — §7 extends it. +- ADR-0003 — the simple / advanced mode model this builds on. +- ADR-0005 — the ten-type vocabulary advanced DDL uses (§5). +- ADR-0009 — the DSL conventions; the DSL stays usable in + advanced mode. +- ADR-0012 / ADR-0013 — the metadata tables the `Command` core + keeps in sync, inherited for free (§4, §11). +- ADR-0014 — the data-operation model and the `--all-rows` + guard advanced mode deliberately relaxes (§12). +- ADR-0015 — persistence write-through and replay, reused and + made surface-agnostic (§11). +- ADR-0016 — the data-table renderer `SELECT` results reuse + (§6). +- ADR-0019 — the friendly-error layer all SQL errors route + through (§7, §9). +- ADR-0021 — per-command parse-error usage, free for SQL (§9). +- ADR-0022 — ambient typing assistance; §8 is its extension to + SQL. +- ADR-0023 / ADR-0024 — the unified grammar tree SQL becomes + part of (§1, §2). +- ADR-0026 — the `WHERE` expression grammar the SQL expression + grammar is the superset of (§3). +- ADR-0027 — the validity indicator, free for SQL (§8). +- ADR-0028 — the `OutputLine` styled-runs the teaching echo + uses (§10). diff --git a/docs/adr/README.md b/docs/adr/README.md index 00dc0ad..a92b210 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -35,3 +35,4 @@ This directory contains the project's ADRs, recorded per - [ADR-0027 — Input-field validity indicator](0027-input-validity-indicator.md) — **Accepted**, a debounced `[ERR]` / `[WRN]` marker at the input row's right edge, backed by a walker diagnostics-severity model (parse-outcome + schema-existence); advisory, never blocks submission (`S6`); Amendment 1 adds a `LIKE`-on-numeric-column WARNING - [ADR-0028 — Query plans (`EXPLAIN QUERY PLAN`)](0028-query-plans.md) — **Accepted**, an `explain` prefix command over `show data` / `update` / `delete`; an annotated, span-styled plan tree; introduces the `OutputLine` styled-runs mechanism (ADR-0016's deferred per-span styling) (`QA1` / `QA2`) - [ADR-0029 — Column constraints (NOT NULL / UNIQUE / CHECK / DEFAULT)](0029-column-constraints.md) — **Accepted**, the four column-level constraints declared in the column-spec suffix (`create table` / `add column`) and modified on existing columns via `add constraint …` / `drop constraint …`; a pre-flight dry-run guards populated columns; `CHECK` reuses the ADR-0026 expression grammar via `Subgrammar` (`C3`) +- [ADR-0030 — Advanced mode: the standard-SQL surface](0030-advanced-mode-sql-surface.md) — **Accepted**, SQL added as grammar *within the unified grammar tree* (ADR-0024), not a separate batch parser — so SQL gets the same completion / highlighting / hints / parse-errors as the DSL; mode gates the SQL forms; DDL routes through the typed `Command` executor (metadata + type vocabulary preserved), DML and `SELECT` execute as validated SQL; engine-neutral posture, the DSL→SQL teaching echo; supersedes ADR-0001's `sqlparser-rs` reservation; phased plan (`Q1` / `Q2` / `Q4`) diff --git a/docs/handoff/20260519-handoff-24.md b/docs/handoff/20260519-handoff-24.md new file mode 100644 index 0000000..29cf2ad --- /dev/null +++ b/docs/handoff/20260519-handoff-24.md @@ -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`. diff --git a/docs/requirements.md b/docs/requirements.md index 7ec4c96..36022f0 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -196,15 +196,31 @@ handoff-14 cleanup; 449 after B2/C2.) - [ ] **Q1** SQL parsed via `sqlparser-rs`; supported subset is defined (specifics deferred to a future ADR). - *(Progress: DSL is parsed via `chumsky` (ADR-0009); SQL - handling in advanced mode is still a placeholder echo.)* + *(Progress: SQL handling in advanced mode is still a + placeholder echo. The architecture is now decided — ADR-0030: + 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 as the DSL. ADR-0001's `sqlparser-rs` + reservation is superseded. Implementation is phased and + pending.)* - [ ] **Q2** Non-standard syntax rejected with a clear message pointing at the supported subset. + *(Design done — ADR-0030 §8: out-of-subset statements are + refused with an engine-neutral message naming the construct. + Implementation pending.)* - [x] **Q3** User-facing simplified types map transparently to SQLite STRICT types in generated DDL. *(All ten types implemented and tested.)* -- [~] **Q4** Supported SQL subset specification — design and ADR - pending. Q1 cannot be marked satisfied without it. +- [x] **Q4** Supported SQL subset specification — **ADR-0030**. + Advanced mode is a standard-SQL surface, engine-neutral; the + supported surface — `SELECT` (full query surface), + `INSERT` / `UPDATE` / `DELETE`, `CREATE` / `DROP` / `ALTER + TABLE`, `CREATE` / `DROP INDEX` — is authored as grammar in + the unified tree. DDL routes through the typed `Command` + executor (metadata + the playground type vocabulary + preserved); DML and `SELECT` execute as validated SQL. Q1's + implementation is now unblocked. ## Database backend (per ADR-0002)