Persistence: empty table -> no CSV (per Iteration 2 follow-up)
The Iteration-2 rule wrote a header-only CSV for every existing table, which surprised users who created a table and saw a file appear before any data went in. Tighten the rule: a CSV exists iff the table has rows. Persistence::write_table_data now delegates to delete_table_data when the snapshot is empty, removing any prior CSV. The schema-only invariant (YAML knows the table; CSV knows its rows) is preserved. The cascade-delete integration test was rewritten to assert the CSVs vanish; two new tests pin the rule (create -> no CSV; delete --all-rows -> CSV removed). Tests: 291 passing (256 lib + 9 + 9 + 17), 0 failing, 0 skipped.
This commit is contained in:
@@ -240,11 +240,89 @@ fn delete_with_cascade_rewrites_both_csvs() {
|
||||
assert_eq!(result.rows_affected, 1);
|
||||
});
|
||||
|
||||
let customers_csv = read_csv(&path, "Customers").expect("Customers.csv");
|
||||
let orders_csv = read_csv(&path, "Orders").expect("Orders.csv");
|
||||
// Both CSVs should be header-only after cascade.
|
||||
assert_eq!(customers_csv.lines().count(), 1, "got: {customers_csv}");
|
||||
assert_eq!(orders_csv.lines().count(), 1, "got: {orders_csv}");
|
||||
// Both CSVs should be gone after the cascade leaves both
|
||||
// tables empty: empty table -> no CSV (the rule from
|
||||
// Persistence::write_table_data; see ADR-0015 §4 commentary).
|
||||
assert!(
|
||||
read_csv(&path, "Customers").is_none(),
|
||||
"Customers.csv should be gone after cascade leaves it empty",
|
||||
);
|
||||
assert!(
|
||||
read_csv(&path, "Orders").is_none(),
|
||||
"Orders.csv should be gone after cascade leaves it empty",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_table_does_not_write_csv_for_empty_table() {
|
||||
let data = tempdir();
|
||||
let (_p, db, path) = open_project(&data);
|
||||
|
||||
rt().block_on(async {
|
||||
db.create_table(
|
||||
"Customers".to_string(),
|
||||
vec![
|
||||
ColumnSpec { name: "id".to_string(), ty: Type::Serial },
|
||||
ColumnSpec { name: "Name".to_string(), ty: Type::Text },
|
||||
],
|
||||
vec!["id".to_string()],
|
||||
Some("create table Customers with pk id:serial".to_string()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
// Schema landed in YAML.
|
||||
let yaml = read_yaml(&path);
|
||||
assert!(yaml.contains("- name: Customers"), "yaml missing table:\n{yaml}");
|
||||
// ...but no CSV until there's data.
|
||||
assert!(
|
||||
read_csv(&path, "Customers").is_none(),
|
||||
"no CSV should exist for an empty table",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_all_rows_removes_csv() {
|
||||
let data = tempdir();
|
||||
let (_p, db, path) = open_project(&data);
|
||||
|
||||
rt().block_on(async {
|
||||
db.create_table(
|
||||
"Customers".to_string(),
|
||||
vec![
|
||||
ColumnSpec { name: "id".to_string(), ty: Type::Serial },
|
||||
ColumnSpec { name: "Name".to_string(), ty: Type::Text },
|
||||
],
|
||||
vec!["id".to_string()],
|
||||
Some("create table Customers with pk id:serial".to_string()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
db.insert(
|
||||
"Customers".to_string(),
|
||||
None,
|
||||
vec![Value::Text("Alice".to_string())],
|
||||
Some("insert into Customers ('Alice')".to_string()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// CSV exists once there's data.
|
||||
assert!(read_csv(&path, "Customers").is_some());
|
||||
|
||||
db.delete(
|
||||
"Customers".to_string(),
|
||||
RowFilter::AllRows,
|
||||
Some("delete from Customers --all-rows".to_string()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
assert!(
|
||||
read_csv(&path, "Customers").is_none(),
|
||||
"CSV should be removed when the table becomes empty",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user