From 92cddb64375457e16b67cbf5f58fc16c3d73b2fe Mon Sep 17 00:00:00 2001 From: Diego Reis Date: Thu, 17 Jul 2025 20:43:48 -0300 Subject: [PATCH] bind/rust: Add more tests for Transaction --- bindings/rust/src/lib.rs | 4 ++ bindings/rust/src/transaction.rs | 97 +++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index a7dbfe6fd..923cded43 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -36,6 +36,7 @@ pub mod params; pub mod transaction; pub mod value; +use transaction::TransactionBehavior; pub use value::Value; pub use params::params_from_iter; @@ -132,6 +133,7 @@ impl Database { #[allow(clippy::arc_with_non_send_sync)] let connection = Connection { inner: Arc::new(Mutex::new(conn)), + transaction_behavior: TransactionBehavior::Deferred, }; Ok(connection) } @@ -140,12 +142,14 @@ impl Database { /// A database connection. pub struct Connection { inner: Arc>>, + transaction_behavior: TransactionBehavior, } impl Clone for Connection { fn clone(&self) -> Self { Self { inner: Arc::clone(&self.inner), + transaction_behavior: self.transaction_behavior, } } } diff --git a/bindings/rust/src/transaction.rs b/bindings/rust/src/transaction.rs index 044d8fb5a..be9e2f493 100644 --- a/bindings/rust/src/transaction.rs +++ b/bindings/rust/src/transaction.rs @@ -288,7 +288,7 @@ impl Connection { #[cfg(test)] mod test { - use crate::{Builder, Connection, Result}; + use crate::{Builder, Connection, Error, Result}; use super::DropBehavior; @@ -299,18 +299,30 @@ mod test { Ok(conn) } + #[tokio::test] + #[should_panic(expected = "Transaction dropped without finish()")] + async fn test_drop_panic() { + let mut conn = checked_memory_handle().await.unwrap(); + { + let tx = conn.transaction().await.unwrap(); + tx.execute("INSERT INTO foo VALUES(?)", &[1]).await.unwrap(); + } + } + #[tokio::test] async fn test_drop() -> Result<()> { let mut conn = checked_memory_handle().await?; { let tx = conn.transaction().await?; tx.execute("INSERT INTO foo VALUES(?)", &[1]).await?; + tx.finish().await?; // default: rollback } { let mut tx = conn.transaction().await?; tx.execute("INSERT INTO foo VALUES(?)", &[2]).await?; - tx.set_drop_behavior(DropBehavior::Commit) + tx.set_drop_behavior(DropBehavior::Commit); + tx.finish().await?; } { let tx = conn.transaction().await?; @@ -325,6 +337,87 @@ mod test { .as_integer() .unwrap() ); + tx.finish().await?; + } + Ok(()) + } + + fn assert_nested_tx_error(e: Error) { + if let Error::SqlExecutionFailure(e) = &e { + assert!(e.contains("transaction")); + } else { + panic!("Unexpected error type: {e:?}"); + } + } + + #[tokio::test] + async fn test_unchecked_nesting() -> Result<()> { + let conn = checked_memory_handle().await?; + + { + let tx = conn.unchecked_transaction().await?; + let e = tx.unchecked_transaction().await.unwrap_err(); + assert_nested_tx_error(e); + tx.finish().await?; + // default: rollback + } + { + let tx = conn.unchecked_transaction().await?; + tx.execute("INSERT INTO foo VALUES(?)", &[1]).await?; + // Ensure this doesn't interfere with ongoing transaction + let e = tx.unchecked_transaction().await.unwrap_err(); + assert_nested_tx_error(e); + + tx.execute("INSERT INTO foo VALUES(?)", &[1]).await?; + tx.commit().await?; + } + + let mut result = conn.query("SELECT SUM(x) FROM foo", ()).await?; + assert_eq!( + 2, + *result + .next() + .await? + .unwrap() + .get_value(0)? + .as_integer() + .unwrap() + ); + Ok(()) + } + + #[tokio::test] + async fn test_explicit_rollback_commit() -> Result<()> { + let mut conn = checked_memory_handle().await?; + { + let tx = conn.transaction().await?; + tx.execute("INSERT INTO foo VALUES(?)", &[1]).await?; + tx.rollback().await?; + + // This is a current Turso's limitation. + // Since we don't have support for savepoints yet, + // a rollback ends with a transaction so we need to immediately open a new one. + let tx = conn.transaction().await?; + tx.execute("INSERT INTO foo VALUES(?)", &[2]).await?; + tx.commit().await?; + } + { + let tx = conn.transaction().await?; + tx.execute("INSERT INTO foo VALUES(?)", &[4]).await?; + tx.commit().await?; + } + { + let mut result = conn.query("SELECT SUM(x) FROM foo", ()).await?; + assert_eq!( + 2, + *result + .next() + .await? + .unwrap() + .get_value(0)? + .as_integer() + .unwrap() + ); } Ok(()) }