use motedb::{types::Value, Database};
use tempfile::TempDir;
fn rows(result: motedb::StreamingQueryResult) -> Vec<Vec<Value>> {
use motedb::QueryResult;
match result.materialize().unwrap() {
QueryResult::Select { rows, .. } => rows,
_ => panic!("Expected Select result"),
}
}
#[test]
fn test_auto_commit_writes_durable() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val INT)")
.unwrap();
db.execute("INSERT INTO t VALUES (1, 100)").unwrap();
let result = db.execute("SELECT val FROM t WHERE id = 1").unwrap();
let r = rows(result);
assert_eq!(r.len(), 1);
assert_eq!(&r[0][0], &Value::Integer(100));
}
#[test]
fn test_savepoint_rollback() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val TEXT)")
.unwrap();
let tx = db.begin_transaction().unwrap();
db.execute("INSERT INTO t VALUES (1, 'before')").unwrap();
db.savepoint(tx, "sp1").unwrap();
db.execute("INSERT INTO t VALUES (2, 'after')").unwrap();
db.rollback_to_savepoint(tx, "sp1").unwrap();
db.commit_transaction(tx).unwrap();
let result = db.execute("SELECT COUNT(*) FROM t").unwrap();
let r = rows(result);
assert!(r.len() >= 1);
}
#[test]
fn test_nested_savepoints() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val TEXT)")
.unwrap();
let tx = db.begin_transaction().unwrap();
db.execute("INSERT INTO t VALUES (1, 'root')").unwrap();
db.savepoint(tx, "sp1").unwrap();
db.execute("INSERT INTO t VALUES (2, 'sp1')").unwrap();
db.savepoint(tx, "sp2").unwrap();
db.execute("INSERT INTO t VALUES (3, 'sp2')").unwrap();
db.rollback_to_savepoint(tx, "sp1").unwrap();
db.commit_transaction(tx).unwrap();
let result = db.execute("SELECT COUNT(*) FROM t").unwrap();
let r = rows(result);
assert!(r.len() >= 1);
}
#[test]
fn test_release_savepoint() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val INT)")
.unwrap();
let tx = db.begin_transaction().unwrap();
db.savepoint(tx, "sp1").unwrap();
db.savepoint(tx, "sp2").unwrap();
db.release_savepoint(tx, "sp2").unwrap();
db.rollback_to_savepoint(tx, "sp1").unwrap();
db.commit_transaction(tx).unwrap();
}
#[test]
fn test_rollback_transaction() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val INT)")
.unwrap();
db.execute("INSERT INTO t VALUES (1, 10)").unwrap();
let tx = db.begin_transaction().unwrap();
db.execute("INSERT INTO t VALUES (2, 20)").unwrap();
db.rollback_transaction(tx).unwrap();
let result = db.execute("SELECT COUNT(*) FROM t").unwrap();
let r = rows(result);
assert!(r.len() >= 1);
}
#[test]
fn test_sequential_transactions() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val INT)")
.unwrap();
for i in 0..5 {
let tx = db.begin_transaction().unwrap();
db.execute(&format!("INSERT INTO t VALUES ({}, {})", i, i * 10))
.unwrap();
db.commit_transaction(tx).unwrap();
}
let result = db.execute("SELECT COUNT(*) FROM t").unwrap();
let r = rows(result);
assert_eq!(&r[0][0], &Value::Integer(5));
}
#[test]
fn test_transaction_stats_tracking() {
let dir = TempDir::new().unwrap();
let db = Database::create(dir.path()).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY)").unwrap();
let before = db.transaction_stats();
let tx = db.begin_transaction().unwrap();
db.execute("INSERT INTO t VALUES (1)").unwrap();
db.commit_transaction(tx).unwrap();
let after = db.transaction_stats();
assert_eq!(after.total_committed, before.total_committed + 1);
}
#[test]
fn test_crash_recovery_committed_survives() {
let dir = TempDir::new().unwrap();
let path = dir.path().to_path_buf();
{
let db = Database::create(&path).unwrap();
db.execute("CREATE TABLE t (id INT PRIMARY KEY, val TEXT)")
.unwrap();
db.execute("INSERT INTO t VALUES (1, 'committed')").unwrap();
db.checkpoint().unwrap();
db.close().unwrap();
}
{
let db = Database::open(&path).unwrap();
let result = db.execute("SELECT val FROM t WHERE id = 1").unwrap();
let r = rows(result);
assert_eq!(r.len(), 1);
assert_eq!(&r[0][0], &Value::text("committed".to_string()));
}
}