#![cfg(any(feature = "rusqlite", feature = "turso", feature = "libsql"))]
use crate::common::schema::sqlite::{InsertSimple, SelectSimple, SimpleSchema, UpdateSimple};
use drizzle::core::expr::*;
use drizzle::error::DrizzleError;
use drizzle::sqlite::connection::SQLiteTransactionType;
use drizzle::sqlite::prelude::*;
use drizzle_macros::sqlite_test;
sqlite_test!(test_transaction_commit, SimpleSchema, {
let SimpleSchema { simple } = schema;
let result = drizzle_try!(db.transaction(SQLiteTransactionType::Deferred, |tx| {
drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("user1")])
.execute()
)?;
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("user2")])
.execute()
)?;
Ok(())
})
}));
assert!(result.is_ok());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 2);
assert_eq!(users[0].name, "user1");
assert_eq!(users[1].name, "user2");
});
sqlite_test!(test_transaction_rollback, SimpleSchema, {
let SimpleSchema { simple } = schema;
drizzle_exec!(
db.insert(simple)
.values([InsertSimple::new("initial_user")])
.execute()
);
let result: Result<(), DrizzleError> = drizzle_try!(db.transaction(
SQLiteTransactionType::Immediate,
|tx| drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("temp_user")])
.execute()
)?;
Err(DrizzleError::Other(
"Intentional rollback".to_string().into(),
))
})
));
assert!(result.is_err());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 1);
assert_eq!(users[0].name, "initial_user");
});
sqlite_test!(test_transaction_types, SimpleSchema, {
let SimpleSchema { simple } = schema;
for tx_type in [
SQLiteTransactionType::Deferred,
SQLiteTransactionType::Immediate,
SQLiteTransactionType::Exclusive,
] {
let result = drizzle_try!(db.transaction(tx_type, |tx| drizzle_tx!(tx, {
let user_name = format!("user_{:?}", tx_type);
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new(user_name.as_str())])
.execute()
)?;
Ok(())
})));
assert!(result.is_ok(), "Transaction failed for type {:?}", tx_type);
}
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 3);
});
sqlite_test!(test_transaction_query_builders, SimpleSchema, {
let SimpleSchema { simple } = schema;
drizzle_exec!(
db.insert(simple)
.values([
InsertSimple::new("alice"),
InsertSimple::new("bob"),
InsertSimple::new("charlie"),
])
.execute()
);
let result = drizzle_try!(
db.transaction(SQLiteTransactionType::Deferred, |tx| drizzle_tx!(tx, {
let users: Vec<SelectSimple> = drizzle_try!(
tx.select(())
.from(simple)
.r#where(eq(simple.name, "alice"))
.all()
)?;
assert_eq!(users.len(), 1);
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("dave")])
.execute()
)?;
drizzle_try!(
tx.update(simple)
.set(UpdateSimple::default().with_name("updated_bob"))
.r#where(eq(simple.name, "bob"))
.execute()
)?;
drizzle_try!(
tx.delete(simple)
.r#where(eq(simple.name, "charlie"))
.execute()
)?;
Ok(())
}))
);
assert!(result.is_ok());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 3);
let names: Vec<String> = users.into_iter().map(|u| u.name).collect();
assert!(names.contains(&"alice".to_string()));
assert!(names.contains(&"dave".to_string()));
assert!(names.contains(&"updated_bob".to_string()));
assert!(!names.contains(&"bob".to_string()));
assert!(!names.contains(&"charlie".to_string()));
});
sqlite_test!(test_transaction_database_error_rollback, SimpleSchema, {
let SimpleSchema { simple } = schema;
drizzle_exec!(
db.insert(simple)
.values([InsertSimple::new("initial")])
.execute()
);
let result = drizzle_try!(
db.transaction(SQLiteTransactionType::Deferred, |tx| drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("valid_insert")])
.execute()
)?;
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("duplicate").with_id(1)]) .execute()
)?;
Ok(())
}))
);
assert!(result.is_err());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 1);
assert_eq!(users[0].name, "initial");
});
sqlite_test!(test_transaction_panic_rollback, SimpleSchema, {
let SimpleSchema { simple } = schema;
drizzle_exec!(
db.insert(simple)
.values([InsertSimple::new("before_panic")])
.execute()
);
let result: Result<Result<(), DrizzleError>, _> = drizzle_catch_unwind!(db.transaction(
SQLiteTransactionType::Deferred,
|tx| drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("should_rollback")])
.execute()
)?;
panic!("Simulated panic in transaction");
})
));
assert!(result.is_err());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 1);
assert_eq!(users[0].name, "before_panic");
});
sqlite_test!(test_nested_transaction_operations, SimpleSchema, {
let SimpleSchema { simple } = schema;
let result = drizzle_try!(
db.transaction(SQLiteTransactionType::Immediate, |tx| drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([
InsertSimple::new("user1"),
InsertSimple::new("user2"),
InsertSimple::new("user3"),
])
.execute()
)?;
let count: Vec<SelectSimple> = drizzle_try!(tx.select(()).from(simple).all())?;
assert_eq!(count.len(), 3);
drizzle_try!(
tx.update(simple)
.set(UpdateSimple::default().with_name("updated_user1"))
.r#where(eq(simple.name, "user1"))
.execute()
)?;
drizzle_try!(
tx.delete(simple)
.r#where(eq(simple.name, "user3"))
.execute()
)?;
let remaining: Vec<SelectSimple> = drizzle_try!(tx.select(()).from(simple).all())?;
assert_eq!(remaining.len(), 2);
Ok(())
}))
);
assert!(result.is_ok());
let final_users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(final_users.len(), 2);
let names: Vec<String> = final_users.into_iter().map(|u| u.name).collect();
assert!(names.contains(&"updated_user1".to_string()));
assert!(names.contains(&"user2".to_string()));
assert!(!names.contains(&"user1".to_string()));
assert!(!names.contains(&"user3".to_string()));
});
sqlite_test!(
test_transaction_with_failed_query_in_middle,
SimpleSchema,
{
let SimpleSchema { simple } = schema;
let result = drizzle_try!(db.transaction(
SQLiteTransactionType::Deferred,
|tx| drizzle_tx!(tx, {
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("first")])
.execute()
)?;
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new("second")])
.execute()
)?;
let affected = drizzle_try!(
tx.update(simple)
.set(UpdateSimple::default().with_name("wont_work"))
.r#where(eq(simple.name, "nonexistent_user"))
.execute()
)?;
if affected == 0 {
return Err(DrizzleError::Other(
"No rows affected by update".to_string().into(),
));
}
Ok(())
})
));
assert!(result.is_err());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 0);
}
);
sqlite_test!(test_large_transaction_rollback, SimpleSchema, {
let SimpleSchema { simple } = schema;
let result: Result<(), DrizzleError> = drizzle_try!(db.transaction(
SQLiteTransactionType::Exclusive,
|tx| drizzle_tx!(tx, {
for i in 0..100 {
let user_name = format!("user_{}", i);
drizzle_try!(
tx.insert(simple)
.values([InsertSimple::new(user_name.as_str())])
.execute()
)?;
}
let count: Vec<SelectSimple> = drizzle_try!(tx.select(()).from(simple).all())?;
assert_eq!(count.len(), 100);
Err(DrizzleError::Other(
"Intentional rollback of large transaction"
.to_string()
.into(),
))
})
));
assert!(result.is_err());
let users: Vec<SelectSimple> = drizzle_exec!(db.select(()).from(simple).all());
assert_eq!(users.len(), 0);
});