fix: ADR-0035 4g — reconstruct table-CHECK metadata on rebuild
do_rebuild_from_text re-emitted table-level CHECKs into the recreated DDL (so they stayed enforced) but never repopulated __rdbms_playground_ table_checks. A fresh rebuild (missing .db, reconstructed from project.yaml) therefore left the CHECK metadata empty: DROP CONSTRAINT, describe, and a later save would lose it — including a named CHECK's name. In-place rebuilds only worked because the wipe never touched the table. (Latent since 4a.3 for unnamed checks; exposed by 4g's named round-trip claim.) Rebuild now wipes and repopulates CHECK_TABLE from the yaml snapshot (name + seq + expr), like META/REL, and adds the 4g `name` column if a pre-4g table predates it (the rebuild-only migration). Regression test: a named CHECK's metadata survives a fresh rebuild (DROP CONSTRAINT by name resolves).
This commit is contained in:
@@ -596,3 +596,59 @@ fn e2e_add_constraint_is_one_undo_step() {
|
||||
// After undo the CHECK is gone: qty = -1 is accepted.
|
||||
assert!(insert_t_qty_ok(&db, &r, 3, -1), "one undo removed the CHECK");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn e2e_named_check_metadata_survives_a_fresh_rebuild() {
|
||||
// A FRESH rebuild (deleted .db, reconstructed from project.yaml) must
|
||||
// repopulate the table-CHECK metadata — not just re-emit the CHECK
|
||||
// into the recreated DDL. Otherwise the CHECK is enforced but its
|
||||
// metadata (incl. the name) is lost: `describe` / `DROP CONSTRAINT` /
|
||||
// a later save would drop it (ADR-0035 §4g; fixes a latent 4a.3 gap).
|
||||
use rdbms_playground::dsl::ColumnSpec;
|
||||
use rdbms_playground::project::PLAYGROUND_DB;
|
||||
let dir = tempfile::tempdir().expect("tempdir");
|
||||
let r = rt();
|
||||
let project_path = {
|
||||
let project = project::open_or_create(None, Some(dir.path())).expect("open");
|
||||
let path = project.path().to_path_buf();
|
||||
let db = Database::open_with_persistence(project.db_path(), Persistence::new(path.clone()))
|
||||
.expect("db");
|
||||
r.block_on(db.sql_create_table(
|
||||
"T".to_string(),
|
||||
vec![ColumnSpec::new("id", Type::Int), ColumnSpec::new("qty", Type::Int)],
|
||||
vec!["id".to_string()],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
Some("create table T (id int primary key, qty int)".to_string()),
|
||||
))
|
||||
.expect("create");
|
||||
r.block_on(db.alter_add_table_check(
|
||||
"T".to_string(),
|
||||
Some("qty_positive".to_string()),
|
||||
"qty >= 0".to_string(),
|
||||
Some("alter table T add constraint qty_positive check (qty >= 0)".to_string()),
|
||||
))
|
||||
.expect("add named check");
|
||||
drop(db);
|
||||
path
|
||||
};
|
||||
// Delete the .db → the next open + rebuild reconstructs from yaml.
|
||||
std::fs::remove_file(project_path.join(PLAYGROUND_DB)).unwrap();
|
||||
let project = project::Project::open(&project_path).unwrap();
|
||||
let db = Database::open_with_persistence(
|
||||
project.db_path(),
|
||||
Persistence::new(project.path().to_path_buf()),
|
||||
)
|
||||
.unwrap();
|
||||
r.block_on(db.rebuild_from_text(project.path().to_path_buf(), None)).expect("rebuild");
|
||||
|
||||
// The named CHECK metadata survived: DROP CONSTRAINT by name resolves.
|
||||
r.block_on(db.alter_drop_constraint(
|
||||
"T".to_string(),
|
||||
"qty_positive".to_string(),
|
||||
Some("drop".to_string()),
|
||||
))
|
||||
.expect("DROP CONSTRAINT after a fresh rebuild — the CHECK metadata was reconstructed");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user