use stoolap::Database;
#[test]
fn test_vacuum_empty_database() {
let db = Database::open("memory://vacuum_empty").expect("Failed to create database");
let result = db.query("VACUUM", ()).expect("VACUUM should succeed");
let mut found = false;
for row in result {
let row = row.expect("Failed to get row");
let deleted: i64 = row.get(0).unwrap();
let versions: i64 = row.get(1).unwrap();
let txns: i64 = row.get(2).unwrap();
assert_eq!(deleted, 0);
assert_eq!(versions, 0);
assert_eq!(txns, 0);
found = true;
}
assert!(found, "Expected one result row");
}
#[test]
fn test_vacuum_cleans_deleted_rows() {
let db = Database::open("memory://vacuum_deleted").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.expect("CREATE TABLE failed");
for i in 1..=100 {
db.execute(&format!("INSERT INTO t VALUES ({}, 'row_{}')", i, i), ())
.expect("INSERT failed");
}
db.execute("DELETE FROM t WHERE id <= 50", ())
.expect("DELETE failed");
let result = db.query("VACUUM", ()).expect("VACUUM failed");
let mut deleted_cleaned = 0i64;
for row in result {
let row = row.expect("Failed to get row");
deleted_cleaned = row.get(0).unwrap();
}
assert!(
deleted_cleaned > 0,
"Expected VACUUM to clean deleted rows, got {}",
deleted_cleaned
);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("COUNT failed");
assert_eq!(count, 50, "Should have 50 remaining rows");
let min_id: i64 = db
.query_one("SELECT MIN(id) FROM t", ())
.expect("MIN failed");
assert_eq!(min_id, 51, "Smallest remaining id should be 51");
}
#[test]
fn test_vacuum_specific_table() {
let db = Database::open("memory://vacuum_table").expect("Failed to create database");
db.execute("CREATE TABLE t1 (id INTEGER PRIMARY KEY)", ())
.expect("CREATE t1 failed");
db.execute("CREATE TABLE t2 (id INTEGER PRIMARY KEY)", ())
.expect("CREATE t2 failed");
for i in 1..=10 {
db.execute(&format!("INSERT INTO t1 VALUES ({})", i), ())
.expect("INSERT t1 failed");
db.execute(&format!("INSERT INTO t2 VALUES ({})", i), ())
.expect("INSERT t2 failed");
}
db.execute("DELETE FROM t1 WHERE id <= 5", ())
.expect("DELETE t1 failed");
db.execute("DELETE FROM t2 WHERE id <= 5", ())
.expect("DELETE t2 failed");
let result = db.query("VACUUM t1", ()).expect("VACUUM t1 failed");
let mut deleted_cleaned = 0i64;
for row in result {
let row = row.expect("Failed to get row");
deleted_cleaned = row.get(0).unwrap();
}
assert!(
deleted_cleaned > 0,
"Expected VACUUM to clean deleted rows from t1"
);
let c1: i64 = db
.query_one("SELECT COUNT(*) FROM t1", ())
.expect("COUNT t1 failed");
let c2: i64 = db
.query_one("SELECT COUNT(*) FROM t2", ())
.expect("COUNT t2 failed");
assert_eq!(c1, 5);
assert_eq!(c2, 5);
}
#[test]
fn test_vacuum_nonexistent_table() {
let db = Database::open("memory://vacuum_noexist").expect("Failed to create database");
let result = db.execute("VACUUM nonexistent_table", ());
assert!(result.is_err(), "VACUUM on nonexistent table should fail");
}
#[test]
fn test_pragma_vacuum() {
let db = Database::open("memory://pragma_vacuum").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.expect("CREATE TABLE failed");
for i in 1..=50 {
db.execute(&format!("INSERT INTO t VALUES ({}, 'row_{}')", i, i), ())
.expect("INSERT failed");
}
db.execute("DELETE FROM t WHERE id <= 25", ())
.expect("DELETE failed");
let result = db.query("PRAGMA vacuum", ()).expect("PRAGMA vacuum failed");
let mut deleted_cleaned = 0i64;
for row in result {
let row = row.expect("Failed to get row");
deleted_cleaned = row.get(0).unwrap();
}
assert!(
deleted_cleaned > 0,
"Expected PRAGMA vacuum to clean deleted rows"
);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("COUNT failed");
assert_eq!(count, 25);
}
#[test]
fn test_vacuum_after_updates() {
let db = Database::open("memory://vacuum_updates").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val INTEGER)", ())
.expect("CREATE TABLE failed");
for i in 1..=20 {
db.execute(&format!("INSERT INTO t VALUES ({}, {})", i, i), ())
.expect("INSERT failed");
}
for _ in 0..5 {
db.execute("UPDATE t SET val = val + 1", ())
.expect("UPDATE failed");
}
let result = db.query("VACUUM", ()).expect("VACUUM failed");
let mut versions_cleaned = 0i64;
for row in result {
let row = row.expect("Failed to get row");
versions_cleaned = row.get(1).unwrap();
}
assert!(
versions_cleaned > 0,
"Expected VACUUM to clean old versions after updates, got {}",
versions_cleaned
);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("COUNT failed");
assert_eq!(count, 20);
let sum: i64 = db
.query_one("SELECT SUM(val) FROM t", ())
.expect("SUM failed");
assert_eq!(sum, 310);
}
#[test]
fn test_vacuum_idempotent() {
let db = Database::open("memory://vacuum_idempotent").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY)", ())
.expect("CREATE TABLE failed");
for i in 1..=10 {
db.execute(&format!("INSERT INTO t VALUES ({})", i), ())
.expect("INSERT failed");
}
db.execute("DELETE FROM t WHERE id <= 5", ())
.expect("DELETE failed");
db.execute("VACUUM", ()).expect("First VACUUM failed");
let result = db.query("VACUUM", ()).expect("Second VACUUM failed");
let mut deleted_cleaned = 0i64;
for row in result {
let row = row.expect("Failed to get row");
deleted_cleaned = row.get(0).unwrap();
}
assert_eq!(
deleted_cleaned, 0,
"Second VACUUM should find nothing to clean"
);
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("COUNT failed");
assert_eq!(count, 5);
}
#[test]
fn test_vacuum_insert_after_delete() {
let db = Database::open("memory://vacuum_reinsert").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, val TEXT)", ())
.expect("CREATE TABLE failed");
for i in 1..=10 {
db.execute(
&format!("INSERT INTO t VALUES ({}, 'original_{}')", i, i),
(),
)
.expect("INSERT failed");
}
db.execute("DELETE FROM t WHERE id <= 5", ())
.expect("DELETE failed");
db.execute("VACUUM", ()).expect("VACUUM failed");
for i in 1..=5 {
db.execute(&format!("INSERT INTO t VALUES ({}, 'new_{}')", i, i), ())
.expect("Re-INSERT failed");
}
let count: i64 = db
.query_one("SELECT COUNT(*) FROM t", ())
.expect("COUNT failed");
assert_eq!(count, 10);
let val: String = db
.query_one("SELECT val FROM t WHERE id = 1", ())
.expect("SELECT failed");
assert_eq!(val, "new_1");
}
#[test]
fn test_vacuum_rejects_inside_transaction() {
let db = Database::open("memory://vacuum_tx_reject").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY)", ())
.expect("CREATE TABLE failed");
db.execute("BEGIN", ()).expect("BEGIN failed");
let result = db.execute("VACUUM", ());
assert!(
result.is_err(),
"VACUUM should fail inside an active transaction"
);
db.execute("ROLLBACK", ()).expect("ROLLBACK failed");
db.execute("VACUUM", ())
.expect("VACUUM should succeed outside transaction");
}
#[test]
fn test_pragma_vacuum_rejects_inside_transaction() {
let db = Database::open("memory://pragma_vacuum_tx").expect("Failed to create database");
db.execute("CREATE TABLE t (id INTEGER PRIMARY KEY)", ())
.expect("CREATE TABLE failed");
db.execute("BEGIN", ()).expect("BEGIN failed");
let result = db.execute("PRAGMA vacuum", ());
assert!(
result.is_err(),
"PRAGMA VACUUM should fail inside an active transaction"
);
db.execute("ROLLBACK", ()).expect("ROLLBACK failed");
db.execute("PRAGMA vacuum", ())
.expect("PRAGMA VACUUM should succeed outside transaction");
}