use vibesql_ast::{BeginStmt, CommitStmt, DurabilityHint, InsertStmt, RollbackStmt};
use vibesql_storage::Database;
use vibesql_types::SqlValue;
use super::common::setup_users_table as setup_test_table;
use crate::{BeginTransactionExecutor, CommitExecutor, InsertExecutor, RollbackExecutor};
#[test]
fn test_begin_transaction_success() {
let mut db = Database::new();
setup_test_table(&mut db);
assert!(!db.in_transaction());
assert_eq!(db.transaction_id(), None);
let result = BeginTransactionExecutor::execute(
&BeginStmt { durability: DurabilityHint::Default },
&mut db,
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Transaction started");
assert!(db.in_transaction());
assert_eq!(db.transaction_id(), Some(1));
}
#[test]
fn test_begin_transaction_already_active() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
assert!(db.in_transaction());
let result = BeginTransactionExecutor::execute(
&BeginStmt { durability: DurabilityHint::Default },
&mut db,
);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Transaction already active"));
}
#[test]
fn test_commit_without_transaction() {
let mut db = Database::new();
let result = CommitExecutor::execute(&CommitStmt, &mut db);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No active transaction to commit"));
}
#[test]
fn test_rollback_without_transaction() {
let mut db = Database::new();
let result = RollbackExecutor::execute(&RollbackStmt, &mut db);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No active transaction to rollback"));
}
#[test]
fn test_commit_transaction() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
assert!(db.in_transaction());
let result = CommitExecutor::execute(&CommitStmt, &mut db);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Transaction committed");
assert!(!db.in_transaction());
assert_eq!(db.transaction_id(), None);
}
#[test]
fn test_rollback_transaction() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
assert!(db.in_transaction());
let result = RollbackExecutor::execute(&RollbackStmt, &mut db);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "Transaction rolled back");
assert!(!db.in_transaction());
assert_eq!(db.transaction_id(), None);
}
#[test]
fn test_transaction_insert_commit() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
let rows = InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
assert_eq!(rows, 1);
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
CommitExecutor::execute(&CommitStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
}
#[test]
fn test_transaction_insert_rollback() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
let rows = InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
assert_eq!(rows, 1);
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
RollbackExecutor::execute(&RollbackStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 0);
}
#[test]
fn test_transaction_multiple_operations_commit() {
let mut db = Database::new();
setup_test_table(&mut db);
let insert_stmt1 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt1).unwrap();
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt2 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(2)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Bob"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt2).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 2);
CommitExecutor::execute(&CommitStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 2);
}
#[test]
fn test_transaction_multiple_operations_rollback() {
let mut db = Database::new();
setup_test_table(&mut db);
let insert_stmt1 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt1).unwrap();
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt2 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(2)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Bob"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt2).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 2);
RollbackExecutor::execute(&RollbackStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
}
#[test]
fn test_transaction_isolation() {
let mut db1 = Database::new();
let mut db2 = Database::new();
setup_test_table(&mut db1);
setup_test_table(&mut db2);
assert_eq!(db1.get_table("users").unwrap().row_count(), 0);
assert_eq!(db2.get_table("users").unwrap().row_count(), 0);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db1)
.unwrap();
let insert_stmt = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db1, &insert_stmt).unwrap();
assert_eq!(db1.get_table("users").unwrap().row_count(), 1);
assert_eq!(db2.get_table("users").unwrap().row_count(), 0);
CommitExecutor::execute(&CommitStmt, &mut db1).unwrap();
assert_eq!(db1.get_table("users").unwrap().row_count(), 1);
assert_eq!(db2.get_table("users").unwrap().row_count(), 0);
}
#[test]
fn test_transaction_nested_operations() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
for i in 1..=5 {
let insert_stmt = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(i)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from(format!(
"User{}",
i
)))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
}
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 5);
CommitExecutor::execute(&CommitStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 5);
}
#[test]
fn test_transaction_empty_rollback() {
let mut db = Database::new();
setup_test_table(&mut db);
let insert_stmt = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt).unwrap();
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
RollbackExecutor::execute(&RollbackStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
}
#[test]
fn test_multiple_transactions() {
let mut db = Database::new();
setup_test_table(&mut db);
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt1 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(1)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Alice"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt1).unwrap();
CommitExecutor::execute(&CommitStmt, &mut db).unwrap();
BeginTransactionExecutor::execute(&BeginStmt { durability: DurabilityHint::Default }, &mut db)
.unwrap();
let insert_stmt2 = InsertStmt {
with_clause: None,
schema_name: None,
schema_quoted: false,
table_quoted: false,
table_name: "users".to_string(),
columns: vec![],
source: vibesql_ast::InsertSource::Values(vec![vec![
vibesql_ast::Expression::Literal(SqlValue::Integer(2)),
vibesql_ast::Expression::Literal(SqlValue::Varchar(arcstr::ArcStr::from("Bob"))),
]]),
conflict_clause: None,
on_conflict: None,
on_duplicate_key_update: None,
returning: None,
};
InsertExecutor::execute(&mut db, &insert_stmt2).unwrap();
RollbackExecutor::execute(&RollbackStmt, &mut db).unwrap();
let table = db.get_table("users").unwrap();
assert_eq!(table.row_count(), 1);
let rows: Vec<_> = table.scan().iter().collect();
let first_row = &rows[0];
assert_eq!(first_row.get(0).unwrap(), &SqlValue::Integer(1));
assert_eq!(first_row.get(1).unwrap(), &SqlValue::Varchar(arcstr::ArcStr::from("Alice")));
}