Files
rdbms-playground/CLAUDE.md
T
claude@clouddev1 a50c6cdf70 WHERE expressions: matrix cells + predicate_tail grammar fix (ADR-0026 step 6)
Adds tests/typing_surface/where_expression.rs — 9 matrix
cells for the complex WHERE / show-data limit typing surface:
operator candidates after an operand, AND / OR after a
predicate, NOT, BETWEEN / IN bounds, and `show data`
where / limit.

Writing the cells surfaced a grammar bug. `predicate_tail`'s
`[NOT] negatable` branch started with `Optional(not)`, and an
Optional-first `Seq` always "commits" — so on an incomplete
input the walker's `Choice` returned that branch's
`Incomplete` early and discarded every sibling branch's
expected set, dropping `is` and the comparison operators from
completion after a column. Fixed by splitting it into
explicit `NOT negatable` and bare `negatable` branches — no
`predicate_tail` branch starts with an `Optional` now. The
matched terminal sequence is unchanged, so `build_expr` is
untouched.

Docs: ADR-0026 gains an "As-built notes" section recording
the option-1 builder realization, its two deviations from the
§3 sketch, and the deferral of §7 diagnostic flagging to
ADR-0027. requirements.md C5a -> [x] (steps 1-4) with the
test baseline refreshed to 1079; CLAUDE.md's deferred list
reconciled (C5a implemented; the QA1/QA2 note now points at
ADR-0028).
2026-05-18 23:19:53 +00:00

