d17addddd7
Add the `explain` prefix command — `explain show data`,
`explain update`, `explain delete` — from grammar through to a
rendered plan tree.
- Grammar: an `EXPLAIN` CommandNode whose shape is a Choice over
the three explainable query shapes, referenced (not
duplicated) through `Subgrammar`. `Command::Explain { query:
Box<Self> }`; `build_show_data` is extracted so the role-based
builders serve both standalone and explain-wrapped commands.
- Worker: SQL construction is split out of do_query_data /
do_update / do_delete into `build_*_sql`, so EXPLAIN QUERY
PLAN runs the exact same statement. `Request::ExplainPlan` /
`do_explain_plan` capture the plan; `QueryPlan` / `ExplainRow`
carry it back. EXPLAIN QUERY PLAN never executes, so
explaining update/delete changes nothing.
- Display SQL: the executed statement with `?N` parameters
inlined as standard-SQL literals via a quote-aware scan.
- Render: `render_explain_plan` draws the box-drawing plan tree
(plain output; ADR-0028 step 4 adds the styled tree).
- Catalog: `parse.usage.explain` and the `help.data.explain`
entry, so `explain` shows up in the in-app `help` listing.
1151 tests pass (+18); clippy clean.
161 lines
5.7 KiB
Rust
161 lines
5.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::{
|
|
AddColumnResult, ChangeColumnTypeResult, DataResult, DbError, DeleteResult,
|
|
DropColumnResult, InsertResult, QueryPlan, 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 },
|
|
/// An `explain …` command succeeded (ADR-0028). `plan`
|
|
/// carries the captured query plan; nothing was executed.
|
|
DslExplainSucceeded { command: Command, plan: QueryPlan },
|
|
DslInsertSucceeded {
|
|
command: Command,
|
|
result: InsertResult,
|
|
},
|
|
DslUpdateSucceeded {
|
|
command: Command,
|
|
result: UpdateResult,
|
|
},
|
|
DslDeleteSucceeded {
|
|
command: Command,
|
|
result: DeleteResult,
|
|
},
|
|
/// 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,
|
|
},
|
|
/// 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,
|
|
},
|
|
/// 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,
|
|
},
|
|
/// 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,
|
|
},
|
|
/// 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),
|
|
/// 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 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), and the
|
|
/// seed entries for input-history hydration off the new
|
|
/// project's `history.log` (I2-persist, ADR-0015 §12).
|
|
ProjectSwitched {
|
|
display_name: String,
|
|
is_temp: bool,
|
|
history_entries: Vec<String>,
|
|
},
|
|
/// 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,
|
|
},
|
|
/// 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,
|
|
},
|
|
}
|