Files
rdbms-playground/src/action.rs
T
claude@clouddev1 04c8e4295f feat: DSL→SQL teaching echo — channel + create-table slice (ADR-0037 + ADR-0038)
Walking skeleton validating the whole echo architecture end to end; the
Command→SQL renderer currently covers `create table`, with the rest of
Bucket A / B / category-3 to follow (ADR-0038 §8).

- Channel (ADR-0037): the three-way EffectiveMode (reusing the existing
  enum, not a new SubmissionMode — recorded in the ADR) rides on
  Action::ExecuteDsl to the runtime. `replay` bypasses the interactive
  spawn, so it never echoes (silent, for free).
- Echo (ADR-0038): built at the runtime's ExecuteDsl dispatch — the worker
  gets decomposed calls, not the Command, so ADR §4's "worker builds it"
  was corrected to the dispatch layer. Gated by echo_for (advanced
  effective mode + DSL-form). Carried on DslSucceeded; rendered by
  note_ok_summary as `Executing SQL: …` immediately beneath `[ok]`. New
  src/echo.rs renderer; echo.executing_sql i18n key.
- command_to_sql: `create table` → `CREATE TABLE T (id serial PRIMARY KEY)`
  (single inline / compound table-level PK), playground type vocabulary,
  round-trip-verified against the advanced walker (the §1 contract).

Tests: echo.rs (render, round-trip contract, mode gate, Sql*-not-echoed);
app.rs (submit carries the 3-way mode; echo renders beneath [ok]).
Suite 1970/0/1; clippy clean.
2026-05-27 22:09:54 +00:00

133 lines
5.5 KiB
Rust

//! Actions returned by the application's update function.
//!
//! `update` is pure with respect to the runtime: it mutates
//! state in place and returns a list of `Action`s for the
//! runtime to enact (quit, dispatch a DSL command to the
//! database, etc.). Side effects belong here, not in update
//! itself, which keeps update directly testable without a Tokio
//! runtime, a real terminal, or a database.
use crate::app::EffectiveMode;
use crate::dsl::Command;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Action {
/// Stop the event loop and exit cleanly.
Quit,
/// Hand a parsed DSL command to the database worker.
///
/// `command` is the parsed AST that the worker executes;
/// `source` is the original user-typed text, retained for
/// `history.log` per ADR-0015 §5. The runtime feeds the
/// result back as `AppEvent::DslSucceeded` /
/// `AppEvent::DslFailed`.
ExecuteDsl {
command: Command,
source: String,
/// The effective mode the line was submitted under (ADR-0037):
/// `Simple` / `AdvancedPersistent` / `AdvancedOneShot`. Output-only
/// — execution semantics do not depend on it; the runtime uses it
/// to gate the DSL → SQL teaching echo (ADR-0038), which fires for
/// DSL-form commands submitted in an advanced effective mode.
submission_mode: EffectiveMode,
},
/// Record a *failed* submission to `history.log` as an `err`
/// record (ADR-0034 §1/§2). Emitted by the pure-sync `App`
/// for both failure kinds — a line that failed to parse (at
/// submit) and a command the worker rejected (on
/// `AppEvent::DslFailed`) — because the App does no I/O. The
/// runtime appends best-effort: a failure to record a failure
/// must never escalate a user error into a fatal (ADR-0034
/// §4). `source` is the original user-typed text.
JournalFailure {
source: String,
},
/// User issued the `rebuild` app-level command (ADR-0015
/// §7, §11). Runtime computes a summary from
/// `project.yaml` + `data/` and posts back as
/// `AppEvent::RebuildPrepared`, which opens the
/// confirmation modal.
PrepareRebuild,
/// User confirmed the rebuild from inside the modal.
/// Runtime wipes the current schema/data and reconstructs
/// from text sources.
Rebuild {
source: String,
},
/// Open the load-picker modal. Runtime lists projects in
/// the active data root and posts back as
/// `AppEvent::LoadPickerReady`.
OpenLoadPicker,
/// Switch to the project at `path` (absolute or relative
/// to the active data root). Runtime drops the current
/// project, opens the new one, refreshes app state.
LoadProject {
path: std::path::PathBuf,
source: String,
},
/// Save the current project to `target` and switch to it.
/// `target` is a name or absolute path; relative names
/// resolve against `<data-root>/projects/` per ADR-0015 §1.
SaveAs {
target: String,
source: String,
},
/// Close the current project (auto-save guarantees state
/// is on disk) and create a fresh auto-named temp.
NewProject {
source: String,
},
/// Export the current project to a zip file. `target` is
/// `None` for the default filename
/// (`YYYYMMDD-<projectname>-export-NN.zip`) under the
/// active data root, or `Some(path)` for an explicit
/// target. Relative paths resolve under
/// `<data-root>/`. Per ADR-0015 §11 the zip excludes
/// `playground.db` and `history.log`.
Export {
target: Option<String>,
source: String,
},
/// Import a previously-exported zip and switch to the
/// resulting project. `zip_path` is the user-typed path to
/// the source archive (relative to CWD or absolute).
/// `as_target` is the optional user-supplied destination
/// name; when `None`, the destination is derived from the
/// zip's top-level folder. Collisions auto-suffix `-NN`
/// (ADR-0015 §11 amendment).
Import {
zip_path: String,
as_target: Option<String>,
source: String,
},
/// Replay a script of DSL commands from a file. The runtime
/// reads the file, iterates non-blank/non-comment lines, and
/// dispatches each through the same path as interactive
/// input. On per-line failure the runtime reports the line
/// number and stops (no rollback). On success it reports the
/// number of commands run.
///
/// `path` is the literal user-typed path; the runtime
/// resolves relative paths against the active project's root
/// so `replay history.log` works inside any project. Replay
/// itself is NOT written to `history.log` — only the
/// individual commands it dispatches are, since they are
/// what mutate state.
Replay {
path: String,
},
/// User issued `undo` (`PrepareUndo`) or `redo` (`PrepareRedo`)
/// (ADR-0006 Amendment 1). The runtime peeks the snapshot the
/// command would restore and posts `AppEvent::UndoPrepared`
/// (opening the confirmation modal) or `AppEvent::UndoUnavailable`
/// (nothing to undo/redo). Only emitted when undo is enabled —
/// the `App` notes "undo is off" itself under `--no-undo`.
PrepareUndo,
PrepareRedo,
/// User confirmed `undo` / `redo` from inside the modal. The
/// runtime restores the snapshot through the worker, then
/// refreshes the table list + schema cache.
Undo,
Redo,
}