233 lines
11 KiB
Markdown
Raw 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.
# RDBMS Playground — project notes for Claude
## What this project is
A cross-platform TUI application that gives learners a sandbox for
exploring relational database concepts: tables, columns, primary
and foreign keys, relationships, indexes, queries, and query
plans. The audience is students from beginners to those ready for
raw SQL, and the design accommodates both ends of that spectrum.
The application is a teaching tool, not a database administration
tool. Decisions about the type system, command surface, and
backend choices are skewed toward pedagogy over breadth.
## Authoritative decisions
All significant design decisions live in `docs/adr/`. Read
`docs/adr/README.md` for the index. **Before proposing changes
that touch a decided area, read the relevant ADR.** Decisions are
not re-litigated casually — if a decision needs to change, write a
new ADR that supersedes the old one.
Current decisions at a glance (each backed by an ADR):
- **Stack:** Rust + Ratatui + Crossterm; `sqlparser-rs` reserved
for SQL (advanced mode, not yet wired); `chumsky` for the DSL;
`rusqlite` for the database (ADR-0001).
- **Backend:** SQLite with `STRICT` tables and FK enforcement on
(ADR-0002). Database access through a dedicated worker thread
with mpsc/oneshot request channels (ADR-0010).
- **Input:** simple mode (DSL only) by default; advanced mode
(SQL + app-level commands) on toggle; `:` one-shot escape from
simple to advanced (ADR-0003). No other sigils.
- **Project format:** `project.yaml` + `data/<table>.csv` +
`history.log`; `playground.db` is a derived artifact (ADR-0004,
amended by ADR-0015). Implemented through Iteration 4 +
cleanup; export/import (Iter 5) and migration framework /
--resume / persistent input history (Iter 6) pending.
- **Project storage runtime:** every command persists through to
db + yaml + csv + history.log in one execution context, gated
by the combined db persistence logic; commit-db-last ordering
for crash-recoverable state; existence-only load + explicit
`rebuild` command; in-TUI list-with-browse load picker; lock
file for single-instance enforcement; persistence failures
are fatal (banner + quit) (ADR-0015). Empty tables produce no
CSV. CSV reader hand-rolled to preserve NULL-vs-empty
distinction. Temp projects are marked by a literal `[temp]`
segment in their directory name (validate_user_name rejects
brackets, so user-named projects can never collide).
- **Temp project cleanup:** unmodified empty temps
(kind=Temp, empty schema, empty data dir) are auto-deleted
on switch and on quit by `safely_delete_temp_project`,
which stacks containment / symlink-rejection /
`[temp]`-marker / contents-allowlist guards. Anything
unexpected → refuse, never delete the wrong thing.
- **Types:** `text`, `int`, `real`, `decimal`, `bool`, `date`,
`datetime`, `blob`, `serial`, `shortid`. Compound primary keys
supported. No real UUIDs (ADR-0005). FK column type
compatibility via `Type::fk_target_type()``serial → int`,
`shortid → text`, others identity (ADR-0011).
- **Safety:** auto-snapshot before destructive ops; `:undo`;
append-only `history.log` for replay and scripting (ADR-0006).
*(Designed; not yet implemented.)*
- **Sharing:** `export` command produces a zip without the `.db`;
no hosted publishing (ADR-0007).
- **Testing:** four-tier strategy from `cargo test` units up to
PTY-based end-to-end (ADR-0008). Tiers 13 are active; Tier 4
is wired only for the listed critical flows.
- **DSL syntax conventions:** required clauses use keyword
grammar (`with pk`, `to table` optional, `from..to`, `set`,
`where`); `--` flags are reserved for opt-in choices; one
sigil only (`:`); keywords case-insensitive, identifiers
case-preserving (ADR-0009).
- **Internal metadata tables** (ADR-0012, ADR-0013): the database
carries `__rdbms_playground_columns` for user-facing column
types and `__rdbms_playground_relationships` for named FKs.
These are the source of truth for round-tripping schema info.
Internal tables follow the `__rdbms_*` naming convention and
are filtered out of `list_tables`.
- **FK relationships:** declared via `add 1:n relationship [as
<name>] from <P>.<col> to <C>.<col> [on delete <action>] [on
update <action>] [--create-fk]`. Implemented through the
rebuild-table primitive — the same machinery covers B2's
pending column drop/rename/type-change use cases (ADR-0013).
- **Data operations:** `insert / update / delete / show data`
with required WHERE plus `--all-rows` opt-in for unfiltered
ops; auto-show after writes shows just the affected rows;
DELETE reports per-relationship cascade summaries (ADR-0014).
## Repository layout
```
.
├── Cargo.toml # dependencies, lints (nursery)
├── CLAUDE.md # this file
├── docs/
│ ├── adr/ # all decision records (read 0000 first)
│ ├── handoff/ # session-handover notes
│ └── requirements.md # the Phase-1 checklist with progress
├── src/
│ ├── action.rs # Action enum (Quit / ExecuteDsl)
│ ├── app.rs # App state + pure update() + Tier-1 tests
│ ├── cli.rs # CLI args (--theme, --log-file)
│ ├── db.rs # rusqlite worker, all DDL/DML, metadata tables
│ ├── dsl/
│ │ ├── action.rs # ReferentialAction enum + parsing
│ │ ├── command.rs # Command AST + RelationshipSelector + RowFilter
│ │ ├── mod.rs # re-exports
│ │ ├── parser.rs # chumsky grammar (all DSL commands)
│ │ ├── shortid.rs # base58 generator + validator
│ │ ├── types.rs # user-facing Type enum + fk_target_type
│ │ └── value.rs # Value/Bound + per-type validation
│ ├── event.rs # AppEvent (input + DSL outcomes)
│ ├── lib.rs # module re-exports for tests
│ ├── logging.rs # tracing setup, file-backed
│ ├── main.rs # binary entry; thin
│ ├── mode.rs # Simple/Advanced mode enum
│ ├── runtime.rs # Tokio loop, terminal setup, dispatch
│ ├── snapshots/ # insta snapshots for Tier-2 tests
│ ├── theme.rs # light/dark themes
│ └── ui.rs # ratatui rendering
└── tests/
└── walking_skeleton.rs # Tier-3 integration tests
```
Key invariants in the code:
- **`update()` is pure-sync.** It returns `Vec<Action>` for the
runtime to enact. Side effects belong in the runtime, not the
update function — that's what makes Tier 1/3 tests tractable.
- **Database access goes through the worker thread.** Always.
No direct `rusqlite::Connection` use outside `db.rs`.
- **Schema mutations update metadata in the same transaction.**
See ADR-0012 / ADR-0013. Adding a new DDL operation must keep
the column- and relationship-metadata tables in sync.
- **Renderer is pure render of `App` state.** It reports
viewport metrics back via `note_output_viewport` so subsequent
scroll input is wrap-aware.
## Working style for this project
- **Documentation discipline.** Significant decisions get an
ADR. In-flight discussion stays in conversation or issues
until it settles. The ADR-0000 index-upkeep rule applies:
every ADR change updates `docs/adr/README.md` in the same
edit.
- **Testing.** Per the user's global standards, tests are
established before changes, bugs are reproduced with failing
tests before being fixed, and "all green, no skips" is the
only acceptable end state. Integration tests exercise full
flows.
- **No silent feature loss.** Anything in an ADR is decided. If
implementation reveals that a decision is wrong or
impractical, raise it explicitly and update the ADR — do not
quietly drift.
- **Pedagogy wins ties.** When a design choice trades clarity
for raw capability, prefer clarity. Real RDBMS power-user
features exist; this app is not the place to teach them.
- **No engine name in user-facing strings.** The choice of
database engine is an implementation detail per ADR-0002
(User-facing posture). Error messages, success notes,
help text, and any other user-visible string refer to
"the database" or "the engine" in the abstract — never
the specific product (SQLite, STRICT, rusqlite, PRAGMA).
ADR-internal prose and code comments may name it where
technically necessary for precision.
- **Confirm commits.** Per the user's global rules, every
`git commit` is preceded by an explicit message proposal
and user approval. No AI attribution in commit messages.
## Things deliberately deferred
These are explicitly tracked (mostly in `requirements.md`) but
not yet implemented:
- **Project storage** (track 2): largely implemented through
Iteration 4 + cleanup pass + safety hardening (Iterations
14 of ADR-0015). Pending pieces: `export` / `import` (Iter
5), `--resume` + persistent input history hydration +
migration framework scaffold (Iter 6).
- **Complex WHERE expressions** (C5a): implemented through
ADR-0026 steps 14 — the stratified expression grammar
(AND/OR/NOT, the six comparisons, LIKE/IN/BETWEEN/IS NULL,
parentheses) reached through a new `Subgrammar` node, the
recursive `Expr` AST + parameterised SQL, and `where` /
`limit` on `show data`. Type-mismatched comparisons run
permissively (§7). Still pending: the §7 advisory
*flagging* of type mismatches / `= NULL`, the seam with
ADR-0027's diagnostics-severity model.
- **SQL handling in advanced mode** (Q1): `sqlparser-rs` parser
+ a defined SQL subset (Q4 — its own ADR).
- **Column drops/renames/type changes** (B2 / C2 partial): the
rebuild-table primitive (ADR-0013) is in place; the grammar
and dispatch are pending.
- **Indexes**: `add index` / `drop index` done (ADR-0025).
`EXPLAIN QUERY PLAN` (QA1 / QA2) is designed in ADR-0028 —
the `explain` prefix command + span-styled plan tree —
but not yet implemented.
- **Modify relationship** (C3a): drop+add covers the use case
today.
- **m:n convenience** (C4): auto-generates a junction table
with appropriate FKs — depends on relationships being solid
(they are).
- **Friendly error layer** (H1): partial — FK errors are
enriched both ways; full SQL→English translation pending.
- **Strong syntax-help in parse errors** (H1a): point users at
missing keywords/clauses rather than the unexpected
character.
- **Snapshot/replay/undo** (U-series): designed in ADR-0006;
not yet implemented.
- **Tutorial/lesson system**: acknowledged as in scope for
design; needs its own ADR.
- **Session log + Markdown export** (V4): the bigger UX
project — scrollable session journal, smart structure
rendering, save-as-markdown.
- **Readline shortcuts** (I1b): Ctrl-A/Ctrl-E, Ctrl-W/Ctrl-K/
Ctrl-U.
- **Multi-line input** (I1): Enter inserts newline,
Ctrl-Enter submits.
- **Tab completion** (I3), **syntax highlighting** (I4).
- **ER diagram export** (V3).
- **CI** (TT5): test infrastructure exists; CI workflow not
yet configured.
## Handoff notes
When taking over a session, read in order:
1. `docs/handoff/` — most recent file gives session context.
2. `CLAUDE.md` (this file).
3. `docs/requirements.md` — current progress on each item.
4. `docs/adr/README.md` and any ADR you'll touch.