Files
rdbms-playground/src/event.rs
T
claude@clouddev1 5c076f6d8f Iteration 2: per-command write-through to project.yaml, CSVs, history.log
Every successful user command now persists through to YAML, the
affected CSVs, and history.log inside the same SQLite transaction,
with the commit-db-last ordering from ADR-0015 §6: validate ->
mutate -> stage text + fsync -> atomic rename -> append history ->
commit. A failure in any text-write step rolls back the SQLite tx,
so disk state is unchanged on failure. Persistence failures are
routed through a new AppEvent::PersistenceFatal which sets a
fatal_message on the App, emits Action::Quit, and is printed to
stderr after terminal teardown so the banner remains above the
shell prompt (ADR-0015 §8).

New persistence module owns the file formats: hand-rolled YAML
schema writer, per-type CSV encoder (RFC 4180, NULL distinct from
empty string, base64 blobs), append-only history.log with ISO-8601
timestamps and successful-only entries. Atomic per-file writes via
tmp + fsync + rename.

The db worker holds an Option<Persistence>; tests still use
Database::open(":memory:") with no persistence. Action::ExecuteDsl
gains a source field carrying the user-typed text, threaded
through to history.log.

Tests: 289 passing (256 lib + 7 new integration + 9 lifecycle + 17
walking-skeleton), 0 failing, 0 skipped. Clippy clean with nursery
lints.
2026-05-07 21:09:15 +00:00

59 lines
1.7 KiB
Rust

//! Events fed into the application's update function.
//!
//! `AppEvent` is the single input type the runtime delivers to
//! `App::update`. Synthetic instances drive Tier 3 integration
//! tests (see ADR-0008), so the type is plain data with no
//! runtime dependency.
use crossterm::event::KeyEvent;
use crate::db::{DataResult, DeleteResult, InsertResult, TableDescription, UpdateResult};
use crate::dsl::Command;
#[derive(Debug, Clone)]
pub enum AppEvent {
Key(KeyEvent),
Resize {
cols: u16,
rows: u16,
},
Tick,
/// A DSL command finished successfully. `description` is
/// `Some` for commands that produce a table view (create,
/// add column) and `None` for commands that don't (drop).
DslSucceeded {
command: Command,
description: Option<TableDescription>,
},
/// A `show data` query succeeded.
DslDataSucceeded { command: Command, data: DataResult },
DslInsertSucceeded {
command: Command,
result: InsertResult,
},
DslUpdateSucceeded {
command: Command,
result: UpdateResult,
},
DslDeleteSucceeded {
command: Command,
result: DeleteResult,
},
/// A DSL command failed. `error` is already a friendly
/// message produced via `DbError::friendly_message`.
DslFailed {
command: Command,
error: String,
},
/// Refreshed list of tables in the database.
TablesRefreshed(Vec<String>),
/// A persistence failure occurred (ADR-0015 §8). The
/// application surfaces a fatal banner and exits cleanly so
/// the message remains above the shell prompt.
PersistenceFatal {
operation: String,
path: std::path::PathBuf,
message: String,
},
}