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:
claude@clouddev1
2026-06-17 21:39:19 +00:00
parent e9606b5f6d
commit 41b7e9a049
102 changed files with 8017 additions and 4975 deletions
+261 -64
View File
@@ -34,8 +34,7 @@ fn rt() -> tokio::runtime::Runtime {
fn open_project_db() -> (project::Project, Database, tempfile::TempDir) {
let dir = tempfile::tempdir().expect("create tempdir");
let project =
project::open_or_create(None, Some(dir.path())).expect("open or create project");
let project = project::open_or_create(None, Some(dir.path())).expect("open or create project");
let persistence = Persistence::new(project.path().to_path_buf());
let db = Database::open_with_persistence(project.db_path(), persistence)
.expect("open db with persistence");
@@ -83,9 +82,11 @@ fn run_delete(
input: &str,
) -> Result<DeleteResult, DbError> {
match parse_command(input).expect("parse delete") {
Command::SqlDelete { sql, target_table, returning } => {
rt.block_on(db.run_sql_delete(sql, Some(input.to_string()), target_table, returning))
}
Command::SqlDelete {
sql,
target_table,
returning,
} => rt.block_on(db.run_sql_delete(sql, Some(input.to_string()), target_table, returning)),
other => panic!("expected Command::SqlDelete, got {other:?}"),
}
}
@@ -95,8 +96,20 @@ fn run_delete(
/// `ON DELETE CASCADE`. Seeds Alice (1) with two orders (10, 11)
/// and Bob (2) with one order (12).
fn cascade_fixture(db: &Database, rt: &tokio::runtime::Runtime) {
create_cols(db, rt, "Customers", &[("id", Type::Int), ("Name", Type::Text)], &["id"]);
create_cols(db, rt, "Orders", &[("id", Type::Int), ("CustId", Type::Int)], &["id"]);
create_cols(
db,
rt,
"Customers",
&[("id", Type::Int), ("Name", Type::Text)],
&["id"],
);
create_cols(
db,
rt,
"Orders",
&[("id", Type::Int), ("CustId", Type::Int)],
&["id"],
);
rt.block_on(db.add_relationship(
Some("places".to_string()),
"Customers".to_string(),
@@ -109,16 +122,28 @@ fn cascade_fixture(db: &Database, rt: &tokio::runtime::Runtime) {
None,
))
.expect("add cascade relationship");
seed(db, rt, "insert into Customers (id, Name) values (1, 'Alice'), (2, 'Bob')", "Customers");
seed(db, rt, "insert into Orders (id, CustId) values (10, 1), (11, 1), (12, 2)", "Orders");
seed(
db,
rt,
"insert into Customers (id, Name) values (1, 'Alice'), (2, 'Bob')",
"Customers",
);
seed(
db,
rt,
"insert into Orders (id, CustId) values (10, 1), (11, 1), (12, 2)",
"Orders",
);
}
#[test]
fn parse_path_lowers_sql_delete_to_command() {
let command = parse_command("delete from Orders where id = 1")
.expect("delete parses in advanced mode");
let command =
parse_command("delete from Orders where id = 1").expect("delete parses in advanced mode");
match command {
Command::SqlDelete { sql, target_table, .. } => {
Command::SqlDelete {
sql, target_table, ..
} => {
assert_eq!(sql, "delete from Orders where id = 1");
assert_eq!(target_table, "Orders");
}
@@ -130,14 +155,28 @@ fn parse_path_lowers_sql_delete_to_command() {
fn delete_with_where_persists() {
let (project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Text)], &["id"]);
seed(&db, &rt, "insert into t (id, v) values (1, 'gone'), (2, 'keep')", "t");
create_cols(
&db,
&rt,
"t",
&[("id", Type::Int), ("v", Type::Text)],
&["id"],
);
seed(
&db,
&rt,
"insert into t (id, v) values (1, 'gone'), (2, 'keep')",
"t",
);
let result = run_delete(&db, &rt, "delete from t where id = 1").expect("delete runs");
assert_eq!(result.rows_affected, 1, "one row deleted");
assert!(result.cascade.is_empty(), "no children, no cascade");
let csv = read_csv(&project, "t").expect("t.csv");
assert!(csv.contains("keep"), "untouched row preserved: {csv:?}");
assert!(!csv.contains("gone"), "deleted row removed from CSV: {csv:?}");
assert!(
!csv.contains("gone"),
"deleted row removed from CSV: {csv:?}"
);
}
#[test]
@@ -145,18 +184,35 @@ fn delete_without_where_runs_across_all_rows() {
// ADR-0030 §12: no `--all-rows` rail.
let (project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Text)], &["id"]);
seed(&db, &rt, "insert into t (id, v) values (1, 'a'), (2, 'b'), (3, 'c')", "t");
create_cols(
&db,
&rt,
"t",
&[("id", Type::Int), ("v", Type::Text)],
&["id"],
);
seed(
&db,
&rt,
"insert into t (id, v) values (1, 'a'), (2, 'b'), (3, 'c')",
"t",
);
let result = run_delete(&db, &rt, "delete from t").expect("unfiltered delete runs");
assert_eq!(result.rows_affected, 3, "all rows deleted");
// Empty tables produce no CSV (CLAUDE.md persistence note), so the
// file is either absent or has only a header — either way, no data.
let csv = read_csv(&project, "t").unwrap_or_default();
assert!(!csv.contains('a') && !csv.contains('b') && !csv.contains('c'), "no rows left: {csv:?}");
assert!(
!csv.contains('a') && !csv.contains('b') && !csv.contains('c'),
"no rows left: {csv:?}"
);
let remaining = rt
.block_on(db.query_data("t".to_string(), None, None))
.expect("query t");
assert!(remaining.rows.is_empty(), "table empty after unfiltered delete");
assert!(
remaining.rows.is_empty(),
"table empty after unfiltered delete"
);
}
#[test]
@@ -165,8 +221,8 @@ fn cascade_delete_reports_summary_and_repersists_child() {
let rt = rt();
cascade_fixture(&db, &rt);
// Delete Alice (customer 1) — cascades to her two orders (10, 11).
let result = run_delete(&db, &rt, "delete from Customers where id = 1")
.expect("cascading delete runs");
let result =
run_delete(&db, &rt, "delete from Customers where id = 1").expect("cascading delete runs");
assert_eq!(result.rows_affected, 1, "one parent row deleted");
assert_eq!(result.cascade.len(), 1, "one cascade relationship reported");
let effect = &result.cascade[0];
@@ -177,9 +233,14 @@ fn cascade_delete_reports_summary_and_repersists_child() {
assert_eq!(effect.rows_changed, 2, "both of Alice's orders cascaded");
// The child CSV must be re-persisted to reflect the cascade.
let orders_csv = read_csv(&project, "Orders").expect("Orders.csv");
assert!(orders_csv.contains("12"), "Bob's order (12) preserved: {orders_csv:?}");
assert!(!orders_csv.contains("10") && !orders_csv.contains("11"),
"Alice's cascaded orders gone from CSV: {orders_csv:?}");
assert!(
orders_csv.contains("12"),
"Bob's order (12) preserved: {orders_csv:?}"
);
assert!(
!orders_csv.contains("10") && !orders_csv.contains("11"),
"Alice's cascaded orders gone from CSV: {orders_csv:?}"
);
}
#[test]
@@ -193,8 +254,8 @@ fn cascade_parity_with_dsl() {
let (_p_sql, db_sql, _d_sql) = open_project_db();
cascade_fixture(&db_sql, &rt);
let sql_result = run_delete(&db_sql, &rt, "delete from Customers where id = 1")
.expect("SQL delete runs");
let sql_result =
run_delete(&db_sql, &rt, "delete from Customers where id = 1").expect("SQL delete runs");
let (_p_dsl, db_dsl, _d_dsl) = open_project_db();
cascade_fixture(&db_dsl, &rt);
@@ -206,8 +267,14 @@ fn cascade_parity_with_dsl() {
))
.expect("DSL delete runs");
assert_eq!(sql_result.rows_affected, dsl_result.rows_affected, "row counts match");
assert_eq!(sql_result.cascade, dsl_result.cascade, "cascade summaries identical");
assert_eq!(
sql_result.rows_affected, dsl_result.rows_affected,
"row counts match"
);
assert_eq!(
sql_result.cascade, dsl_result.cascade,
"cascade summaries identical"
);
}
#[test]
@@ -229,9 +296,14 @@ fn r2_where_with_subquery() {
assert_eq!(result.rows_affected, 2, "Alice's two orders deleted");
assert!(result.cascade.is_empty(), "Orders has no cascade children");
let orders_csv = read_csv(&project, "Orders").expect("Orders.csv");
assert!(orders_csv.contains("12"), "Bob's order preserved: {orders_csv:?}");
assert!(!orders_csv.contains("10") && !orders_csv.contains("11"),
"Alice's orders deleted: {orders_csv:?}");
assert!(
orders_csv.contains("12"),
"Bob's order preserved: {orders_csv:?}"
);
assert!(
!orders_csv.contains("10") && !orders_csv.contains("11"),
"Alice's orders deleted: {orders_csv:?}"
);
}
#[test]
@@ -255,10 +327,15 @@ fn r2_cascade_with_subquery_where() {
.expect("cascade + subquery-WHERE delete runs");
assert_eq!(result.rows_affected, 1, "Alice deleted");
assert_eq!(result.cascade.len(), 1, "one cascade relationship");
assert_eq!(result.cascade[0].rows_changed, 2, "both Alice orders cascaded");
assert_eq!(
result.cascade[0].rows_changed, 2,
"both Alice orders cascaded"
);
let orders_csv = read_csv(&project, "Orders").expect("Orders.csv");
assert!(orders_csv.contains("12") && !orders_csv.contains("10") && !orders_csv.contains("11"),
"only Bob's order remains: {orders_csv:?}");
assert!(
orders_csv.contains("12") && !orders_csv.contains("10") && !orders_csv.contains("11"),
"only Bob's order remains: {orders_csv:?}"
);
}
#[test]
@@ -269,9 +346,27 @@ fn cascade_to_two_children_reports_both() {
// emitting more than one effect.
let (project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "Customers", &[("id", Type::Int), ("Name", Type::Text)], &["id"]);
create_cols(&db, &rt, "Orders", &[("id", Type::Int), ("CustId", Type::Int)], &["id"]);
create_cols(&db, &rt, "Reviews", &[("id", Type::Int), ("CustId", Type::Int)], &["id"]);
create_cols(
&db,
&rt,
"Customers",
&[("id", Type::Int), ("Name", Type::Text)],
&["id"],
);
create_cols(
&db,
&rt,
"Orders",
&[("id", Type::Int), ("CustId", Type::Int)],
&["id"],
);
create_cols(
&db,
&rt,
"Reviews",
&[("id", Type::Int), ("CustId", Type::Int)],
&["id"],
);
for (child, name) in [("Orders", "places"), ("Reviews", "writes")] {
rt.block_on(db.add_relationship(
Some(name.to_string()),
@@ -286,14 +381,33 @@ fn cascade_to_two_children_reports_both() {
))
.unwrap_or_else(|e| panic!("add rel {name}: {e:?}"));
}
seed(&db, &rt, "insert into Customers (id, Name) values (1, 'Alice')", "Customers");
seed(&db, &rt, "insert into Orders (id, CustId) values (10, 1), (11, 1)", "Orders");
seed(&db, &rt, "insert into Reviews (id, CustId) values (20, 1)", "Reviews");
seed(
&db,
&rt,
"insert into Customers (id, Name) values (1, 'Alice')",
"Customers",
);
seed(
&db,
&rt,
"insert into Orders (id, CustId) values (10, 1), (11, 1)",
"Orders",
);
seed(
&db,
&rt,
"insert into Reviews (id, CustId) values (20, 1)",
"Reviews",
);
let result = run_delete(&db, &rt, "delete from Customers where id = 1")
.expect("cascade-to-two delete runs");
assert_eq!(result.rows_affected, 1);
assert_eq!(result.cascade.len(), 2, "both cascade relationships reported");
assert_eq!(
result.cascade.len(),
2,
"both cascade relationships reported"
);
let by_child: std::collections::HashMap<&str, i64> = result
.cascade
.iter()
@@ -302,9 +416,16 @@ fn cascade_to_two_children_reports_both() {
assert_eq!(by_child.get("Orders"), Some(&2), "two orders cascaded");
assert_eq!(by_child.get("Reviews"), Some(&1), "one review cascaded");
// Both child CSVs re-persisted to the post-cascade (empty) state.
let orders = rt.block_on(db.query_data("Orders".to_string(), None, None)).unwrap();
let reviews = rt.block_on(db.query_data("Reviews".to_string(), None, None)).unwrap();
assert!(orders.rows.is_empty() && reviews.rows.is_empty(), "both children emptied");
let orders = rt
.block_on(db.query_data("Orders".to_string(), None, None))
.unwrap();
let reviews = rt
.block_on(db.query_data("Reviews".to_string(), None, None))
.unwrap();
assert!(
orders.rows.is_empty() && reviews.rows.is_empty(),
"both children emptied"
);
let _ = &project;
}
@@ -318,11 +439,19 @@ fn delete_childless_parent_reports_no_cascade() {
let rt = rt();
cascade_fixture(&db, &rt);
// Carol (3) exists with no orders; deleting her cascades nothing.
seed(&db, &rt, "insert into Customers (id, Name) values (3, 'Carol')", "Customers");
seed(
&db,
&rt,
"insert into Customers (id, Name) values (3, 'Carol')",
"Customers",
);
let result = run_delete(&db, &rt, "delete from Customers where id = 3")
.expect("childless-parent delete runs");
assert_eq!(result.rows_affected, 1, "Carol deleted");
assert!(result.cascade.is_empty(), "no children → no cascade effect reported");
assert!(
result.cascade.is_empty(),
"no children → no cascade effect reported"
);
// All three orders untouched.
let orders_csv = read_csv(&project, "Orders").expect("Orders.csv");
assert!(
@@ -340,8 +469,20 @@ fn delete_violating_fk_fails_and_persists_nothing() {
// parent row survives and history records no line.
let (project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "Customers", &[("id", Type::Int), ("Name", Type::Text)], &["id"]);
create_cols(&db, &rt, "Orders", &[("id", Type::Int), ("CustId", Type::Int)], &["id"]);
create_cols(
&db,
&rt,
"Customers",
&[("id", Type::Int), ("Name", Type::Text)],
&["id"],
);
create_cols(
&db,
&rt,
"Orders",
&[("id", Type::Int), ("CustId", Type::Int)],
&["id"],
);
rt.block_on(db.add_relationship(
Some("places".to_string()),
"Customers".to_string(),
@@ -354,18 +495,40 @@ fn delete_violating_fk_fails_and_persists_nothing() {
None,
))
.expect("add NO ACTION relationship");
seed(&db, &rt, "insert into Customers (id, Name) values (1, 'Alice')", "Customers");
seed(&db, &rt, "insert into Orders (id, CustId) values (10, 1)", "Orders");
seed(
&db,
&rt,
"insert into Customers (id, Name) values (1, 'Alice')",
"Customers",
);
seed(
&db,
&rt,
"insert into Orders (id, CustId) values (10, 1)",
"Orders",
);
let input = "delete from Customers where id = 1";
let result = run_delete(&db, &rt, input);
assert!(result.is_err(), "delete of a referenced parent must be rejected");
assert!(
result.is_err(),
"delete of a referenced parent must be rejected"
);
// Rolled back: Alice survives.
let customers = rt.block_on(db.query_data("Customers".to_string(), None, None)).unwrap();
assert_eq!(customers.rows.len(), 1, "parent row preserved after rejected delete");
let customers = rt
.block_on(db.query_data("Customers".to_string(), None, None))
.unwrap();
assert_eq!(
customers.rows.len(),
1,
"parent row preserved after rejected delete"
);
// No history line for the failed statement (written only on success).
let history = std::fs::read_to_string(project.path().join("history.log")).unwrap_or_default();
assert!(!history.contains(input), "failed delete not logged: {history:?}");
assert!(
!history.contains(input),
"failed delete not logged: {history:?}"
);
}
#[test]
@@ -378,7 +541,13 @@ fn self_referential_cascade_counts_only_cascaded_rows() {
// direct delete). Without the self-ref correction this reports 3.
let (_project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "T", &[("id", Type::Int), ("ParentId", Type::Int)], &["id"]);
create_cols(
&db,
&rt,
"T",
&[("id", Type::Int), ("ParentId", Type::Int)],
&["id"],
);
rt.block_on(db.add_relationship(
Some("parent_of".to_string()),
"T".to_string(),
@@ -391,11 +560,22 @@ fn self_referential_cascade_counts_only_cascaded_rows() {
None,
))
.expect("add self-referential relationship");
seed(&db, &rt, "insert into T (id, ParentId) values (1, null), (2, 1), (3, 2)", "T");
let result =
run_delete(&db, &rt, "delete from T where id = 1").expect("self-ref delete runs");
assert_eq!(result.rows_affected, 1, "one row matched the WHERE directly");
assert_eq!(result.cascade.len(), 1, "self-ref relationship reported once");
seed(
&db,
&rt,
"insert into T (id, ParentId) values (1, null), (2, 1), (3, 2)",
"T",
);
let result = run_delete(&db, &rt, "delete from T where id = 1").expect("self-ref delete runs");
assert_eq!(
result.rows_affected, 1,
"one row matched the WHERE directly"
);
assert_eq!(
result.cascade.len(),
1,
"self-ref relationship reported once"
);
assert_eq!(
result.cascade[0].rows_changed, 2,
"only the 2 cascaded rows, not the directly-deleted root too"
@@ -421,8 +601,19 @@ fn internal_target_table_rejected_at_parse() {
fn delete_returning_yields_predelete_row() {
let (project, db, _dir) = open_project_db();
let rt = rt();
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Text)], &["id"]);
seed(&db, &rt, "insert into t (id, v) values (1, 'gone'), (2, 'keep')", "t");
create_cols(
&db,
&rt,
"t",
&[("id", Type::Int), ("v", Type::Text)],
&["id"],
);
seed(
&db,
&rt,
"insert into t (id, v) values (1, 'gone'), (2, 'keep')",
"t",
);
let result = run_delete(&db, &rt, "delete from t where id = 1 returning *")
.expect("DELETE … RETURNING * runs");
assert_eq!(result.rows_affected, 1, "one row deleted");
@@ -431,7 +622,10 @@ fn delete_returning_yields_predelete_row() {
assert_eq!(result.data.rows[0][1], Some("gone".to_string()));
// And it really is gone from the table.
let csv = read_csv(&project, "t").expect("t.csv");
assert!(!csv.contains("gone") && csv.contains("keep"), "row actually deleted: {csv:?}");
assert!(
!csv.contains("gone") && csv.contains("keep"),
"row actually deleted: {csv:?}"
);
}
#[test]
@@ -449,5 +643,8 @@ fn delete_returning_with_cascade_surfaces_both() {
// Cascade summary still computed alongside the result set.
assert_eq!(result.cascade.len(), 1, "cascade reported");
assert_eq!(result.cascade[0].child_table, "Orders");
assert_eq!(result.cascade[0].rows_changed, 2, "both Alice's orders cascaded");
assert_eq!(
result.cascade[0].rows_changed, 2,
"both Alice's orders cascaded"
);
}