use stoolap::Database;
#[test]
fn test_as_of_parser_transaction_integer() {
let db = Database::open("memory://as_of_parser1").expect("Failed to create database");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Create failed");
db.execute("INSERT INTO users VALUES (1, 'Alice')", ())
.expect("Insert failed");
let result = db.query("SELECT * FROM users AS OF TRANSACTION 12345", ());
assert!(
result.is_ok(),
"AS OF TRANSACTION with integer should parse"
);
}
#[test]
fn test_as_of_parser_timestamp_string() {
let db = Database::open("memory://as_of_parser2").expect("Failed to create database");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Create failed");
db.execute("INSERT INTO users VALUES (1, 'Alice')", ())
.expect("Insert failed");
let result = db.query(
"SELECT * FROM users AS OF TIMESTAMP '2024-01-01 10:00:00'",
(),
);
assert!(result.is_ok(), "AS OF TIMESTAMP with string should parse");
}
#[test]
fn test_as_of_parser_with_table_alias() {
let db = Database::open("memory://as_of_parser3").expect("Failed to create database");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)", ())
.expect("Create failed");
db.execute("INSERT INTO users VALUES (1, 'Alice')", ())
.expect("Insert failed");
let result = db.query("SELECT * FROM users AS OF TRANSACTION 100 AS u", ());
assert!(result.is_ok(), "AS OF with table alias should parse");
}
#[test]
fn test_as_of_parser_invalid_type() {
let db = Database::open("memory://as_of_parser4").expect("Failed to create database");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY)", ())
.expect("Create failed");
let result = db.query("SELECT * FROM users AS OF INVALID 100", ());
assert!(result.is_err(), "Invalid AS OF type should error");
}
#[test]
fn test_as_of_parser_missing_value() {
let db = Database::open("memory://as_of_parser5").expect("Failed to create database");
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY)", ())
.expect("Create failed");
let result = db.query("SELECT * FROM users AS OF TRANSACTION", ());
assert!(result.is_err(), "Missing AS OF value should error");
}
#[test]
fn test_as_of_transaction_basic() {
let db = Database::open("memory://as_of_exec1").expect("Failed to create database");
db.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO users VALUES (1, 'Alice', 30)", ())
.expect("Insert failed");
db.execute("INSERT INTO users VALUES (2, 'Bob', 25)", ())
.expect("Insert failed");
db.execute("UPDATE users SET age = 31 WHERE id = 1", ())
.expect("Update failed");
let current_age: i64 = db
.query_one("SELECT age FROM users WHERE id = 1", ())
.expect("Query failed");
assert_eq!(current_age, 31, "Current age should be 31");
let result = db.query("SELECT * FROM users AS OF TRANSACTION 3", ());
assert!(result.is_ok(), "AS OF TRANSACTION query should execute");
}
#[test]
fn test_as_of_transaction_with_where() {
let db = Database::open("memory://as_of_exec2").expect("Failed to create database");
db.execute(
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO users VALUES (1, 'Alice', 30)", ())
.expect("Insert failed");
db.execute("INSERT INTO users VALUES (2, 'Bob', 25)", ())
.expect("Insert failed");
let result = db.query("SELECT * FROM users AS OF TRANSACTION 2 WHERE id = 1", ());
assert!(result.is_ok(), "AS OF with WHERE should execute");
}
#[test]
fn test_as_of_timestamp() {
let db = Database::open("memory://as_of_exec3").expect("Failed to create database");
db.execute(
"CREATE TABLE events (id INTEGER PRIMARY KEY, event TEXT, status TEXT)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO events VALUES (1, 'Event A', 'pending')", ())
.expect("Insert failed");
db.execute("INSERT INTO events VALUES (2, 'Event B', 'pending')", ())
.expect("Insert failed");
db.execute("UPDATE events SET status = 'completed' WHERE id = 1", ())
.expect("Update failed");
let result = db.query(
"SELECT * FROM events AS OF TIMESTAMP '2020-01-01 00:00:00'",
(),
);
assert!(result.is_ok(), "AS OF TIMESTAMP should execute");
let result = db.query(
"SELECT * FROM events AS OF TIMESTAMP '2050-01-01 00:00:00'",
(),
);
assert!(
result.is_ok(),
"AS OF TIMESTAMP with future date should execute"
);
}
#[test]
fn test_as_of_isolation() {
let db = Database::open("memory://as_of_exec4").expect("Failed to create database");
db.execute(
"CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO accounts VALUES (1, 1000)", ())
.expect("Insert failed");
db.execute("UPDATE accounts SET balance = 2000 WHERE id = 1", ())
.expect("Update failed");
let current_balance: i64 = db
.query_one("SELECT balance FROM accounts WHERE id = 1", ())
.expect("Query failed");
assert_eq!(current_balance, 2000, "Current balance should be 2000");
let result = db.query(
"SELECT balance FROM accounts AS OF TRANSACTION 2 WHERE id = 1",
(),
);
assert!(result.is_ok(), "AS OF query should execute");
}
#[test]
fn test_as_of_errors() {
let db = Database::open("memory://as_of_exec5").expect("Failed to create database");
db.execute(
"CREATE TABLE test_errors (id INTEGER PRIMARY KEY, value TEXT)",
(),
)
.expect("Create failed");
let result = db.query(
"SELECT * FROM test_errors AS OF TIMESTAMP 'invalid-date'",
(),
);
assert!(result.is_err(), "Invalid timestamp format should error");
let result = db.query("SELECT * FROM non_existent AS OF TRANSACTION 1", ());
assert!(result.is_err(), "Non-existent table should error");
}
#[test]
fn test_as_of_version_chain_traversal() {
let db = Database::open("memory://as_of_edge1").expect("Failed to create database");
db.execute(
"CREATE TABLE version_chain (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO version_chain VALUES (1, 1)", ())
.expect("Insert failed");
for i in 2..=10 {
db.execute(
&format!("UPDATE version_chain SET value = {} WHERE id = 1", i),
(),
)
.expect("Update failed");
}
let current_value: i64 = db
.query_one("SELECT value FROM version_chain WHERE id = 1", ())
.expect("Query failed");
assert_eq!(current_value, 10, "Current value should be 10");
for txn_id in [2, 5, 8, 10] {
let result = db.query(
&format!(
"SELECT value FROM version_chain AS OF TRANSACTION {} WHERE id = 1",
txn_id
),
(),
);
assert!(
result.is_ok(),
"AS OF TRANSACTION {} should execute",
txn_id
);
}
}
#[test]
fn test_as_of_with_deleted_version_chain() {
let db = Database::open("memory://as_of_edge2").expect("Failed to create database");
db.execute(
"CREATE TABLE delete_chain (id INTEGER PRIMARY KEY, status TEXT)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO delete_chain VALUES (1, 'created')", ())
.expect("Insert failed");
db.execute(
"UPDATE delete_chain SET status = 'updated' WHERE id = 1",
(),
)
.expect("Update failed");
db.execute("DELETE FROM delete_chain WHERE id = 1", ())
.expect("Delete failed");
db.execute("INSERT INTO delete_chain VALUES (1, 'recreated')", ())
.expect("Re-insert failed");
let current_status: String = db
.query_one("SELECT status FROM delete_chain WHERE id = 1", ())
.expect("Query failed");
assert_eq!(
current_status, "recreated",
"Current status should be 'recreated'"
);
let result = db.query(
"SELECT status FROM delete_chain AS OF TRANSACTION 2 WHERE id = 1",
(),
);
assert!(result.is_ok(), "AS OF after insert should execute");
}
#[test]
fn test_as_of_timestamp_boundary_conditions() {
let db = Database::open("memory://as_of_edge3").expect("Failed to create database");
db.execute(
"CREATE TABLE timestamp_edge (id INTEGER PRIMARY KEY, created_at TEXT)",
(),
)
.expect("Create failed");
db.execute(
"INSERT INTO timestamp_edge VALUES (1, '2024-06-15 12:00:00')",
(),
)
.expect("Insert failed");
let test_cases = [
("2024-06-15 12:00:01", true), ("2024-06-15 11:00:00", false), ("2024-06-16 12:00:00", true), ("2050-01-01 00:00:00", true), ("2020-01-01 00:00:00", false), ];
for (timestamp, _should_have_row) in test_cases {
let result = db.query(
&format!(
"SELECT id FROM timestamp_edge AS OF TIMESTAMP '{}'",
timestamp
),
(),
);
assert!(
result.is_ok(),
"AS OF TIMESTAMP '{}' should execute",
timestamp
);
}
}
#[test]
fn test_as_of_error_conditions() {
let db = Database::open("memory://as_of_edge4").expect("Failed to create database");
db.execute(
"CREATE TABLE error_test (id INTEGER PRIMARY KEY, data TEXT)",
(),
)
.expect("Create failed");
let result = db.query("SELECT * FROM error_test AS OF INVALID 123", ());
assert!(result.is_err(), "Invalid AS OF type should error");
let result = db.query("SELECT * FROM error_test AS OF TRANSACTION 'abc'", ());
assert!(result.is_err(), "Non-integer transaction ID should error");
let result = db.query("SELECT * FROM error_test AS OF TIMESTAMP 123", ());
assert!(
result.is_ok(),
"AS OF TIMESTAMP with integer is valid (nanoseconds)"
);
let result = db.query("SELECT * FROM error_test AS OF TIMESTAMP 'not-a-date'", ());
assert!(result.is_err(), "Malformed timestamp should error");
let result = db.query("SELECT * FROM non_existent AS OF TRANSACTION 1", ());
assert!(result.is_err(), "AS OF on non-existent table should error");
}
#[test]
fn test_as_of_with_null_values() {
let db = Database::open("memory://as_of_edge5").expect("Failed to create database");
db.execute(
"CREATE TABLE null_test (id INTEGER PRIMARY KEY, optional_value TEXT)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO null_test VALUES (1, NULL)", ())
.expect("Insert failed");
db.execute(
"UPDATE null_test SET optional_value = 'not null' WHERE id = 1",
(),
)
.expect("Update failed");
db.execute(
"UPDATE null_test SET optional_value = NULL WHERE id = 1",
(),
)
.expect("Update back to NULL failed");
let result = db.query(
"SELECT optional_value FROM null_test AS OF TRANSACTION 2 WHERE id = 1",
(),
);
assert!(result.is_ok(), "AS OF with NULL should execute");
}
#[test]
fn test_as_of_empty_table() {
let db = Database::open("memory://as_of_cov1").expect("Failed to create database");
db.execute(
"CREATE TABLE coverage_test (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
let result = db.query("SELECT * FROM coverage_test AS OF TRANSACTION 1", ());
assert!(result.is_ok(), "AS OF on empty table should execute");
}
#[test]
fn test_as_of_very_old_transaction() {
let db = Database::open("memory://as_of_cov2").expect("Failed to create database");
db.execute(
"CREATE TABLE coverage_test (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO coverage_test VALUES (1, 100)", ())
.expect("Insert failed");
let result = db.query("SELECT * FROM coverage_test AS OF TRANSACTION 0", ());
assert!(result.is_ok(), "AS OF TRANSACTION 0 should execute");
}
#[test]
fn test_as_of_very_old_timestamp() {
let db = Database::open("memory://as_of_cov3").expect("Failed to create database");
db.execute(
"CREATE TABLE coverage_test (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO coverage_test VALUES (1, 100)", ())
.expect("Insert failed");
let result = db.query(
"SELECT * FROM coverage_test AS OF TIMESTAMP '1970-01-01 00:00:00'",
(),
);
assert!(result.is_ok(), "AS OF TIMESTAMP 1970 should execute");
}
#[test]
fn test_as_of_future_timestamp() {
let db = Database::open("memory://as_of_cov4").expect("Failed to create database");
db.execute(
"CREATE TABLE coverage_test (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO coverage_test VALUES (1, 100)", ())
.expect("Insert failed");
let result = db.query(
"SELECT * FROM coverage_test AS OF TIMESTAMP '2050-01-01 00:00:00'",
(),
);
assert!(result.is_ok(), "AS OF TIMESTAMP 2050 should execute");
}
#[test]
fn test_as_of_with_complex_expressions() {
let db = Database::open("memory://as_of_cov5").expect("Failed to create database");
db.execute(
"CREATE TABLE coverage_test (id INTEGER PRIMARY KEY, value INTEGER, text_value TEXT)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO coverage_test VALUES (1, 100, 'test1')", ())
.expect("Insert failed");
db.execute("INSERT INTO coverage_test VALUES (2, 200, 'test2')", ())
.expect("Insert failed");
db.execute("INSERT INTO coverage_test VALUES (3, 300, NULL)", ())
.expect("Insert failed");
let result = db.query(
"SELECT id, value FROM coverage_test AS OF TRANSACTION 4 \
WHERE (value > 150 AND value < 400) OR text_value IS NULL \
ORDER BY id",
(),
);
assert!(result.is_ok(), "AS OF with complex WHERE should execute");
}
#[test]
fn test_as_of_concurrent_access() {
let db = Database::open("memory://as_of_cov6").expect("Failed to create database");
db.execute(
"CREATE TABLE concurrent_test (id INTEGER PRIMARY KEY, counter INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO concurrent_test VALUES (1, 0)", ())
.expect("Insert failed");
for i in 1..=5 {
db.execute(
&format!("UPDATE concurrent_test SET counter = {} WHERE id = 1", i),
(),
)
.expect("Update failed");
}
let current: i64 = db
.query_one("SELECT counter FROM concurrent_test WHERE id = 1", ())
.expect("Query failed");
assert_eq!(current, 5, "Current counter should be 5");
for txn_id in 2..=6 {
let result = db.query(
&format!(
"SELECT counter FROM concurrent_test AS OF TRANSACTION {} WHERE id = 1",
txn_id
),
(),
);
assert!(
result.is_ok(),
"AS OF TRANSACTION {} should execute",
txn_id
);
}
}
#[test]
fn test_as_of_timestamp_precision() {
let db = Database::open("memory://as_of_cov7").expect("Failed to create database");
db.execute(
"CREATE TABLE timestamp_precision (id INTEGER PRIMARY KEY)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO timestamp_precision VALUES (1)", ())
.expect("Insert failed");
let timestamps = [
"2025-01-01 12:00:00", "2025-01-01 12:00:00.123", "2025-01-01 12:00:00.123456", ];
for ts in timestamps {
let result = db.query(
&format!(
"SELECT id FROM timestamp_precision AS OF TIMESTAMP '{}'",
ts
),
(),
);
if result.is_err() {
println!(
"Timestamp format '{}' not supported: {:?}",
ts,
result.err()
);
}
}
}
#[test]
fn test_as_of_with_aggregation() {
let db = Database::open("memory://as_of_cov8").expect("Failed to create database");
db.execute(
"CREATE TABLE sales (id INTEGER PRIMARY KEY, amount FLOAT)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO sales VALUES (1, 100.0)", ())
.expect("Insert failed");
db.execute("INSERT INTO sales VALUES (2, 200.0)", ())
.expect("Insert failed");
db.execute("UPDATE sales SET amount = 150.0 WHERE id = 1", ())
.expect("Update failed");
let current_sum: f64 = db
.query_one("SELECT SUM(amount) FROM sales", ())
.expect("Query failed");
assert!(
(current_sum - 350.0).abs() < 0.01,
"Current SUM should be 350"
);
let result = db.query("SELECT SUM(amount) FROM sales AS OF TRANSACTION 3", ());
assert!(result.is_ok(), "AS OF with SUM should execute");
}
#[test]
fn test_as_of_select_specific_columns() {
let db = Database::open("memory://as_of_cov9").expect("Failed to create database");
db.execute(
"CREATE TABLE multi_col (a INTEGER PRIMARY KEY, b TEXT, c FLOAT, d INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO multi_col VALUES (1, 'hello', 3.14, 42)", ())
.expect("Insert failed");
let result = db.query("SELECT a, c FROM multi_col AS OF TRANSACTION 2", ());
assert!(result.is_ok(), "AS OF with specific columns should execute");
let result = db.query(
"SELECT b, d FROM multi_col AS OF TRANSACTION 2 WHERE a = 1",
(),
);
assert!(
result.is_ok(),
"AS OF with specific columns and WHERE should execute"
);
}
#[test]
fn test_as_of_select_star() {
let db = Database::open("memory://as_of_cov10").expect("Failed to create database");
db.execute(
"CREATE TABLE star_test (id INTEGER PRIMARY KEY, value INTEGER)",
(),
)
.expect("Create failed");
db.execute("INSERT INTO star_test VALUES (1, 100)", ())
.expect("Insert failed");
db.execute("UPDATE star_test SET value = 200 WHERE id = 1", ())
.expect("Update failed");
let result = db.query("SELECT * FROM star_test AS OF TRANSACTION 2", ());
assert!(result.is_ok(), "AS OF with SELECT * should execute");
}