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:
+196
-51
@@ -28,8 +28,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");
|
||||
@@ -77,15 +76,18 @@ fn run_update(
|
||||
input: &str,
|
||||
) -> Result<UpdateResult, DbError> {
|
||||
match parse_command(input).expect("parse update") {
|
||||
Command::SqlUpdate { sql, target_table, returning, set_literals } => rt.block_on(
|
||||
db.run_sql_update_with_literals(
|
||||
sql,
|
||||
Some(input.to_string()),
|
||||
target_table,
|
||||
returning,
|
||||
set_literals,
|
||||
),
|
||||
),
|
||||
Command::SqlUpdate {
|
||||
sql,
|
||||
target_table,
|
||||
returning,
|
||||
set_literals,
|
||||
} => rt.block_on(db.run_sql_update_with_literals(
|
||||
sql,
|
||||
Some(input.to_string()),
|
||||
target_table,
|
||||
returning,
|
||||
set_literals,
|
||||
)),
|
||||
other => panic!("expected Command::SqlUpdate, got {other:?}"),
|
||||
}
|
||||
}
|
||||
@@ -95,7 +97,9 @@ fn parse_path_lowers_sql_update_to_command() {
|
||||
let command = parse_command("update Orders set total = 0 where id = 1")
|
||||
.expect("update parses in advanced mode");
|
||||
match command {
|
||||
Command::SqlUpdate { sql, target_table, .. } => {
|
||||
Command::SqlUpdate {
|
||||
sql, target_table, ..
|
||||
} => {
|
||||
assert_eq!(sql, "update Orders set total = 0 where id = 1");
|
||||
assert_eq!(target_table, "Orders");
|
||||
}
|
||||
@@ -107,10 +111,20 @@ fn parse_path_lowers_sql_update_to_command() {
|
||||
fn single_column_update_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, 'old'), (2, 'keep')", "t");
|
||||
let result = run_update(&db, &rt, "update t set v = 'new' where id = 1")
|
||||
.expect("update runs");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Text)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, v) values (1, 'old'), (2, 'keep')",
|
||||
"t",
|
||||
);
|
||||
let result = run_update(&db, &rt, "update t set v = 'new' where id = 1").expect("update runs");
|
||||
assert_eq!(result.rows_affected, 1, "one row updated");
|
||||
let csv = read_csv(&project, "t").expect("t.csv");
|
||||
assert!(csv.contains("new"), "updated value present: {csv:?}");
|
||||
@@ -134,7 +148,10 @@ fn multi_column_update_persists() {
|
||||
.expect("multi-col update runs");
|
||||
assert_eq!(result.rows_affected, 1);
|
||||
let csv = read_csv(&project, "t").expect("t.csv");
|
||||
assert!(csv.contains('9') && csv.contains('y'), "both columns updated: {csv:?}");
|
||||
assert!(
|
||||
csv.contains('9') && csv.contains('y'),
|
||||
"both columns updated: {csv:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -142,10 +159,21 @@ fn update_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), ("active", Type::Bool)], &["id"]);
|
||||
seed(&db, &rt, "insert into t (id, active) values (1, true), (2, true)", "t");
|
||||
let result = run_update(&db, &rt, "update t set active = false")
|
||||
.expect("unfiltered update runs");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("active", Type::Bool)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, active) values (1, true), (2, true)",
|
||||
"t",
|
||||
);
|
||||
let result =
|
||||
run_update(&db, &rt, "update t set active = false").expect("unfiltered update runs");
|
||||
assert_eq!(result.rows_affected, 2, "all rows updated");
|
||||
let csv = read_csv(&project, "t").expect("t.csv");
|
||||
assert!(!csv.contains("true"), "no row left active: {csv:?}");
|
||||
@@ -159,10 +187,20 @@ fn update_with_sql_expr_in_set() {
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("price", Type::Int), ("qty", Type::Int), ("total", Type::Int)],
|
||||
&[
|
||||
("id", Type::Int),
|
||||
("price", Type::Int),
|
||||
("qty", Type::Int),
|
||||
("total", Type::Int),
|
||||
],
|
||||
&["id"],
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, price, qty, total) values (1, 6, 7, 0)", "t");
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, price, qty, total) values (1, 6, 7, 0)",
|
||||
"t",
|
||||
);
|
||||
let result = run_update(&db, &rt, "update t set total = price * qty where id = 1")
|
||||
.expect("expression update runs");
|
||||
assert_eq!(result.rows_affected, 1);
|
||||
@@ -176,8 +214,19 @@ fn update_with_subquery_in_set() {
|
||||
let (project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "other", &[("n", Type::Int)], &["n"]);
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Int)], &["id"]);
|
||||
seed(&db, &rt, "insert into other (n) values (3), (8), (5)", "other");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Int)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into other (n) values (3), (8), (5)",
|
||||
"other",
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, v) values (1, 0)", "t");
|
||||
let result = run_update(
|
||||
&db,
|
||||
@@ -196,13 +245,22 @@ fn update_matching_no_rows_is_ok() {
|
||||
// the path doesn't crash, and the CSV is unchanged.
|
||||
let (project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Text)], &["id"]);
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Text)],
|
||||
&["id"],
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, v) values (1, 'keep')", "t");
|
||||
let result = run_update(&db, &rt, "update t set v = 'x' where id = 999")
|
||||
.expect("no-match update is a success");
|
||||
assert_eq!(result.rows_affected, 0, "no rows matched");
|
||||
let csv = read_csv(&project, "t").expect("t.csv");
|
||||
assert!(csv.contains("keep") && !csv.contains('x'), "unchanged: {csv:?}");
|
||||
assert!(
|
||||
csv.contains("keep") && !csv.contains('x'),
|
||||
"unchanged: {csv:?}"
|
||||
);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
@@ -220,8 +278,19 @@ fn sql_update_validates_set_literals_like_the_dsl() {
|
||||
// STRICT TEXT column accept anything).
|
||||
let (project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("d", Type::Date)], &["id"]);
|
||||
seed(&db, &rt, "insert into t (id, d) values (1, '2025-01-15')", "t");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("d", Type::Date)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, d) values (1, '2025-01-15')",
|
||||
"t",
|
||||
);
|
||||
|
||||
// SQL path (advanced mode, full replay pipeline) — REJECTS the bad date.
|
||||
std::fs::write(
|
||||
@@ -300,7 +369,12 @@ fn sql_update_validates_every_assignment_not_just_the_first() {
|
||||
&[("id", Type::Int), ("v", Type::Text), ("d", Type::Date)],
|
||||
&["id"],
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, v, d) values (1, 'a', '2025-01-01')", "t");
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, v, d) values (1, 'a', '2025-01-01')",
|
||||
"t",
|
||||
);
|
||||
std::fs::write(
|
||||
project.path().join("multi.commands"),
|
||||
"update t set v = 'ok', d = '2025/01/15' where id = 1\n",
|
||||
@@ -321,26 +395,64 @@ fn sql_update_validates_every_assignment_not_just_the_first() {
|
||||
fn update_returning_yields_modified_columns() {
|
||||
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, 'old'), (2, 'keep')", "t");
|
||||
let result = run_update(&db, &rt, "update t set v = 'new' where id = 1 returning id, v")
|
||||
.expect("UPDATE … RETURNING runs");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Text)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, v) values (1, 'old'), (2, 'keep')",
|
||||
"t",
|
||||
);
|
||||
let result = run_update(
|
||||
&db,
|
||||
&rt,
|
||||
"update t set v = 'new' where id = 1 returning id, v",
|
||||
)
|
||||
.expect("UPDATE … RETURNING runs");
|
||||
assert_eq!(result.rows_affected, 1, "one row updated");
|
||||
assert_eq!(result.data.columns, vec!["id".to_string(), "v".to_string()]);
|
||||
assert_eq!(result.data.rows.len(), 1);
|
||||
// RETURNING reflects the POST-update value.
|
||||
assert_eq!(result.data.rows[0][1], Some("new".to_string()), "modified value returned");
|
||||
assert_eq!(
|
||||
result.data.rows[0][1],
|
||||
Some("new".to_string()),
|
||||
"modified value returned"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_returning_recovers_bare_column_type() {
|
||||
let (_project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("active", Type::Bool)], &["id"]);
|
||||
seed(&db, &rt, "insert into t (id, active) values (1, false)", "t");
|
||||
let result = run_update(&db, &rt, "update t set active = true where id = 1 returning active")
|
||||
.expect("UPDATE … RETURNING active runs");
|
||||
assert_eq!(result.data.column_types, vec![Some(Type::Bool)], "bool type recovered");
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("active", Type::Bool)],
|
||||
&["id"],
|
||||
);
|
||||
seed(
|
||||
&db,
|
||||
&rt,
|
||||
"insert into t (id, active) values (1, false)",
|
||||
"t",
|
||||
);
|
||||
let result = run_update(
|
||||
&db,
|
||||
&rt,
|
||||
"update t set active = true where id = 1 returning active",
|
||||
)
|
||||
.expect("UPDATE … RETURNING active runs");
|
||||
assert_eq!(
|
||||
result.data.column_types,
|
||||
vec![Some(Type::Bool)],
|
||||
"bool type recovered"
|
||||
);
|
||||
assert_eq!(result.data.rows[0][0], Some("true".to_string()));
|
||||
}
|
||||
|
||||
@@ -352,13 +464,27 @@ fn update_returning_matching_no_rows_is_ok_and_empty() {
|
||||
// phantom row.
|
||||
let (_project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Text)], &["id"]);
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Text)],
|
||||
&["id"],
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, v) values (1, 'keep')", "t");
|
||||
let result = run_update(&db, &rt, "update t set v = 'x' where id = 999 returning id, v")
|
||||
.expect("no-match UPDATE … RETURNING is a success");
|
||||
let result = run_update(
|
||||
&db,
|
||||
&rt,
|
||||
"update t set v = 'x' where id = 999 returning id, v",
|
||||
)
|
||||
.expect("no-match UPDATE … RETURNING is a success");
|
||||
assert_eq!(result.rows_affected, 0, "no rows matched");
|
||||
assert!(result.data.rows.is_empty(), "no rows returned");
|
||||
assert_eq!(result.data.columns, vec!["id".to_string(), "v".to_string()], "columns still present");
|
||||
assert_eq!(
|
||||
result.data.columns,
|
||||
vec!["id".to_string(), "v".to_string()],
|
||||
"columns still present"
|
||||
);
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
@@ -399,14 +525,21 @@ fn advanced_update_set_value_offers_typed_slot_hint_for_column() {
|
||||
// instead of the type-blind sql_expr surface.
|
||||
let schema = schema_cache(&[(
|
||||
"Customers",
|
||||
&[("id", Type::Serial), ("Name", Type::Text), ("Email", Type::Text)],
|
||||
&[
|
||||
("id", Type::Serial),
|
||||
("Name", Type::Text),
|
||||
("Email", Type::Text),
|
||||
],
|
||||
)]);
|
||||
let input = "update Customers set Email=";
|
||||
let hint = ambient_hint_in_mode(input, input.len(), None, &schema, Mode::Advanced);
|
||||
let Some(AmbientHint::Prose(prose)) = hint else {
|
||||
panic!("expected a Prose hint at the typed value slot, got {hint:?}");
|
||||
};
|
||||
assert!(prose.contains("Email"), "hint names the column `Email`: {prose:?}");
|
||||
assert!(
|
||||
prose.contains("Email"),
|
||||
"hint names the column `Email`: {prose:?}"
|
||||
);
|
||||
assert!(
|
||||
prose.contains("quoted string"),
|
||||
"text-column hint says `quoted string`: {prose:?}"
|
||||
@@ -449,7 +582,10 @@ fn advanced_update_set_int_value_type_mismatch_is_caught_live() {
|
||||
&schema,
|
||||
Mode::Advanced,
|
||||
);
|
||||
assert!(matches!(ok, InputState::Valid), "a valid int literal parses: {ok:?}");
|
||||
assert!(
|
||||
matches!(ok, InputState::Valid),
|
||||
"a valid int literal parses: {ok:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -463,10 +599,10 @@ fn advanced_update_set_expression_still_parses_via_sql_expr() {
|
||||
("other", &[("n", Type::Int)]),
|
||||
]);
|
||||
for input in [
|
||||
"update Things set k = 3 + 2 where k = 0", // literal-prefixed expression
|
||||
"update Things set k = 3 + 2 where k = 0", // literal-prefixed expression
|
||||
"update Things set k = (select max(n) from other) where k = 0", // scalar subquery
|
||||
"update Things set note = upper(note) where k = 0", // function call
|
||||
"update Things set k = -5 where k = 0", // signed number → sql_expr
|
||||
"update Things set k = -5 where k = 0", // signed number → sql_expr
|
||||
] {
|
||||
let state = classify_input_with_schema_in_mode(input, &schema, Mode::Advanced);
|
||||
assert!(
|
||||
@@ -488,7 +624,13 @@ fn update_all_rows_flag_in_advanced_updates_every_row() {
|
||||
// parse-level dispatch (covered in tests/sql_dml_e2e.rs).
|
||||
let (project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
create_cols(&db, &rt, "t", &[("id", Type::Int), ("v", Type::Int)], &["id"]);
|
||||
create_cols(
|
||||
&db,
|
||||
&rt,
|
||||
"t",
|
||||
&[("id", Type::Int), ("v", Type::Int)],
|
||||
&["id"],
|
||||
);
|
||||
seed(&db, &rt, "insert into t (id, v) values (1, 1), (2, 2)", "t");
|
||||
std::fs::write(
|
||||
project.path().join("allrows.commands"),
|
||||
@@ -497,7 +639,10 @@ fn update_all_rows_flag_in_advanced_updates_every_row() {
|
||||
.expect("write script");
|
||||
let events = rt.block_on(run_replay(&db, project.path(), "allrows.commands"));
|
||||
assert!(
|
||||
matches!(events.last(), Some(AppEvent::ReplayCompleted { count: 1, .. })),
|
||||
matches!(
|
||||
events.last(),
|
||||
Some(AppEvent::ReplayCompleted { count: 1, .. })
|
||||
),
|
||||
"the --all-rows update replays through the DSL fall-back; events: {events:?}"
|
||||
);
|
||||
let rows = rt
|
||||
|
||||
Reference in New Issue
Block a user