style: format the whole tree with cargo fmt (stock defaults, #35)
One-time, mechanical reformat — no functional changes. The tree was not rustfmt-clean (~1800 hunks across ~100 files); this brings it to stock `cargo fmt` defaults so a `cargo fmt --check` CI gate can follow. Behaviour-preserving: 2509 pass / 0 fail / 1 ignored (unchanged baseline), clippy clean. A .git-blame-ignore-revs entry follows so `git blame` skips this commit.
This commit is contained in:
+125
-149
@@ -36,8 +36,8 @@ use crate::db::{
|
||||
use crate::dsl::command::{
|
||||
Constraint, ConstraintKind, IndexSelector, RelationshipSelector, TableConstraint,
|
||||
};
|
||||
use crate::dsl::{AlterTableAction, ChangeColumnMode, Command, ColumnSpec};
|
||||
use crate::dsl::walker::Severity;
|
||||
use crate::dsl::{AlterTableAction, ChangeColumnMode, ColumnSpec, Command};
|
||||
use crate::event::AppEvent;
|
||||
use crate::project::{
|
||||
Project, ProjectKind, copy_project, list_projects, open_or_create, projects_dir,
|
||||
@@ -130,8 +130,7 @@ pub async fn run(args: Args) -> Result<()> {
|
||||
// to it for `new` (creates a temp) and `load` (lists
|
||||
// projects). We can't easily recover this from the
|
||||
// Project alone, so we keep it ourselves.
|
||||
let data_root = resolve_data_root(args.data_dir.as_deref())
|
||||
.context("resolve data root")?;
|
||||
let data_root = resolve_data_root(args.data_dir.as_deref()).context("resolve data root")?;
|
||||
|
||||
// Resolve the initial project path: --resume reads it from
|
||||
// <data-root>/last_project; otherwise an explicit positional
|
||||
@@ -143,17 +142,12 @@ pub async fn run(args: Args) -> Result<()> {
|
||||
// terminal so the message lands directly in the user's
|
||||
// shell.
|
||||
let initial_path: Option<PathBuf> = if args.resume {
|
||||
match read_last_project(&data_root)
|
||||
.context("read last_project")?
|
||||
{
|
||||
match read_last_project(&data_root).context("read last_project")? {
|
||||
Some(p) if p.exists() => Some(p),
|
||||
Some(p) => {
|
||||
eprintln!(
|
||||
"rdbms-playground: {}",
|
||||
crate::t!(
|
||||
"project.resume_recorded_missing",
|
||||
path = p.display(),
|
||||
),
|
||||
crate::t!("project.resume_recorded_missing", path = p.display(),),
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
@@ -488,19 +482,15 @@ async fn run_loop(
|
||||
// Best-effort — a failure to record a failure must
|
||||
// never escalate a user error into a fatal, so the
|
||||
// result is logged and ignored.
|
||||
if let Err(e) = crate::persistence::Persistence::new(
|
||||
session.project().path().to_path_buf(),
|
||||
)
|
||||
.append_history_failure(&source, advanced)
|
||||
if let Err(e) =
|
||||
crate::persistence::Persistence::new(session.project().path().to_path_buf())
|
||||
.append_history_failure(&source, advanced)
|
||||
{
|
||||
tracing::warn!(error = %e, "failed to journal err record (ignored)");
|
||||
}
|
||||
}
|
||||
Action::PrepareRebuild => {
|
||||
spawn_prepare_rebuild(
|
||||
session.project().path().to_path_buf(),
|
||||
event_tx.clone(),
|
||||
);
|
||||
spawn_prepare_rebuild(session.project().path().to_path_buf(), event_tx.clone());
|
||||
}
|
||||
Action::Rebuild { source } => {
|
||||
spawn_rebuild(
|
||||
@@ -671,8 +661,8 @@ async fn run_loop(
|
||||
// mutually exclusive (one needs an unmodified temp, the
|
||||
// other anything else).
|
||||
let project_at_quit = session.project.as_ref();
|
||||
let cleanup_on_quit: Option<std::path::PathBuf> = project_at_quit
|
||||
.and_then(|p| p.is_unmodified_temp().then(|| p.path().to_path_buf()));
|
||||
let cleanup_on_quit: Option<std::path::PathBuf> =
|
||||
project_at_quit.and_then(|p| p.is_unmodified_temp().then(|| p.path().to_path_buf()));
|
||||
let resume_target_on_quit: Option<std::path::PathBuf> = project_at_quit
|
||||
.filter(|p| !p.is_unmodified_temp())
|
||||
.map(|p| p.path().to_path_buf());
|
||||
@@ -831,7 +821,10 @@ async fn perform_switch(
|
||||
Some(p)
|
||||
}
|
||||
SwitchRequest::NewTemp => None,
|
||||
SwitchRequest::Import { zip_path, as_target } => {
|
||||
SwitchRequest::Import {
|
||||
zip_path,
|
||||
as_target,
|
||||
} => {
|
||||
if !zip_path.exists() {
|
||||
return Err(crate::t!(
|
||||
"project.import_zip_missing",
|
||||
@@ -840,8 +833,7 @@ async fn perform_switch(
|
||||
}
|
||||
// Validate the zip up front so we don't drop the
|
||||
// current project for an unimportable file.
|
||||
let inspection = crate::archive::inspect_zip(zip_path)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let inspection = crate::archive::inspect_zip(zip_path).map_err(|e| e.to_string())?;
|
||||
let resolved = resolve_import_destination(
|
||||
as_target.as_deref(),
|
||||
&inspection.top_folder,
|
||||
@@ -856,16 +848,19 @@ async fn perform_switch(
|
||||
// state matches the in-memory db).
|
||||
if let SwitchRequest::SaveAs { .. } = &req {
|
||||
let src = session.project().path().to_path_buf();
|
||||
let dst = resolved_target.as_ref().expect("SaveAs has resolved target");
|
||||
let dst = resolved_target
|
||||
.as_ref()
|
||||
.expect("SaveAs has resolved target");
|
||||
copy_project(&src, dst).map_err(|e| e.to_string())?;
|
||||
}
|
||||
// For Import: extract the zip into the resolved target.
|
||||
// We do this *before* dropping the current project so
|
||||
// a failure here leaves the user where they were.
|
||||
if let SwitchRequest::Import { zip_path, .. } = &req {
|
||||
let dst = resolved_target.as_ref().expect("Import has resolved target");
|
||||
let inspection = crate::archive::inspect_zip(zip_path)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let dst = resolved_target
|
||||
.as_ref()
|
||||
.expect("Import has resolved target");
|
||||
let inspection = crate::archive::inspect_zip(zip_path).map_err(|e| e.to_string())?;
|
||||
crate::archive::extract_into(zip_path, dst, &inspection.top_folder)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
@@ -874,10 +869,10 @@ async fn perform_switch(
|
||||
// we drop it: if it was an unmodified empty temp, we
|
||||
// delete its directory after the switch so the data dir
|
||||
// doesn't accumulate empty scratch projects.
|
||||
let outgoing_cleanup_path: Option<std::path::PathBuf> =
|
||||
session.project.as_ref().and_then(|p| {
|
||||
p.is_unmodified_temp().then(|| p.path().to_path_buf())
|
||||
});
|
||||
let outgoing_cleanup_path: Option<std::path::PathBuf> = session
|
||||
.project
|
||||
.as_ref()
|
||||
.and_then(|p| p.is_unmodified_temp().then(|| p.path().to_path_buf()));
|
||||
|
||||
// Drop current project + database BEFORE opening the new
|
||||
// ones, releasing the old lock and stopping the old
|
||||
@@ -954,9 +949,7 @@ async fn perform_switch(
|
||||
let new_database =
|
||||
Database::open_with_persistence_and_undo(&db_path, persistence, undo_enabled)
|
||||
.map_err(|e| e.to_string())?;
|
||||
if !db_existed
|
||||
&& let Err(e) = new_database.rebuild_from_text(new_path.clone(), None).await
|
||||
{
|
||||
if !db_existed && let Err(e) = new_database.rebuild_from_text(new_path.clone(), None).await {
|
||||
return Err(e.friendly_message());
|
||||
}
|
||||
|
||||
@@ -982,9 +975,7 @@ async fn perform_switch(
|
||||
// fresh empty temp (a `new` command), which must not be
|
||||
// recorded (see the gate in `run()`). Write failures are
|
||||
// non-fatal.
|
||||
if new_worth_recording
|
||||
&& let Err(e) = write_last_project(&session.data_root, &new_path)
|
||||
{
|
||||
if new_worth_recording && let Err(e) = write_last_project(&session.data_root, &new_path) {
|
||||
tracing::warn!(error = %e, "could not update last_project after switch");
|
||||
}
|
||||
|
||||
@@ -1045,8 +1036,8 @@ fn spawn_export(
|
||||
event_tx: mpsc::Sender<AppEvent>,
|
||||
) {
|
||||
// `export` app command: journalled simple (ADR-0052).
|
||||
let _ = crate::persistence::Persistence::new(project_path.clone())
|
||||
.append_history(&source, false);
|
||||
let _ =
|
||||
crate::persistence::Persistence::new(project_path.clone()).append_history(&source, false);
|
||||
tokio::spawn(async move {
|
||||
let outcome = tokio::task::spawn_blocking(move || {
|
||||
do_export(&project_path, &project_name, &data_root, target.as_deref())
|
||||
@@ -1081,9 +1072,8 @@ fn do_export(
|
||||
}
|
||||
None => {
|
||||
std::fs::create_dir_all(data_root).map_err(|e| e.to_string())?;
|
||||
let (filename, _) =
|
||||
crate::archive::next_export_sequence(data_root, project_name)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let (filename, _) = crate::archive::next_export_sequence(data_root, project_name)
|
||||
.map_err(|e| e.to_string())?;
|
||||
data_root.join(filename)
|
||||
}
|
||||
};
|
||||
@@ -1143,10 +1133,7 @@ async fn seed_initial_tables(database: &Database, event_tx: &mpsc::Sender<AppEve
|
||||
/// no completion. Called wherever `TablesRefreshed` is sent
|
||||
/// today; the schema cache lives on the App and feeds Tab
|
||||
/// completion for identifier slots.
|
||||
async fn refresh_schema_cache(
|
||||
database: &Database,
|
||||
event_tx: &mpsc::Sender<AppEvent>,
|
||||
) {
|
||||
async fn refresh_schema_cache(database: &Database, event_tx: &mpsc::Sender<AppEvent>) {
|
||||
let cache = build_schema_cache(database).await;
|
||||
let _ = event_tx.send(AppEvent::SchemaCacheRefreshed(cache)).await;
|
||||
// ADR-0046 DB2: full relationship records for the sidebar panel.
|
||||
@@ -1234,10 +1221,7 @@ async fn build_schema_cache(database: &Database) -> crate::completion::SchemaCac
|
||||
/// summary that the confirmation modal shows. Runs off the
|
||||
/// event loop so the brief I/O doesn't stall input handling
|
||||
/// even on slow filesystems.
|
||||
fn spawn_prepare_rebuild(
|
||||
project_path: std::path::PathBuf,
|
||||
event_tx: mpsc::Sender<AppEvent>,
|
||||
) {
|
||||
fn spawn_prepare_rebuild(project_path: std::path::PathBuf, event_tx: mpsc::Sender<AppEvent>) {
|
||||
tokio::spawn(async move {
|
||||
let summary = match summarize_project(&project_path) {
|
||||
Ok(s) => s,
|
||||
@@ -1317,9 +1301,7 @@ fn spawn_rebuild(
|
||||
}
|
||||
let summary = summarize_project(&project_path)
|
||||
.unwrap_or_else(|_| "rebuild complete".to_string());
|
||||
let _ = event_tx
|
||||
.send(AppEvent::RebuildSucceeded { summary })
|
||||
.await;
|
||||
let _ = event_tx.send(AppEvent::RebuildSucceeded { summary }).await;
|
||||
// Refresh the table list so the items panel
|
||||
// reflects whatever the rebuild produced.
|
||||
if let Ok(tables) = database.list_tables().await {
|
||||
@@ -1462,12 +1444,8 @@ fn spawn_dsl_dispatch(
|
||||
}
|
||||
let event = match outcome {
|
||||
Ok(CommandOutcome::Schema(description)) => {
|
||||
let schema_echo = build_schema_echo(
|
||||
&command,
|
||||
submission_mode,
|
||||
description.as_ref(),
|
||||
&lookups,
|
||||
);
|
||||
let schema_echo =
|
||||
build_schema_echo(&command, submission_mode, description.as_ref(), &lookups);
|
||||
AppEvent::DslSucceeded {
|
||||
command: command.clone(),
|
||||
description,
|
||||
@@ -1484,12 +1462,10 @@ fn spawn_dsl_dispatch(
|
||||
Ok(CommandOutcome::SchemaDropIndexSkipped) => AppEvent::DslDropIndexSkipped {
|
||||
command: command.clone(),
|
||||
},
|
||||
Ok(CommandOutcome::SchemaCreateIndexSkipped(name)) => {
|
||||
AppEvent::DslCreateIndexSkipped {
|
||||
command: command.clone(),
|
||||
name,
|
||||
}
|
||||
}
|
||||
Ok(CommandOutcome::SchemaCreateIndexSkipped(name)) => AppEvent::DslCreateIndexSkipped {
|
||||
command: command.clone(),
|
||||
name,
|
||||
},
|
||||
Ok(CommandOutcome::Query(data)) => {
|
||||
// ADR-0038: `show data` is the only DSL-form query that
|
||||
// echoes; its limited form orders by the table's primary
|
||||
@@ -1507,12 +1483,10 @@ fn spawn_dsl_dispatch(
|
||||
command: command.clone(),
|
||||
lines,
|
||||
},
|
||||
Ok(CommandOutcome::ShowRelationship(data)) => {
|
||||
AppEvent::DslShowRelationshipSucceeded {
|
||||
command: command.clone(),
|
||||
data: data.map(|b| *b),
|
||||
}
|
||||
}
|
||||
Ok(CommandOutcome::ShowRelationship(data)) => AppEvent::DslShowRelationshipSucceeded {
|
||||
command: command.clone(),
|
||||
data: data.map(|b| *b),
|
||||
},
|
||||
Ok(CommandOutcome::QueryPlan(plan)) => AppEvent::DslExplainSucceeded {
|
||||
command: command.clone(),
|
||||
plan,
|
||||
@@ -1568,11 +1542,8 @@ fn spawn_dsl_dispatch(
|
||||
// the covering indexes the rebuild removed — Bucket B
|
||||
// category 2, ADR-0038 §7 Slice 2b). Non-cascade falls
|
||||
// through to the pre-execution `echo` from `echo_for`.
|
||||
let cascade_echo = build_drop_column_cascade_echo(
|
||||
&command,
|
||||
submission_mode,
|
||||
&result,
|
||||
);
|
||||
let cascade_echo =
|
||||
build_drop_column_cascade_echo(&command, submission_mode, &result);
|
||||
AppEvent::DslDropColumnSucceeded {
|
||||
command: command.clone(),
|
||||
result,
|
||||
@@ -1931,12 +1902,14 @@ fn build_schema_echo(
|
||||
)])
|
||||
}
|
||||
}
|
||||
Command::DropRelationship { .. } => lookups
|
||||
.drop_relationship
|
||||
.as_ref()
|
||||
.map(|(name, child_table)| {
|
||||
vec![crate::echo::render_drop_relationship(name, child_table)]
|
||||
}),
|
||||
Command::DropRelationship { .. } => {
|
||||
lookups
|
||||
.drop_relationship
|
||||
.as_ref()
|
||||
.map(|(name, child_table)| {
|
||||
vec![crate::echo::render_drop_relationship(name, child_table)]
|
||||
})
|
||||
}
|
||||
// `create m:n relationship` (ADR-0045): the resolved junction
|
||||
// columns/FKs only exist on the post-exec description, so the
|
||||
// teaching echo is rendered from it (not `command_to_sql`).
|
||||
@@ -1946,14 +1919,29 @@ fn build_schema_echo(
|
||||
.iter()
|
||||
.filter_map(|c| c.user_type.map(|ty| (c.name.clone(), ty)))
|
||||
.collect();
|
||||
let primary_key: Vec<String> =
|
||||
desc.columns.iter().filter(|c| c.primary_key).map(|c| c.name.clone()).collect();
|
||||
let primary_key: Vec<String> = desc
|
||||
.columns
|
||||
.iter()
|
||||
.filter(|c| c.primary_key)
|
||||
.map(|c| c.name.clone())
|
||||
.collect();
|
||||
let foreign_keys: Vec<(Vec<String>, String, Vec<String>)> = desc
|
||||
.outbound_relationships
|
||||
.iter()
|
||||
.map(|r| (r.local_columns.clone(), r.other_table.clone(), r.other_columns.clone()))
|
||||
.map(|r| {
|
||||
(
|
||||
r.local_columns.clone(),
|
||||
r.other_table.clone(),
|
||||
r.other_columns.clone(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
vec![crate::echo::render_create_m2n(&desc.name, &columns, &primary_key, &foreign_keys)]
|
||||
vec![crate::echo::render_create_m2n(
|
||||
&desc.name,
|
||||
&columns,
|
||||
&primary_key,
|
||||
&foreign_keys,
|
||||
)]
|
||||
}),
|
||||
// Everything else (Bucket A pure-Command, plus the no-echo Bucket C
|
||||
// variants like `Sql*` / `ShowTable`) routes through the existing
|
||||
@@ -2103,10 +2091,7 @@ async fn enrich_unique_violation(
|
||||
facts
|
||||
}
|
||||
|
||||
fn enrich_not_null_violation(
|
||||
command: &Command,
|
||||
message: &str,
|
||||
) -> crate::friendly::FailureContext {
|
||||
fn enrich_not_null_violation(command: &Command, message: &str) -> crate::friendly::FailureContext {
|
||||
let mut facts = crate::friendly::FailureContext::default();
|
||||
let Some((table, column)) = parse_qualified_target(message) else {
|
||||
return facts;
|
||||
@@ -2133,9 +2118,7 @@ async fn enrich_fk_violation(
|
||||
// schema-aware lookup so natural-order multi-value
|
||||
// INSERT (which `user_value_for_column` alone can't
|
||||
// resolve) gets handled too.
|
||||
let Ok((outbound, _)) =
|
||||
database.read_relationships(table.clone()).await
|
||||
else {
|
||||
let Ok((outbound, _)) = database.read_relationships(table.clone()).await else {
|
||||
return facts;
|
||||
};
|
||||
facts.table = Some(table.clone());
|
||||
@@ -2173,8 +2156,7 @@ async fn enrich_fk_violation(
|
||||
// children reference). Check inbound as a fallback.
|
||||
if facts.parent_table.is_none()
|
||||
&& matches!(command, Command::Update { .. })
|
||||
&& let Ok((_, inbound)) =
|
||||
database.read_relationships(table.clone()).await
|
||||
&& let Ok((_, inbound)) = database.read_relationships(table.clone()).await
|
||||
&& let Some(rel) = inbound.first()
|
||||
{
|
||||
facts.child_table = Some(rel.other_table.clone());
|
||||
@@ -2184,9 +2166,7 @@ async fn enrich_fk_violation(
|
||||
// Parent-side: inbound FK lookup. Surface a child
|
||||
// table that still references the row(s) being
|
||||
// deleted.
|
||||
let Ok((_, inbound)) =
|
||||
database.read_relationships(table.clone()).await
|
||||
else {
|
||||
let Ok((_, inbound)) = database.read_relationships(table.clone()).await else {
|
||||
return facts;
|
||||
};
|
||||
facts.table = Some(table.clone());
|
||||
@@ -2271,10 +2251,7 @@ async fn user_value_for_column_with_schema(
|
||||
..
|
||||
} = command
|
||||
{
|
||||
let desc = database
|
||||
.describe_table(table.to_string())
|
||||
.await
|
||||
.ok()?;
|
||||
let desc = database.describe_table(table.to_string()).await.ok()?;
|
||||
// Build the natural-order column list the same way
|
||||
// `do_insert` does: filter out serial / shortid columns
|
||||
// because the engine auto-fills them and the user's
|
||||
@@ -2285,8 +2262,7 @@ async fn user_value_for_column_with_schema(
|
||||
.filter(|c| {
|
||||
!matches!(
|
||||
c.user_type,
|
||||
Some(crate::dsl::Type::Serial)
|
||||
| Some(crate::dsl::Type::ShortId)
|
||||
Some(crate::dsl::Type::Serial) | Some(crate::dsl::Type::ShortId)
|
||||
)
|
||||
})
|
||||
.map(|c| c.name.as_str())
|
||||
@@ -2310,10 +2286,7 @@ async fn user_value_for_column_with_schema(
|
||||
&& listed_columns.is_empty()
|
||||
&& literal_rows.len() == 1
|
||||
{
|
||||
let desc = database
|
||||
.describe_table(table.to_string())
|
||||
.await
|
||||
.ok()?;
|
||||
let desc = database.describe_table(table.to_string()).await.ok()?;
|
||||
let idx = desc.columns.iter().position(|c| c.name == column)?;
|
||||
return literal_rows[0].get(idx).cloned().flatten();
|
||||
}
|
||||
@@ -2323,16 +2296,12 @@ async fn user_value_for_column_with_schema(
|
||||
/// Render a `DataResult` as a `DiagnosticTable` for the
|
||||
/// friendly-error layer's bordered renderer (ADR-0019 §7,
|
||||
/// reusing ADR-0017 §7's renderer).
|
||||
fn diagnostic_from_data_result(
|
||||
data: &DataResult,
|
||||
) -> crate::friendly::DiagnosticTable {
|
||||
use crate::output_render::{numeric_alignment_for, Alignment};
|
||||
fn diagnostic_from_data_result(data: &DataResult) -> crate::friendly::DiagnosticTable {
|
||||
use crate::output_render::{Alignment, numeric_alignment_for};
|
||||
let alignments: Vec<Alignment> = data
|
||||
.column_types
|
||||
.iter()
|
||||
.map(|t| {
|
||||
t.map_or(Alignment::Left, numeric_alignment_for)
|
||||
})
|
||||
.map(|t| t.map_or(Alignment::Left, numeric_alignment_for))
|
||||
.collect();
|
||||
let rows: Vec<Vec<String>> = data
|
||||
.rows
|
||||
@@ -2543,9 +2512,7 @@ pub async fn run_replay(
|
||||
// command, which was skipped above) — report it with the line
|
||||
// number and stop.
|
||||
let schema = build_schema_cache(database).await;
|
||||
let command = match crate::dsl::parser::parse_command_with_schema(
|
||||
&command_text, &schema,
|
||||
) {
|
||||
let command = match crate::dsl::parser::parse_command_with_schema(&command_text, &schema) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
events.push(AppEvent::ReplayFailed {
|
||||
@@ -2566,8 +2533,7 @@ pub async fn run_replay(
|
||||
// Retain a clone for failure enrichment (the command is moved into
|
||||
// dispatch). ADR-0035 Amendment 1, F2 follow-up.
|
||||
let command_for_ctx = command.clone();
|
||||
let outcome =
|
||||
execute_command_typed(database, command, command_text.clone()).await;
|
||||
let outcome = execute_command_typed(database, command, command_text.clone()).await;
|
||||
match outcome {
|
||||
Ok(_) => {
|
||||
// ADR-0052: journal the replayed line at the dispatch
|
||||
@@ -2873,7 +2839,10 @@ async fn execute_command_typed(
|
||||
.drop_constraint(table, column, ConstraintKind::NotNull, src)
|
||||
.await
|
||||
.map(|d| CommandOutcome::Schema(Some(d))),
|
||||
AlterTableAction::SetColumnDefault { column, default_sql } => database
|
||||
AlterTableAction::SetColumnDefault {
|
||||
column,
|
||||
default_sql,
|
||||
} => database
|
||||
.set_column_default(table, column, default_sql, src)
|
||||
.await
|
||||
.map(|d| CommandOutcome::Schema(Some(d))),
|
||||
@@ -2989,10 +2958,7 @@ async fn execute_command_typed(
|
||||
// A SQL `SELECT` (advanced mode; ADR-0030 §6, ADR-0031).
|
||||
// The grammar walker has already validated `sql` is in
|
||||
// the supported subset; the worker runs it as text.
|
||||
Command::Select { sql } => database
|
||||
.run_select(sql)
|
||||
.await
|
||||
.map(CommandOutcome::Query),
|
||||
Command::Select { sql } => database.run_select(sql).await.map(CommandOutcome::Query),
|
||||
// A SQL `INSERT` (advanced mode; ADR-0033 §1). Grammar-as-
|
||||
// text: the worker runs the validated `sql` and re-persists
|
||||
// the parsed `target_table`'s CSV. Reuses the DSL insert
|
||||
@@ -3112,12 +3078,9 @@ fn setup_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>> {
|
||||
Ok(terminal)
|
||||
}
|
||||
|
||||
fn teardown_terminal(
|
||||
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
|
||||
) -> Result<()> {
|
||||
fn teardown_terminal(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<()> {
|
||||
disable_raw_mode().context("disable raw mode")?;
|
||||
execute!(terminal.backend_mut(), LeaveAlternateScreen)
|
||||
.context("leave alternate screen")?;
|
||||
execute!(terminal.backend_mut(), LeaveAlternateScreen).context("leave alternate screen")?;
|
||||
terminal.show_cursor().context("show cursor")?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -3257,7 +3220,9 @@ mod tests {
|
||||
// Limited → ORDER BY the resolved primary key.
|
||||
assert_eq!(
|
||||
super::build_show_data_echo(&db, &limited, EffectiveMode::AdvancedPersistent).await,
|
||||
Some(vec!["SELECT * FROM Customers ORDER BY id LIMIT 5".to_string()]),
|
||||
Some(vec![
|
||||
"SELECT * FROM Customers ORDER BY id LIMIT 5".to_string()
|
||||
]),
|
||||
);
|
||||
// Simple mode → silent, gated before any lookup.
|
||||
assert_eq!(
|
||||
@@ -3288,10 +3253,10 @@ mod tests {
|
||||
async fn bucket_b_resolved_name_echoes_against_real_worker() {
|
||||
use crate::app::EffectiveMode;
|
||||
use crate::db::Database;
|
||||
use crate::dsl::Command;
|
||||
use crate::dsl::ReferentialAction;
|
||||
use crate::dsl::command::{ColumnSpec, IndexSelector, RelationshipSelector};
|
||||
use crate::dsl::types::Type;
|
||||
use crate::dsl::Command;
|
||||
|
||||
let db = Database::open(":memory:").expect("open in-memory");
|
||||
db.create_table(
|
||||
@@ -3319,7 +3284,12 @@ mod tests {
|
||||
|
||||
// --- add index (auto-named) ----------------------------------
|
||||
let desc_after_add_index = db
|
||||
.add_index(None, "Customers".to_string(), vec!["Email".to_string()], None)
|
||||
.add_index(
|
||||
None,
|
||||
"Customers".to_string(),
|
||||
vec!["Email".to_string()],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("add index");
|
||||
let add_idx_cmd = Command::AddIndex {
|
||||
@@ -3439,7 +3409,10 @@ mod tests {
|
||||
.await;
|
||||
assert_eq!(
|
||||
endpoints_lookups.drop_relationship,
|
||||
Some(("Customers_id_to_Orders_CustId".to_string(), "Orders".to_string())),
|
||||
Some((
|
||||
"Customers_id_to_Orders_CustId".to_string(),
|
||||
"Orders".to_string()
|
||||
)),
|
||||
"endpoints selector resolves name via child describe",
|
||||
);
|
||||
|
||||
@@ -3454,7 +3427,10 @@ mod tests {
|
||||
.await;
|
||||
assert_eq!(
|
||||
named_lookups.drop_relationship,
|
||||
Some(("Customers_id_to_Orders_CustId".to_string(), "Orders".to_string())),
|
||||
Some((
|
||||
"Customers_id_to_Orders_CustId".to_string(),
|
||||
"Orders".to_string()
|
||||
)),
|
||||
"named selector scans user tables to find the child",
|
||||
);
|
||||
|
||||
@@ -3487,10 +3463,10 @@ mod tests {
|
||||
async fn bucket_b_multi_statement_echoes_against_real_worker() {
|
||||
use crate::app::EffectiveMode;
|
||||
use crate::db::Database;
|
||||
use crate::dsl::Command;
|
||||
use crate::dsl::ReferentialAction;
|
||||
use crate::dsl::command::ColumnSpec;
|
||||
use crate::dsl::types::Type;
|
||||
use crate::dsl::Command;
|
||||
|
||||
// --- drop column --cascade -----------------------------------
|
||||
let db = Database::open(":memory:").expect("open in-memory");
|
||||
@@ -3505,9 +3481,14 @@ mod tests {
|
||||
)
|
||||
.await
|
||||
.expect("create Customers");
|
||||
db.add_index(None, "Customers".to_string(), vec!["Email".to_string()], None)
|
||||
.await
|
||||
.expect("index Email");
|
||||
db.add_index(
|
||||
None,
|
||||
"Customers".to_string(),
|
||||
vec!["Email".to_string()],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("index Email");
|
||||
|
||||
let drop_cmd = Command::DropColumn {
|
||||
table: "Customers".to_string(),
|
||||
@@ -3531,12 +3512,8 @@ mod tests {
|
||||
);
|
||||
// Simple mode → silent.
|
||||
assert!(
|
||||
super::build_drop_column_cascade_echo(
|
||||
&drop_cmd,
|
||||
EffectiveMode::Simple,
|
||||
&drop_result,
|
||||
)
|
||||
.is_none(),
|
||||
super::build_drop_column_cascade_echo(&drop_cmd, EffectiveMode::Simple, &drop_result,)
|
||||
.is_none(),
|
||||
);
|
||||
|
||||
// --- add relationship --create-fk (column newly created) ----
|
||||
@@ -3673,11 +3650,11 @@ mod tests {
|
||||
// switch (an unmodified temp would be cleaned up, taking its
|
||||
// project.yaml with it). Without the unload persist the
|
||||
// outgoing skeleton carries no `mode:` → `None`.
|
||||
use super::{handle_project_switch, Session, SwitchRequest};
|
||||
use super::{Session, SwitchRequest, handle_project_switch};
|
||||
use crate::db::Database;
|
||||
use crate::mode::Mode;
|
||||
use crate::persistence::Persistence;
|
||||
use crate::project::{projects_dir, Project};
|
||||
use crate::project::{Project, projects_dir};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
let data_root = tempfile::tempdir().unwrap();
|
||||
@@ -3686,8 +3663,7 @@ mod tests {
|
||||
let outgoing_path = projects.join("Outgoing");
|
||||
let outgoing = Project::create_named(&outgoing_path).unwrap();
|
||||
let db_path = outgoing.db_path();
|
||||
let persistence =
|
||||
Persistence::new(outgoing.path().to_path_buf()).with_mode(Mode::Advanced);
|
||||
let persistence = Persistence::new(outgoing.path().to_path_buf()).with_mode(Mode::Advanced);
|
||||
let database =
|
||||
Database::open_with_persistence_and_undo(&db_path, persistence, true).unwrap();
|
||||
let mut session = Session {
|
||||
|
||||
Reference in New Issue
Block a user