mod test_helpers {
include!("../common/test_helpers.rs");
}
use test_helpers::run_with_both_backends;
use tegdb::{Database, Result, SqlValue};
#[test]
fn test_basic_operations_both_backends() -> Result<()> {
run_with_both_backends("basic_operations", |db_path| {
let mut db = Database::open(db_path)?;
let affected = db.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT(32) NOT NULL, age INTEGER)",
)?;
assert_eq!(affected, 0);
let affected = db.execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")?;
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users").unwrap();
assert!(result.columns().contains(&"id".to_string()));
assert!(result.columns().contains(&"name".to_string()));
assert!(result.columns().contains(&"age".to_string()));
assert_eq!(result.columns().len(), 3);
assert_eq!(result.rows().len(), 1);
let affected = db.execute("UPDATE users SET age = 31 WHERE name = 'Alice'")?;
assert_eq!(affected, 1);
let affected = db.execute("DELETE FROM users WHERE age < 30")?;
assert_eq!(affected, 0);
let result = db.query("SELECT name, age FROM users").unwrap();
assert_eq!(result.rows().len(), 1); assert_eq!(result.rows()[0][0], SqlValue::Text("Alice".to_string()));
assert_eq!(result.rows()[0][1], SqlValue::Integer(31));
Ok(())
})
}
#[test]
fn test_transactions_both_backends() -> Result<()> {
run_with_both_backends("transactions", |db_path| {
let mut db = Database::open(db_path)?;
db.execute("CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)")?;
db.execute("INSERT INTO accounts (id, balance) VALUES (1, 1000)")?;
db.execute("INSERT INTO accounts (id, balance) VALUES (2, 500)")?;
{
let mut tx = db.begin_transaction()?;
let affected1 = tx.execute("UPDATE accounts SET balance = 800 WHERE id = 1")?;
assert_eq!(affected1, 1);
let affected2 = tx.execute("UPDATE accounts SET balance = 700 WHERE id = 2")?;
assert_eq!(affected2, 1);
let result = tx.query("SELECT id, balance FROM accounts").unwrap();
assert_eq!(result.rows().len(), 2);
let row1 = &result.rows()[0];
let row2 = &result.rows()[1];
assert_eq!(row1[1], SqlValue::Integer(800));
assert_eq!(row2[1], SqlValue::Integer(700));
tx.commit()?;
}
let result = db.query("SELECT id, balance FROM accounts").unwrap();
let row1 = &result.rows()[0];
let row2 = &result.rows()[1];
assert_eq!(row1[1], SqlValue::Integer(800));
assert_eq!(row2[1], SqlValue::Integer(700));
Ok(())
})
}
#[test]
fn test_data_types_both_backends() -> Result<()> {
run_with_both_backends("data_types", |db_path| {
let mut db = Database::open(db_path)?;
db.execute(
"CREATE TABLE test_types (
id INTEGER PRIMARY KEY,
text_col TEXT(32),
int_col INTEGER,
real_col REAL,
null_col TEXT(32)
)",
)?;
db.execute(&format!("INSERT INTO test_types (id, text_col, int_col, real_col, null_col) VALUES (1, 'hello', 42, {}, 'empty')", std::f64::consts::PI))?;
db.execute("INSERT INTO test_types (id, text_col, int_col, real_col, null_col) VALUES (2, 'test', -100, -2.5, 'empty')")?;
db.execute("INSERT INTO test_types (id, text_col, int_col, real_col, null_col) VALUES (3, 'world', 0, 0.0, 'not null')")?;
let result = db.query("SELECT * FROM test_types").unwrap();
assert_eq!(result.rows().len(), 3);
let row1 = &result.rows()[0];
let id_pos = result.columns().iter().position(|c| c == "id").unwrap();
let text_pos = result
.columns()
.iter()
.position(|c| c == "text_col")
.unwrap();
let int_pos = result
.columns()
.iter()
.position(|c| c == "int_col")
.unwrap();
let real_pos = result
.columns()
.iter()
.position(|c| c == "real_col")
.unwrap();
let null_pos = result
.columns()
.iter()
.position(|c| c == "null_col")
.unwrap();
assert_eq!(row1[id_pos], SqlValue::Integer(1));
assert_eq!(row1[text_pos], SqlValue::Text("hello".to_string()));
assert_eq!(row1[int_pos], SqlValue::Integer(42));
assert_eq!(row1[real_pos], SqlValue::Real(std::f64::consts::PI));
assert_eq!(row1[null_pos], SqlValue::Text("empty".to_string()));
Ok(())
})
}
#[test]
fn test_schema_persistence_both_backends() -> Result<()> {
run_with_both_backends("schema_persistence", |db_path| {
{
let mut db = Database::open(db_path)?;
db.execute("CREATE TABLE persistent_test (id INTEGER PRIMARY KEY, data TEXT(32))")?;
db.execute("INSERT INTO persistent_test (id, data) VALUES (1, 'test data')")?;
}
{
let mut db = Database::open(db_path)?;
let result = db.query("SELECT * FROM persistent_test").unwrap();
assert_eq!(result.rows().len(), 1);
let id_pos = result
.columns()
.iter()
.position(|c| c == "id")
.expect("id column not found");
let data_pos = result
.columns()
.iter()
.position(|c| c == "data")
.expect("data column not found");
assert_eq!(result.rows()[0][id_pos], SqlValue::Integer(1));
assert_eq!(
result.rows()[0][data_pos],
SqlValue::Text("test data".to_string())
);
db.execute("INSERT INTO persistent_test (id, data) VALUES (2, 'more data')")?;
let result = db.query("SELECT * FROM persistent_test").unwrap();
assert_eq!(result.rows().len(), 2);
}
Ok(())
})
}
#[test]
fn test_converted_from_existing_test() -> Result<()> {
run_with_both_backends("converted_test", |db_path| {
let mut db = Database::open(db_path)?;
let affected = db.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT(32) NOT NULL, age INTEGER)",
)?;
assert_eq!(affected, 0);
let affected = db.execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")?;
assert_eq!(affected, 1);
let affected = db.execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")?;
assert_eq!(affected, 1);
let affected = db.execute("INSERT INTO users (id, name, age) VALUES (3, 'Carol', 35)")?;
assert_eq!(affected, 1);
let result = db.query("SELECT * FROM users").unwrap();
assert!(result.columns().contains(&"id".to_string()));
assert!(result.columns().contains(&"name".to_string()));
assert!(result.columns().contains(&"age".to_string()));
assert_eq!(result.columns().len(), 3);
assert_eq!(result.rows().len(), 3);
let affected = db.execute("UPDATE users SET age = 31 WHERE name = 'Alice'")?;
assert_eq!(affected, 1);
let affected = db.execute("DELETE FROM users WHERE age < 30")?;
assert_eq!(affected, 1);
let result = db.query("SELECT name, age FROM users").unwrap();
assert_eq!(result.rows().len(), 2);
Ok(())
})
}