4aeea55984
Record the submission mode per history entry so advanced commands are reusable in simple mode, and fix the bug where a ':'-one-shot command lost its ':' across sessions (ADR-0052, closing #30). Format: the history.log status token gains an optional ':adv' suffix (ok / ok:adv / err / err:adv); 'source' stays last and canonical, so replay is unaffected. The in-memory ring (still Vec<String>) stores advanced entries ': '-prefixed; recall strips the ':' in advanced mode and keeps it in simple; hydration reconstructs the prefix from the tag. Journaling moved from the worker to the dispatch layer (spawn_dsl_- dispatch / run_replay / app-command sites), where the mode is in scope with no worker plumbing; finalize_persistence writes only yaml/csv (commit-db-last still atomic for state). The journal write is now best-effort (command already committed), consistent with the failure path. App commands journal simple, so they recall bare. Journaling is now uniform (every successful command, per ADR-0034) — closing a gap where show tables/relationships/explain didn't journal. Amends ADR-0034 (status tag + journaling location), ADR-0015 §6 (history.log out of the worker tx), ADR-0040 (journal-write best-effort). 15 worker-level journaling tests retired, re-covered at the new layer (history.rs format, app.rs recall matrix, iteration6 cross-session regression, replay). 2471 pass / 0 fail / 0 skip, clippy clean.
291 lines
12 KiB
Rust
291 lines
12 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::{
|
|
AddColumnResult, ChangeColumnTypeResult, DataResult, DbError, DeleteResult,
|
|
DropColumnResult, InsertResult, QueryPlan, RelationshipDiagramData, 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>,
|
|
/// The DSL → SQL teaching echo (ADR-0038): equivalent advanced-mode
|
|
/// SQL, built by the runtime when a DSL-form command ran in an
|
|
/// advanced effective mode (ADR-0037). `None` when no echo applies
|
|
/// (simple mode, SQL-entered, or a form with no echo). The App
|
|
/// renders it beneath `[ok]`.
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
/// A SQL `CREATE TABLE IF NOT EXISTS` matched an existing table —
|
|
/// a no-op (ADR-0035 §4). Renders the existing structure plus an
|
|
/// "already exists — skipped" note.
|
|
DslCreateSkipped {
|
|
command: Command,
|
|
description: TableDescription,
|
|
},
|
|
/// A SQL `DROP TABLE IF EXISTS` matched no table — a no-op
|
|
/// (ADR-0035 §4, 4c). Renders a "doesn't exist — skipped" note;
|
|
/// there is no structure to show.
|
|
DslDropSkipped {
|
|
command: Command,
|
|
},
|
|
/// A SQL `DROP INDEX IF EXISTS` matched no index — a no-op
|
|
/// (ADR-0035 §4d). Renders an index-specific "doesn't exist —
|
|
/// skipped" note; no structure to show.
|
|
DslDropIndexSkipped {
|
|
command: Command,
|
|
},
|
|
/// A SQL `CREATE INDEX IF NOT EXISTS` matched an existing index name
|
|
/// — a no-op (ADR-0035 §4d). `name` is the resolved index name (the
|
|
/// auto-name is not on the command). Renders "already exists —
|
|
/// skipped"; no structure to show.
|
|
DslCreateIndexSkipped {
|
|
command: Command,
|
|
name: String,
|
|
},
|
|
/// A `show data` query succeeded. `echo` is the DSL → SQL teaching
|
|
/// echo (ADR-0038) — built post-execution because the limited form
|
|
/// orders by the table's primary key (handoff §5). `None` for a
|
|
/// SQL-entered `SELECT` or any simple-mode submission.
|
|
DslDataSucceeded {
|
|
command: Command,
|
|
data: DataResult,
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
/// An `explain …` command succeeded (ADR-0028). `plan`
|
|
/// carries the captured query plan; nothing was executed.
|
|
DslExplainSucceeded { command: Command, plan: QueryPlan },
|
|
/// A `show <kind>` list command (V5) — carries pre-formatted
|
|
/// display lines (tables / relationships / indexes).
|
|
DslShowListSucceeded { command: Command, lines: Vec<String> },
|
|
/// `show relationship <name>` (ADR-0044) — structured data for the
|
|
/// diagram, rendered App-side; `None` when no such relationship.
|
|
DslShowRelationshipSucceeded {
|
|
command: Command,
|
|
data: Option<RelationshipDiagramData>,
|
|
},
|
|
DslInsertSucceeded {
|
|
command: Command,
|
|
result: InsertResult,
|
|
},
|
|
DslSeedSucceeded {
|
|
command: Command,
|
|
result: crate::db::SeedResult,
|
|
},
|
|
DslUpdateSucceeded {
|
|
command: Command,
|
|
result: UpdateResult,
|
|
/// The DSL → SQL teaching echo (ADR-0038): `UPDATE T SET …` for an
|
|
/// `update … --all-rows` fall-through. `None` for a SQL-entered
|
|
/// `UPDATE` or any simple-mode submission.
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
DslDeleteSucceeded {
|
|
command: Command,
|
|
result: DeleteResult,
|
|
/// The DSL → SQL teaching echo (ADR-0038): `DELETE FROM T` for a
|
|
/// `delete … --all-rows` fall-through. `None` for a SQL-entered
|
|
/// `DELETE` or any simple-mode submission.
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
/// A `change column …` succeeded. `result` carries both the
|
|
/// post-rebuild description (for the auto-show) and the
|
|
/// optional `[client-side]` note (ADR-0017 §6).
|
|
DslChangeColumnSucceeded {
|
|
command: Command,
|
|
result: ChangeColumnTypeResult,
|
|
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T ALTER
|
|
/// COLUMN c SET DATA TYPE …`. `None` in simple mode.
|
|
echo: Option<Vec<String>>,
|
|
/// The `--dont-convert` caveat (ADR-0038 §6 category 3): set by the
|
|
/// runtime to `true` when the command ran with
|
|
/// `ChangeColumnMode::DontConvert` in an advanced effective mode
|
|
/// (the only case where it is meaningful — the line references
|
|
/// "the line above," i.e. the echo). The App renders the prose
|
|
/// caveat between the existing client-side notes and the structure.
|
|
dont_convert_caveat: bool,
|
|
},
|
|
/// An `add column …` succeeded. `result` carries the
|
|
/// post-add description plus any `[client-side]` notes
|
|
/// from the auto-fill paths (ADR-0018 §9).
|
|
DslAddColumnSucceeded {
|
|
command: Command,
|
|
result: AddColumnResult,
|
|
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T ADD
|
|
/// COLUMN c <ty> …`. `None` in simple mode.
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
/// A `drop column …` succeeded. `result` carries the
|
|
/// post-drop description plus the names of any indexes
|
|
/// removed by `--cascade` (ADR-0025).
|
|
DslDropColumnSucceeded {
|
|
command: Command,
|
|
result: DropColumnResult,
|
|
/// The DSL → SQL teaching echo (ADR-0038): `ALTER TABLE T DROP
|
|
/// COLUMN c` for a plain (non-`--cascade`) drop. `None` in simple
|
|
/// mode, and for `--cascade` (a multi-statement echo, Phase 2).
|
|
echo: Option<Vec<String>>,
|
|
},
|
|
/// A DSL command failed. `error` is the structured
|
|
/// payload, `facts` is the runtime-built schema-resolved
|
|
/// enrichment (parent tables, attempted values,
|
|
/// pinpointed offending rows). App applies its current
|
|
/// verbosity setting (`messages_verbosity`) when rendering
|
|
/// through `friendly::translate_error` (ADR-0019 §5, §6).
|
|
DslFailed {
|
|
command: Command,
|
|
error: DbError,
|
|
facts: crate::friendly::FailureContext,
|
|
/// The original user-typed source line, retained so the
|
|
/// App can journal the failed command as an `err` record
|
|
/// (ADR-0034 §1/§2). The worker only journals successful
|
|
/// commands, so an execution failure would otherwise be
|
|
/// lost across sessions.
|
|
source: String,
|
|
/// Whether the rejected command was submitted in an advanced
|
|
/// effective mode (ADR-0052): threaded so the App can tag the
|
|
/// `err` record `err:adv` and the failed advanced command
|
|
/// hydrates in its `:`-prefixed, simple-mode-recallable form.
|
|
advanced: bool,
|
|
},
|
|
/// Refreshed list of tables in the database.
|
|
TablesRefreshed(Vec<String>),
|
|
/// Refreshed schema lookup cache feeding Tab completion
|
|
/// for identifier slots (ADR-0022 §9 + stage 8d). Runtime
|
|
/// posts this alongside `TablesRefreshed` after project
|
|
/// load and after every successful DDL.
|
|
SchemaCacheRefreshed(crate::completion::SchemaCache),
|
|
/// Refreshed list of relationships as full schema records, for the
|
|
/// sidebar relationships panel (ADR-0046 DB2). Posted by the runtime
|
|
/// alongside `SchemaCacheRefreshed` after every schema refresh.
|
|
RelationshipsRefreshed(Vec<crate::persistence::RelationshipSchema>),
|
|
/// 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,
|
|
},
|
|
/// Runtime has computed the rebuild summary from
|
|
/// `project.yaml` + `data/` and is ready for the user to
|
|
/// confirm. App opens the confirmation modal.
|
|
RebuildPrepared {
|
|
summary: String,
|
|
},
|
|
/// Rebuild completed successfully. App closes the modal,
|
|
/// surfaces a friendly outcome message, and refreshes the
|
|
/// table list.
|
|
RebuildSucceeded {
|
|
summary: String,
|
|
},
|
|
/// Rebuild failed in a non-fatal way (e.g., user-visible
|
|
/// constraint problem) — surfaced like other DSL failures.
|
|
RebuildFailed {
|
|
error: String,
|
|
},
|
|
/// Runtime peeked the snapshot `undo`/`redo` would restore and
|
|
/// is ready for the user to confirm (ADR-0006 Amendment 1). App
|
|
/// opens the confirmation modal naming `command`. `is_redo`
|
|
/// selects undo vs redo wording.
|
|
UndoPrepared {
|
|
command: String,
|
|
timestamp: String,
|
|
is_redo: bool,
|
|
},
|
|
/// Nothing to undo / redo (the ring or redo stack was empty).
|
|
/// App surfaces a friendly note.
|
|
UndoUnavailable {
|
|
is_redo: bool,
|
|
},
|
|
/// Undo / redo completed. App closes the modal, notes the
|
|
/// command that was undone/redone; the runtime also refreshes
|
|
/// the table list + schema cache.
|
|
UndoSucceeded {
|
|
command: String,
|
|
is_redo: bool,
|
|
},
|
|
/// Undo / redo failed (a rare restore error). App closes the
|
|
/// modal and surfaces the error.
|
|
UndoFailed {
|
|
error: String,
|
|
is_redo: bool,
|
|
},
|
|
/// Runtime has gathered the list of available projects
|
|
/// for the load picker. App opens the picker modal.
|
|
LoadPickerReady {
|
|
entries: Vec<crate::app::LoadPickerEntry>,
|
|
},
|
|
/// A project switch (load / new / save-as / import)
|
|
/// succeeded. Carries the new display name, the temp
|
|
/// flag (drives the `[TEMP]` status-bar prefix), the
|
|
/// seed entries for input-history hydration off the new
|
|
/// project's `history.log` (I2-persist, ADR-0015 §12), and
|
|
/// the mode to restore for the switched-to project (its
|
|
/// stored mode, ADR-0015 mode-restore amendment, issue #14 —
|
|
/// "loading triggers the mode switch each time").
|
|
ProjectSwitched {
|
|
display_name: String,
|
|
is_temp: bool,
|
|
history_entries: Vec<String>,
|
|
mode: crate::mode::Mode,
|
|
},
|
|
/// A project switch failed in a non-fatal way (target
|
|
/// already exists, path unreadable, …). Surfaced as an
|
|
/// error in the output panel.
|
|
ProjectSwitchFailed {
|
|
error: String,
|
|
},
|
|
/// Export wrote a zip successfully. Carries the resolved
|
|
/// final path so the user gets a "wrote to: …" note.
|
|
ExportSucceeded {
|
|
path: std::path::PathBuf,
|
|
},
|
|
/// Export failed in a non-fatal way (target exists, IO
|
|
/// error, sequence range exhausted, …).
|
|
ExportFailed {
|
|
error: String,
|
|
},
|
|
/// A `replay <path>` finished without error, after running
|
|
/// `count` non-blank, non-comment commands from the file.
|
|
/// Surfaced as `[ok] replay — N command(s)` in the output.
|
|
ReplayCompleted {
|
|
path: String,
|
|
count: usize,
|
|
/// Pre-rendered `[skip]` warnings for app-lifecycle commands
|
|
/// whose omission can leave the replayed state incomplete —
|
|
/// `import` and a nested `replay` (ADR-0034). Other skipped
|
|
/// app commands are silent and do not appear here.
|
|
warnings: Vec<String>,
|
|
},
|
|
/// A `replay <path>` aborted at line `line_number`. `command`
|
|
/// is the line text as it appeared in the file (for the
|
|
/// user's eyeline so they can locate the failing entry);
|
|
/// `error` is the rendered parse or runtime error.
|
|
ReplayFailed {
|
|
path: String,
|
|
line_number: usize,
|
|
command: String,
|
|
error: String,
|
|
},
|
|
}
|