refactor(db): unwind vestigial worker source plumbing (ADR-0052 follow-up)

ADR-0052 moved success journaling out of the worker to the dispatch
layer, leaving the `source` that handlers threaded purely for the
worker's old history.log write dead. Remove it:

- drop `_source` from finalize_persistence and do_rebuild_from_text
- inline + delete the three read-only *_request wrappers
- drop the now-unused `source` param from the ~30 forwarding worker
  handlers (leaf + composite), compiler-guided
- remove the `source` field from the DescribeTable/QueryData/RunSelect
  requests and their DatabaseHandle methods (call sites updated)

The only worker `source` left is the snapshot/undo label
(snapshot_then / stage_pre_mutation / begin_batch). Purely mechanical,
no behaviour change. 2471 pass / 0 fail / 1 ignored, clippy clean.
This commit is contained in:
claude@clouddev1
2026-06-14 13:47:49 +00:00
parent ae73a4be85
commit e8fa859ab9
22 changed files with 231 additions and 384 deletions
+5 -5
View File
@@ -93,7 +93,7 @@ fn rename_column_with_case_variant_table_keeps_metadata_in_step() {
.expect("rename column via a case-variant table name");
let desc = r
.block_on(db.describe_table("Items".to_string(), None))
.block_on(db.describe_table("Items".to_string()))
.expect("describe Items");
let amount = desc
.columns
@@ -126,7 +126,7 @@ fn insert_with_case_variant_table_persists_and_survives_rebuild() {
let db = fresh_rebuild(db, &project, &r);
let rows = r
.block_on(db.query_data("Items".to_string(), None, None, None))
.block_on(db.query_data("Items".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 1, "the wrong-case insert survived the rebuild (no data loss)");
@@ -146,7 +146,7 @@ fn add_column_with_case_variant_table_survives_rebuild() {
);
let db = fresh_rebuild(db, &project, &r);
let desc = r.block_on(db.describe_table("Items".to_string(), None)).expect("describe");
let desc = r.block_on(db.describe_table("Items".to_string())).expect("describe");
let qty = desc.columns.iter().find(|c| c.name == "qty").expect("qty added");
assert_eq!(qty.user_type, Some(Type::Int), "qty's user-type survived the rebuild");
// The CHECK is intact too (a negative qty is refused under the real table).
@@ -224,12 +224,12 @@ fn add_relationship_with_case_variant_tables_survives_rebuild() {
add 1:n relationship from parent.id to child.parent_id\n",
);
// The parent's inbound relationship is visible under the stored case.
let p = r.block_on(db.describe_table("Parent".to_string(), None)).expect("describe Parent");
let p = r.block_on(db.describe_table("Parent".to_string())).expect("describe Parent");
assert_eq!(p.inbound_relationships.len(), 1, "relationship recorded under the stored case");
assert_eq!(p.inbound_relationships[0].other_table, "Child");
let db = fresh_rebuild(db, &project, &r);
let p = r.block_on(db.describe_table("Parent".to_string(), None)).expect("describe Parent");
let p = r.block_on(db.describe_table("Parent".to_string())).expect("describe Parent");
assert_eq!(p.inbound_relationships.len(), 1, "relationship survived the rebuild");
assert_eq!(p.inbound_relationships[0].other_table, "Child");
}
+5 -5
View File
@@ -276,7 +276,7 @@ fn compound_fk_declares_enforces_and_round_trips() {
);
// describe shows the compound endpoints symmetrically.
let city = db.describe_table("City".to_string(), None).await.unwrap();
let city = db.describe_table("City".to_string()).await.unwrap();
let outbound = &city.outbound_relationships[0];
assert_eq!(
outbound.local_columns,
@@ -329,7 +329,7 @@ fn compound_fk_create_fk_makes_both_child_columns() {
)
.await
.expect("add compound relationship with --create-fk");
let city = db.describe_table("City".to_string(), None).await.unwrap();
let city = db.describe_table("City".to_string()).await.unwrap();
for col in ["c_country", "c_code"] {
assert!(
city.columns.iter().any(|c| c.name == col),
@@ -527,7 +527,7 @@ fn compound_fk_survives_rebuild_from_text() {
.await;
assert!(bad.is_err(), "compound FK still enforced after rebuild from text");
// Endpoints survived the round-trip intact.
let city = db.describe_table("City".to_string(), None).await.unwrap();
let city = db.describe_table("City".to_string()).await.unwrap();
assert_eq!(
city.outbound_relationships[0].other_columns,
vec!["country".to_string(), "code".to_string()],
@@ -563,7 +563,7 @@ fn compound_fk_undo_removes_the_relationship() {
.await
.expect("add compound relationship");
assert_eq!(
db.describe_table("City".to_string(), None)
db.describe_table("City".to_string())
.await
.unwrap()
.outbound_relationships
@@ -573,7 +573,7 @@ fn compound_fk_undo_removes_the_relationship() {
// One undo step removes the whole relationship (ADR-0013/0006).
db.undo().await.unwrap().expect("undo applied");
assert!(
db.describe_table("City".to_string(), None)
db.describe_table("City".to_string())
.await
.unwrap()
.outbound_relationships
+4 -4
View File
@@ -76,7 +76,7 @@ fn rebuild_restores_schema_only_project() {
// Phase 4: confirm Customers exists with the right shape.
let desc = rt()
.block_on(async { db.describe_table("Customers".to_string(), None).await })
.block_on(async { db.describe_table("Customers".to_string()).await })
.expect("describe_table");
assert_eq!(desc.name, "Customers");
let cols: Vec<&str> = desc.columns.iter().map(|c| c.name.as_str()).collect();
@@ -143,7 +143,7 @@ fn rebuild_restores_rows_from_csv() {
});
let rows = rt()
.block_on(async { db.query_data("Customers".to_string(), None, None, None).await })
.block_on(async { db.query_data("Customers".to_string(), None, None).await })
.expect("query_data");
assert_eq!(rows.rows.len(), 2);
let names: Vec<Option<String>> = rows.rows.iter().map(|r| r[1].clone()).collect();
@@ -371,7 +371,7 @@ fn rebuild_preserves_created_at_from_yaml() {
// Trigger any successful command so project.yaml is
// rewritten from the now-rebuilt db state.
rt().block_on(async {
db.describe_table("T".to_string(), Some("show table T".to_string()))
db.describe_table("T".to_string())
.await
.unwrap();
// describe is read-only; force a rewrite by adding a column.
@@ -451,7 +451,7 @@ fn rebuild_restores_indexes() {
});
let desc = rt()
.block_on(async { db.describe_table("Customers".to_string(), None).await })
.block_on(async { db.describe_table("Customers".to_string()).await })
.expect("describe_table");
assert_eq!(desc.indexes.len(), 1, "index should survive rebuild");
assert_eq!(desc.indexes[0].name, "idx_email");
+1 -1
View File
@@ -173,7 +173,7 @@ fn rebuild_against_populated_db_wipes_and_reloads() {
.expect("rebuild");
});
let rows = rt()
.block_on(async { db.query_data("Customers".to_string(), None, None, None).await })
.block_on(async { db.query_data("Customers".to_string(), None, None).await })
.unwrap();
assert_eq!(rows.rows.len(), 1);
assert_eq!(rows.rows[0][1].as_deref(), Some("Edna"));
+1 -1
View File
@@ -362,7 +362,7 @@ fn end_to_end_export_then_import_real_project() {
// Round-trip: the inserted row is back.
let data_view = rt()
.block_on(async { imported_db.query_data("Customers".to_string(), None, None, None).await })
.block_on(async { imported_db.query_data("Customers".to_string(), None, None).await })
.expect("query data");
assert_eq!(data_view.rows.len(), 1);
// Serial id auto-filled to 1; Name was the inserted value.
+6 -6
View File
@@ -107,7 +107,7 @@ fn generates_junction_with_compound_pk_and_two_enforced_fks() {
assert!(tables.contains(&"Students_Courses".to_string()), "tables: {tables:?}");
// Two FK columns, both part of the compound PK.
let desc = db.describe_table("Students_Courses".to_string(), None).await.unwrap();
let desc = db.describe_table("Students_Courses".to_string()).await.unwrap();
let cols: Vec<(&str, bool)> =
desc.columns.iter().map(|c| (c.name.as_str(), c.primary_key)).collect();
assert_eq!(
@@ -191,7 +191,7 @@ fn compound_parent_pk_contributes_one_fk_column_each() {
.await
.expect("create m:n");
let desc = db.describe_table("Students_Sections".to_string(), None).await.unwrap();
let desc = db.describe_table("Students_Sections".to_string()).await.unwrap();
let names: Vec<&str> = desc.columns.iter().map(|c| c.name.as_str()).collect();
assert_eq!(names, vec!["Students_id", "Sections_course_id", "Sections_term"]);
// All three form the compound PK.
@@ -221,7 +221,7 @@ fn deleting_a_parent_cascades_to_the_junction() {
// Deleting the student cascades to the junction (ON DELETE CASCADE).
db.delete("Students".to_string(), RowFilter::AllRows, None).await.unwrap();
let rows = db.query_data("Students_Courses".to_string(), None, None, None).await.unwrap();
let rows = db.query_data("Students_Courses".to_string(), None, None).await.unwrap();
assert!(rows.rows.is_empty(), "junction rows should cascade-delete, got {:?}", rows.rows);
});
}
@@ -249,7 +249,7 @@ fn create_m2n_is_one_undo_step() {
let tables = db.list_tables().await.unwrap();
assert!(!tables.contains(&"Students_Courses".to_string()), "undo should remove the junction: {tables:?}");
// The parents' relationships are gone too (the junction held them).
let students = db.describe_table("Students".to_string(), None).await.unwrap();
let students = db.describe_table("Students".to_string()).await.unwrap();
assert!(students.inbound_relationships.is_empty(), "no leftover relationship after undo");
});
}
@@ -321,7 +321,7 @@ fn the_junction_can_be_renamed() {
assert!(tables.contains(&"Enrollments".to_string()), "tables: {tables:?}");
assert!(!tables.contains(&"Students_Courses".to_string()));
// Both relationships survive the rename (rebuild-preserving).
let desc = db.describe_table("Enrollments".to_string(), None).await.unwrap();
let desc = db.describe_table("Enrollments".to_string()).await.unwrap();
assert_eq!(desc.outbound_relationships.len(), 2, "FKs preserved across rename");
});
}
@@ -362,7 +362,7 @@ fn junction_survives_save_and_rebuild() {
db.rebuild_from_text(project.path().to_path_buf(), None).await.expect("rebuild");
let tables = db.list_tables().await.unwrap();
assert!(tables.contains(&"Students_Courses".to_string()), "junction survived: {tables:?}");
let desc = db.describe_table("Students_Courses".to_string(), None).await.unwrap();
let desc = db.describe_table("Students_Courses".to_string()).await.unwrap();
assert_eq!(desc.outbound_relationships.len(), 2, "both FKs reconstructed");
assert!(desc.columns.iter().all(|c| c.primary_key), "compound PK reconstructed");
});
+9 -9
View File
@@ -108,13 +108,13 @@ fn replay_runs_advanced_sql_create_table_as_a_write() {
// The SQL DDL line actually created the structural table…
let desc = rt()
.block_on(async { db.describe_table("Widget".to_string(), None).await })
.block_on(async { db.describe_table("Widget".to_string()).await })
.expect("describe");
let names: Vec<String> = desc.columns.iter().map(|c| c.name.clone()).collect();
assert_eq!(names, vec!["id".to_string(), "name".to_string()]);
// …and the following insert (serial id auto-filled) ran against it.
let rows = rt()
.block_on(async { db.query_data("Widget".to_string(), None, None, None).await })
.block_on(async { db.query_data("Widget".to_string(), None, None).await })
.expect("query")
.rows;
assert_eq!(rows.len(), 1);
@@ -139,7 +139,7 @@ fn replay_three_lines_dispatches_three_commands() {
// The dispatched commands actually mutated state.
let data_result = rt()
.block_on(async { db.query_data("T".to_string(), None, None, None).await })
.block_on(async { db.query_data("T".to_string(), None, None).await })
.expect("query_data");
assert_eq!(data_result.rows.len(), 1, "row inserted");
assert_eq!(data_result.rows[0][1].as_deref(), Some("Alice"));
@@ -174,7 +174,7 @@ fn replay_of_actual_history_log_runs_ok_commands_and_skips_err() {
assert_completed(&events, 3);
let data_result = rt()
.block_on(async { db.query_data("T".to_string(), None, None, None).await })
.block_on(async { db.query_data("T".to_string(), None, None).await })
.expect("query_data");
assert_eq!(data_result.rows.len(), 1, "only the ok INSERT applied");
assert_eq!(data_result.rows[0][1].as_deref(), Some("alpha"));
@@ -227,7 +227,7 @@ fn replay_skips_app_lifecycle_commands_silently() {
other => panic!("expected ReplayCompleted, got {other:?}"),
}
let data_result = rt()
.block_on(async { db.query_data("T".to_string(), None, None, None).await })
.block_on(async { db.query_data("T".to_string(), None, None).await })
.expect("query_data");
assert!(
data_result.columns.iter().any(|c| c == "v"),
@@ -401,14 +401,14 @@ fn replay_aborts_on_first_parse_failure_and_reports_line() {
// but earlier commands stayed applied (table T exists with
// the `name` column).
let desc = rt()
.block_on(async { db.describe_table("T".to_string(), None).await })
.block_on(async { db.describe_table("T".to_string()).await })
.expect("describe_table");
assert!(
desc.columns.iter().any(|c| c.name == "name"),
"earlier add column should have stayed applied"
);
let data_result = rt()
.block_on(async { db.query_data("T".to_string(), None, None, None).await })
.block_on(async { db.query_data("T".to_string(), None, None).await })
.expect("query_data");
assert!(
data_result.rows.is_empty(),
@@ -467,7 +467,7 @@ fn replay_rejects_wrong_type_value_in_a_hand_built_script() {
// The earlier two lines stayed applied; the failing insert
// did not run — state is intact.
let data_result = rt()
.block_on(async { db.query_data("T".to_string(), None, None, None).await })
.block_on(async { db.query_data("T".to_string(), None, None).await })
.expect("query_data");
assert!(
data_result.rows.is_empty(),
@@ -527,7 +527,7 @@ fn replay_skips_nested_replay_with_a_warning() {
other => panic!("expected ReplayCompleted (nested replay skipped), got {other:?}"),
}
// The nested file's table was NOT created (the replay was skipped).
let cols = rt().block_on(async { db.query_data("T".to_string(), None, None, None).await });
let cols = rt().block_on(async { db.query_data("T".to_string(), None, None).await });
assert!(cols.is_err(), "inner.commands' table T must not exist (nested replay skipped)");
}
+1 -1
View File
@@ -462,7 +462,7 @@ fn app_show_table_renders_relationships_as_compact_diagrams() {
rt.block_on(seed_schema(&db));
// Orders holds the FK to Customers — an outbound relationship.
let desc = rt
.block_on(db.describe_table("Orders".to_string(), None))
.block_on(db.describe_table("Orders".to_string()))
.expect("describe Orders");
let mut app = App::new();
+17 -17
View File
@@ -111,7 +111,7 @@ fn e2e_alter_drop_compound_primary_key_member_is_refused() {
/// The current user-facing type of column `name` in table `T`.
fn col_type(db: &Database, r: &tokio::runtime::Runtime, name: &str) -> Option<Type> {
r.block_on(db.describe_table("T".to_string(), None))
r.block_on(db.describe_table("T".to_string()))
.expect("describe")
.columns
.into_iter()
@@ -120,7 +120,7 @@ fn col_type(db: &Database, r: &tokio::runtime::Runtime, name: &str) -> Option<Ty
}
fn column_names(db: &Database, r: &tokio::runtime::Runtime) -> Vec<String> {
r.block_on(db.describe_table("T".to_string(), None))
r.block_on(db.describe_table("T".to_string()))
.expect("describe")
.columns
.into_iter()
@@ -163,7 +163,7 @@ fn e2e_alter_table_add_rename_drop_and_raw_default_check() {
// The DEFAULT backfilled the pre-existing row to qty = 0.
let rows = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 1);
@@ -252,7 +252,7 @@ fn e2e_alter_column_type_clean_and_lossy_convert() {
}
let rows = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 1);
@@ -292,7 +292,7 @@ fn e2e_alter_column_type_int_to_serial_is_allowed() {
}
assert_eq!(col_type(&db, &r, "n"), Some(Type::Serial), "int→serial converted the column");
let rows = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows[0][1].as_deref(), Some("100"), "the existing value is preserved");
@@ -635,7 +635,7 @@ fn e2e_drop_composite_unique_is_one_undo_step() {
.expect("write");
r.block_on(run_replay(&db, project.path(), "u.commands"));
let has_unique = || {
!r.block_on(db.describe_table("T".to_string(), None))
!r.block_on(db.describe_table("T".to_string()))
.expect("describe")
.unique_constraints
.is_empty()
@@ -878,7 +878,7 @@ fn e2e_describe_shows_table_level_constraints() {
"events: {events:?}"
);
let desc = r.block_on(db.describe_table("T".to_string(), None)).expect("describe");
let desc = r.block_on(db.describe_table("T".to_string())).expect("describe");
assert_eq!(
desc.unique_constraints,
vec![vec!["a".to_string(), "b".to_string()]],
@@ -976,7 +976,7 @@ fn e2e_rename_table_with_rows_csv_follows_and_survives_rebuild() {
assert!(!csv_path(&project, "Orders").exists(), "data/Orders.csv removed");
let rows = r
.block_on(db.query_data("Purchases".to_string(), None, None, None))
.block_on(db.query_data("Purchases".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 2);
@@ -991,7 +991,7 @@ fn e2e_rename_table_with_rows_csv_follows_and_survives_rebuild() {
"Purchases round-tripped through a fresh rebuild: {tables:?}"
);
let rows = r
.block_on(db.query_data("Purchases".to_string(), None, None, None))
.block_on(db.query_data("Purchases".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 2);
@@ -1077,7 +1077,7 @@ fn e2e_rename_fk_parent_updates_metadata_and_still_enforces() {
);
// The child's outbound relationship now points at the new parent name.
let c = r.block_on(db.describe_table("C".to_string(), None)).expect("describe C");
let c = r.block_on(db.describe_table("C".to_string())).expect("describe C");
assert_eq!(c.outbound_relationships.len(), 1);
assert_eq!(c.outbound_relationships[0].other_table, "Parent");
@@ -1129,7 +1129,7 @@ fn e2e_rename_fk_child_updates_metadata_and_still_enforces() {
);
// The parent's inbound relationship now names the renamed child.
let p = r.block_on(db.describe_table("P".to_string(), None)).expect("describe P");
let p = r.block_on(db.describe_table("P".to_string())).expect("describe P");
assert_eq!(p.inbound_relationships.len(), 1);
assert_eq!(p.inbound_relationships[0].other_table, "Child");
@@ -1168,7 +1168,7 @@ fn e2e_rename_self_referential_table_updates_both_ends() {
);
// Both ends of the self-reference now name `Tree`.
let t = r.block_on(db.describe_table("Tree".to_string(), None)).expect("describe Tree");
let t = r.block_on(db.describe_table("Tree".to_string())).expect("describe Tree");
assert_eq!(t.outbound_relationships[0].other_table, "Tree");
assert_eq!(t.inbound_relationships[0].other_table, "Tree");
@@ -1216,7 +1216,7 @@ fn e2e_rename_table_keeps_its_index_with_a_stale_name() {
"events: {events:?}"
);
let u = r.block_on(db.describe_table("Users".to_string(), None)).expect("describe Users");
let u = r.block_on(db.describe_table("Users".to_string())).expect("describe Users");
assert_eq!(u.indexes.len(), 1, "the index followed the rename");
assert_eq!(
u.indexes[0].name, "T_email_idx",
@@ -1226,7 +1226,7 @@ fn e2e_rename_table_keeps_its_index_with_a_stale_name() {
// Survives a fresh rebuild (recreated from IndexSchema on table Users).
let db = fresh_rebuild(db, &project, &r);
let u = r.block_on(db.describe_table("Users".to_string(), None)).expect("describe Users");
let u = r.block_on(db.describe_table("Users".to_string())).expect("describe Users");
assert_eq!(u.indexes.len(), 1);
assert_eq!(u.indexes[0].name, "T_email_idx");
}
@@ -1255,7 +1255,7 @@ fn e2e_rename_table_is_one_undo_step() {
"undo restored the old table name: {tables:?}"
);
assert_eq!(
r.block_on(db.query_data("Orders".to_string(), None, None, None)).expect("query").rows.len(),
r.block_on(db.query_data("Orders".to_string(), None, None)).expect("query").rows.len(),
1,
"the row is back under the old name"
);
@@ -1427,7 +1427,7 @@ fn e2e_alter_column_set_default_applies() {
))
.expect("insert omitting qty");
let rows = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(
@@ -1473,7 +1473,7 @@ fn e2e_alter_column_drop_default_removes_it() {
))
.expect("insert omitting qty");
let rows = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(
+1 -1
View File
@@ -55,7 +55,7 @@ fn insert_row(db: &Database, r: &tokio::runtime::Runtime, id: i64, email: &str)
}
fn index(db: &Database, r: &tokio::runtime::Runtime, name: &str) -> Option<(Vec<String>, bool)> {
r.block_on(db.describe_table("T".to_string(), None))
r.block_on(db.describe_table("T".to_string()))
.expect("describe")
.indexes
.into_iter()
+18 -18
View File
@@ -64,7 +64,7 @@ fn created_table_appears_with_playground_types() {
assert!(tables.contains(&"Widget".to_string()));
let desc = r
.block_on(db.describe_table("Widget".to_string(), None))
.block_on(db.describe_table("Widget".to_string()))
.expect("describe");
let types: Vec<(String, Option<Type>)> = desc
.columns
@@ -98,7 +98,7 @@ fn integer_primary_key_is_plain_int() {
))
.expect("create");
let desc = r
.block_on(db.describe_table("T".to_string(), None))
.block_on(db.describe_table("T".to_string()))
.expect("describe");
assert_eq!(desc.columns[0].user_type, Some(Type::Int));
}
@@ -137,7 +137,7 @@ fn serial_pk_autoincrements_in_multi_column_table() {
}
let data = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query");
let id_idx = data
.columns
@@ -220,7 +220,7 @@ fn table_without_primary_key_is_allowed() {
))
.expect("insert into PK-less table");
let data = r
.block_on(db.query_data("Notes".to_string(), None, None, None))
.block_on(db.query_data("Notes".to_string(), None, None))
.expect("query");
assert_eq!(data.rows.len(), 1);
}
@@ -299,7 +299,7 @@ fn default_is_applied_when_column_omitted() {
))
.expect("insert");
let data = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query");
let n_idx = data.columns.iter().position(|c| c == "n").expect("n column");
assert_eq!(data.rows[0][n_idx].as_deref(), Some("7"), "DEFAULT 7 applied");
@@ -381,7 +381,7 @@ fn check_default_and_composite_unique_survive_rebuild() {
// A valid row inserts; DEFAULT n=7 survived.
r.block_on(ins("1", "1", "5")).expect("valid row");
let data = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query");
let n_idx = data.columns.iter().position(|c| c == "n").expect("n column");
assert_eq!(data.rows[0][n_idx].as_deref(), Some("7"), "DEFAULT survived rebuild");
@@ -679,7 +679,7 @@ fn sql_create_table_is_one_undo_step() {
/// Sorted `id` column values of table `T`.
fn ids(db: &Database, r: &tokio::runtime::Runtime) -> Vec<Option<String>> {
let d = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query");
let idx = d.columns.iter().position(|c| c == "id").expect("id column");
let mut v: Vec<Option<String>> = d.rows.iter().map(|row| row[idx].clone()).collect();
@@ -801,7 +801,7 @@ fn dropping_a_column_a_table_check_references_fails_cleanly() {
// The table is intact: both columns survive (rollback) ...
let desc = r
.block_on(db.describe_table("T".to_string(), None))
.block_on(db.describe_table("T".to_string()))
.expect("describe still works");
assert_eq!(
desc.columns.iter().map(|c| c.name.clone()).collect::<Vec<_>>(),
@@ -925,14 +925,14 @@ fn foreign_key_creates_named_relationship_visible_in_describe() {
.expect("create child with FK");
// The child has an outbound relationship; the parent an inbound one.
let child = r.block_on(db.describe_table("child".to_string(), None)).expect("describe child");
let child = r.block_on(db.describe_table("child".to_string())).expect("describe child");
assert_eq!(child.outbound_relationships.len(), 1, "child references parent");
let rel = &child.outbound_relationships[0];
assert_eq!(rel.name, "parent_id_to_child_pid", "auto-named per ADR-0013");
assert_eq!(rel.other_table, "parent");
assert_eq!(rel.local_columns, vec!["pid".to_string()]);
let parent = r.block_on(db.describe_table("parent".to_string(), None)).expect("describe parent");
let parent = r.block_on(db.describe_table("parent".to_string())).expect("describe parent");
assert_eq!(parent.inbound_relationships.len(), 1, "parent is referenced by child");
}
@@ -954,7 +954,7 @@ fn explicit_constraint_name_is_used() {
Some("create table child (id serial primary key, pid int, constraint child_to_parent foreign key (pid) references parent(id))".to_string()),
))
.expect("create child with named FK");
let child = r.block_on(db.describe_table("child".to_string(), None)).expect("describe");
let child = r.block_on(db.describe_table("child".to_string())).expect("describe");
assert_eq!(child.outbound_relationships[0].name, "child_to_parent");
}
@@ -974,7 +974,7 @@ fn bare_references_resolves_to_parent_single_column_pk() {
Some("create table child (id serial primary key, pid int references parent)".to_string()),
))
.expect("create child with bare REFERENCES");
let child = r.block_on(db.describe_table("child".to_string(), None)).expect("describe");
let child = r.block_on(db.describe_table("child".to_string())).expect("describe");
assert_eq!(child.outbound_relationships[0].other_columns, vec!["id".to_string()], "resolved to parent PK");
}
@@ -1108,7 +1108,7 @@ fn create_table_with_fk_is_one_undo_step() {
// parent (now un-referenced) can be described without a dangling rel.
r.block_on(db.undo()).expect("undo").expect("a step was undone");
assert!(!r.block_on(db.list_tables()).unwrap().contains(&"child".to_string()));
let parent = r.block_on(db.describe_table("parent".to_string(), None)).expect("describe parent");
let parent = r.block_on(db.describe_table("parent".to_string())).expect("describe parent");
assert!(parent.inbound_relationships.is_empty(), "the relationship was undone with the table");
}
@@ -1152,7 +1152,7 @@ fn foreign_key_on_delete_cascade_takes_effect() {
))
.expect("delete parent");
let child_rows = r
.block_on(db.query_data("child".to_string(), None, None, None))
.block_on(db.query_data("child".to_string(), None, None))
.expect("query child");
assert!(child_rows.rows.is_empty(), "ON DELETE CASCADE removed the child row");
}
@@ -1232,7 +1232,7 @@ fn fk_survives_a_rebuild_triggering_column_add() {
.expect("add column via rebuild");
// The relationship still exists after the rebuild.
let child = r.block_on(db.describe_table("child".to_string(), None)).expect("describe");
let child = r.block_on(db.describe_table("child".to_string())).expect("describe");
assert_eq!(child.outbound_relationships.len(), 1, "FK survived the column-add rebuild");
// And the engine still enforces it (now and after a fresh rebuild).
insert_parent_row(&db, &r);
@@ -1275,7 +1275,7 @@ fn fk_referential_actions_survive_rebuild() {
))
.expect("create");
r.block_on(db.rebuild_from_text(p.path().to_path_buf(), None)).expect("rebuild");
let child = r.block_on(db.describe_table("child".to_string(), None)).expect("describe");
let child = r.block_on(db.describe_table("child".to_string())).expect("describe");
let rel = &child.outbound_relationships[0];
assert_eq!(rel.on_delete, ReferentialAction::Cascade, "ON DELETE survived rebuild");
assert_eq!(rel.on_update, ReferentialAction::SetNull, "ON UPDATE survived rebuild");
@@ -1299,7 +1299,7 @@ fn dropping_the_child_clears_the_fk_relationship() {
.expect("create");
r.block_on(db.drop_table("child".to_string(), Some("drop table child".to_string())))
.expect("drop child");
let parent = r.block_on(db.describe_table("parent".to_string(), None)).expect("describe parent");
let parent = r.block_on(db.describe_table("parent".to_string())).expect("describe parent");
assert!(parent.inbound_relationships.is_empty(), "dropping the child cleared the relationship");
}
@@ -1341,7 +1341,7 @@ fn bare_self_reference_resolves_to_own_pk() {
Some("create table emp (id int primary key, mgr int references emp)".to_string()),
))
.expect("create self-referential emp with a bare reference");
let emp = r.block_on(db.describe_table("emp".to_string(), None)).expect("describe");
let emp = r.block_on(db.describe_table("emp".to_string())).expect("describe");
assert_eq!(emp.outbound_relationships[0].other_columns, vec!["id".to_string()], "bare self-ref resolved to own PK");
// Enforced: a non-existent manager is rejected.
r.block_on(db.insert(
+4 -4
View File
@@ -154,7 +154,7 @@ fn delete_without_where_runs_across_all_rows() {
let csv = read_csv(&project, "t").unwrap_or_default();
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, None))
.block_on(db.query_data("t".to_string(), None, None))
.expect("query t");
assert!(remaining.rows.is_empty(), "table empty after unfiltered delete");
}
@@ -302,8 +302,8 @@ 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, None)).unwrap();
let reviews = rt.block_on(db.query_data("Reviews".to_string(), None, None, None)).unwrap();
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;
}
@@ -361,7 +361,7 @@ fn delete_violating_fk_fails_and_persists_nothing() {
let result = run_delete(&db, &rt, input);
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, None)).unwrap();
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();
+1 -1
View File
@@ -149,7 +149,7 @@ fn seed(db: &Database, rt: &tokio::runtime::Runtime, sql: &str) {
}
fn query(db: &Database, rt: &tokio::runtime::Runtime, table: &str) -> Vec<Vec<Option<String>>> {
rt.block_on(db.query_data(table.to_string(), None, None, None))
rt.block_on(db.query_data(table.to_string(), None, None))
.unwrap_or_else(|e| panic!("query_data {table}: {e:?}"))
.rows
}
+1 -1
View File
@@ -55,7 +55,7 @@ fn make_t_with_index(db: &Database, r: &tokio::runtime::Runtime) -> String {
}
fn index_names(db: &Database, r: &tokio::runtime::Runtime) -> Vec<String> {
r.block_on(db.describe_table("T".to_string(), None))
r.block_on(db.describe_table("T".to_string()))
.expect("describe")
.indexes
.into_iter()
+1 -1
View File
@@ -150,7 +150,7 @@ fn drop_table_is_one_undo_step_and_restores_data() {
assert!(r.block_on(db.undo()).expect("undo").is_some(), "the drop was one undo step");
assert!(r.block_on(db.list_tables()).unwrap().contains(&"T".to_string()));
let data = r
.block_on(db.query_data("T".to_string(), None, None, None))
.block_on(db.query_data("T".to_string(), None, None))
.expect("query");
assert_eq!(data.rows.len(), 1, "the dropped row was restored by undo");
}
+10 -16
View File
@@ -215,7 +215,7 @@ fn decimal_aggregation_display_trims_ieee754_noise() {
// The reported case: the aggregate no longer leaks float noise.
let agg = rt
.block_on(db.run_select("select sum(price * qty) from Products".to_string(), None))
.block_on(db.run_select("select sum(price * qty) from Products".to_string()))
.expect("aggregate select");
assert_eq!(
agg.rows[0][0].as_deref(),
@@ -226,7 +226,7 @@ fn decimal_aggregation_display_trims_ieee754_noise() {
// Raw decimal column is still exact — TEXT storage preserves
// the input string verbatim, including the trailing zero.
let raw = rt
.block_on(db.run_select("select price from Products".to_string(), None))
.block_on(db.run_select("select price from Products".to_string()))
.expect("raw decimal select");
let prices: Vec<&str> = raw.rows.iter().map(|r| r[0].as_deref().unwrap()).collect();
assert_eq!(
@@ -240,10 +240,7 @@ fn decimal_aggregation_display_trims_ieee754_noise() {
fn database_run_select_constant_returns_a_single_row() {
let (_p, db, _dir) = open_project_db();
let data = rt()
.block_on(db.run_select(
"select 1".to_string(),
Some("select 1".to_string()),
))
.block_on(db.run_select("select 1".to_string()))
.expect("`select 1` runs clean");
assert_eq!(data.rows.len(), 1, "one result row");
assert_eq!(data.rows[0].len(), 1, "one column");
@@ -288,7 +285,7 @@ fn database_run_select_from_user_table_returns_inserted_rows() {
.expect("insert row");
});
let data = rt
.block_on(db.run_select("select Name from T".to_string(), None))
.block_on(db.run_select("select Name from T".to_string()))
.expect("SELECT runs");
assert_eq!(data.rows.len(), 1);
assert_eq!(data.rows[0][0].as_deref(), Some("Ada"));
@@ -336,7 +333,7 @@ fn database_run_select_recovers_bool_column_type() {
.expect("insert row");
});
let data = rt
.block_on(db.run_select("select Active from Products".to_string(), None))
.block_on(db.run_select("select Active from Products".to_string()))
.expect("SELECT runs");
assert_eq!(data.rows.len(), 2);
assert_eq!(data.column_types, vec![Some(Type::Bool)]);
@@ -374,7 +371,7 @@ fn database_run_select_recovers_text_type_through_alias() {
// playground type is recovered.
let data = rt
.block_on(
db.run_select("select Name as n from Users".to_string(), None),
db.run_select("select Name as n from Users".to_string()),
)
.expect("SELECT runs");
assert_eq!(data.columns, vec!["n".to_string()]);
@@ -402,7 +399,7 @@ fn database_run_select_computed_expression_stays_typeless() {
.expect("insert");
});
let data = rt
.block_on(db.run_select("select Score + 1 from T".to_string(), None))
.block_on(db.run_select("select Score + 1 from T".to_string()))
.expect("SELECT runs");
assert_eq!(data.column_types, vec![None]);
}
@@ -439,7 +436,6 @@ fn engine_aggregate_in_where_routes_through_catalog() {
let err = rt
.block_on(db.run_select(
"select id from T where count(score) > 0".to_string(),
None,
))
.expect_err("engine should reject aggregate in WHERE");
let DbError::Sqlite { .. } = &err else {
@@ -512,7 +508,6 @@ fn engine_group_by_missing_routes_through_catalog() {
let _ = rt
.block_on(db.run_select(
"select category, count(*) from T group by category".to_string(),
None,
))
.expect("benign GROUP BY query runs");
// Direct unit test on the matcher: ensure a message that
@@ -574,7 +569,6 @@ fn engine_scalar_subquery_too_many_rows_routes_through_catalog() {
let _ = rt
.block_on(db.run_select(
"select (select v from T) from T".to_string(),
None,
))
.expect("benign scalar subquery query runs");
let synthetic = DbError::Sqlite {
@@ -624,13 +618,13 @@ fn database_run_select_type_recovery_works_on_empty_table() {
});
// No INSERT — the table is empty.
let data_text = rt
.block_on(db.run_select("select col_text from Empty".to_string(), None))
.block_on(db.run_select("select col_text from Empty".to_string()))
.expect("SELECT runs even on empty table");
assert!(data_text.rows.is_empty());
assert_eq!(data_text.column_types, vec![Some(Type::Text)]);
let data_blob = rt
.block_on(db.run_select("select col_blob from Empty".to_string(), None))
.block_on(db.run_select("select col_blob from Empty".to_string()))
.expect("SELECT runs even on empty table");
assert!(data_blob.rows.is_empty());
assert_eq!(
@@ -723,7 +717,7 @@ fn database_run_select_recovers_all_ten_playground_types() {
for (col, expected_type) in cases {
let sql = format!("select {col} from AllTypes");
let data = rt
.block_on(db.run_select(sql.clone(), None))
.block_on(db.run_select(sql.clone()))
.expect("SELECT runs");
assert_eq!(
data.column_types,
+1 -1
View File
@@ -501,7 +501,7 @@ fn update_all_rows_flag_in_advanced_updates_every_row() {
"the --all-rows update replays through the DSL fall-back; events: {events:?}"
);
let rows = rt
.block_on(db.query_data("t".to_string(), None, None, None))
.block_on(db.query_data("t".to_string(), None, None))
.expect("query")
.rows;
assert_eq!(rows.len(), 2, "both rows present");
+3 -3
View File
@@ -63,7 +63,7 @@ async fn insert_named(db: &Database, name: &str) {
}
async fn row_count(db: &Database) -> usize {
db.query_data("Customers".to_string(), None, None, None)
db.query_data("Customers".to_string(), None, None)
.await
.unwrap()
.rows
@@ -306,7 +306,7 @@ async fn sql_delete(db: &Database, input: &str) {
}
async fn count_t(db: &Database) -> usize {
db.query_data("T".to_string(), None, None, None)
db.query_data("T".to_string(), None, None)
.await
.unwrap()
.rows
@@ -378,7 +378,7 @@ fn undo_restores_db_and_csv_consistently() {
// Both the database read model and the on-disk CSV are
// restored — the (db, csv) pair stays consistent.
assert_eq!(
db.query_data("T".to_string(), None, None, None)
db.query_data("T".to_string(), None, None)
.await
.unwrap()
.rows