sql_middleware/sqlite/
transaction.rs1use std::sync::Arc;
2
3use crate::middleware::{
4 ConversionMode, ParamConverter, ResultSet, RowValues, SqlMiddlewareDbError,
5};
6use crate::pool::MiddlewarePoolConnection;
7use crate::tx_outcome::TxOutcome;
8
9use super::connection::SqliteConnection;
10use super::params::Params;
11
12pub struct Tx {
14 conn: Option<SqliteConnection>,
15 translate_placeholders: bool,
16}
17
18pub struct Prepared {
20 sql: Arc<String>,
21}
22
23pub async fn begin_transaction(
31 mut conn: SqliteConnection,
32 translate_placeholders: bool,
33) -> Result<Tx, SqlMiddlewareDbError> {
34 conn.begin().await?;
35 Ok(Tx {
36 conn: Some(conn),
37 translate_placeholders,
38 })
39}
40
41impl Tx {
42 fn conn_mut(&mut self) -> Result<&mut SqliteConnection, SqlMiddlewareDbError> {
43 self.conn.as_mut().ok_or_else(|| {
44 SqlMiddlewareDbError::ExecutionError("SQLite transaction already completed".into())
45 })
46 }
47
48 pub fn prepare(&self, sql: &str) -> Result<Prepared, SqlMiddlewareDbError> {
53 if self.conn.is_none() {
54 return Err(SqlMiddlewareDbError::ExecutionError(
55 "SQLite transaction already completed".into(),
56 ));
57 }
58 Ok(Prepared {
59 sql: Arc::new(sql.to_owned()),
60 })
61 }
62
63 pub async fn execute_prepared(
68 &mut self,
69 prepared: &Prepared,
70 params: &[RowValues],
71 ) -> Result<usize, SqlMiddlewareDbError> {
72 let converted =
73 <Params as ParamConverter>::convert_sql_params(params, ConversionMode::Execute)?;
74 let conn = self.conn_mut()?;
75 conn.execute_dml_in_tx(prepared.sql.as_ref(), &converted.0)
76 .await
77 }
78
79 pub async fn query_prepared(
84 &mut self,
85 prepared: &Prepared,
86 params: &[RowValues],
87 ) -> Result<ResultSet, SqlMiddlewareDbError> {
88 let converted =
89 <Params as ParamConverter>::convert_sql_params(params, ConversionMode::Query)?;
90 let conn = self.conn_mut()?;
91 conn.execute_select_in_tx(
92 prepared.sql.as_ref(),
93 &converted.0,
94 super::query::build_result_set,
95 )
96 .await
97 }
98
99 pub async fn execute_batch(&mut self, sql: &str) -> Result<(), SqlMiddlewareDbError> {
104 let conn = self.conn_mut()?;
105 conn.execute_batch_in_tx(sql).await
106 }
107
108 pub async fn commit(mut self) -> Result<TxOutcome, SqlMiddlewareDbError> {
116 let mut conn = self.conn.take().ok_or_else(|| {
117 SqlMiddlewareDbError::ExecutionError("SQLite transaction already completed".into())
118 })?;
119 conn.commit().await?;
120 let restored =
121 MiddlewarePoolConnection::from_sqlite_parts(conn, self.translate_placeholders);
122 Ok(TxOutcome::with_restored_connection(restored))
123 }
124
125 pub async fn rollback(mut self) -> Result<TxOutcome, SqlMiddlewareDbError> {
133 let mut conn = self.conn.take().ok_or_else(|| {
134 SqlMiddlewareDbError::ExecutionError("SQLite transaction already completed".into())
135 })?;
136 conn.rollback().await?;
137 let restored =
138 MiddlewarePoolConnection::from_sqlite_parts(conn, self.translate_placeholders);
139 Ok(TxOutcome::with_restored_connection(restored))
140 }
141}
142
143impl Drop for Tx {
144 fn drop(&mut self) {
145 if let Some(mut conn) = self.conn.take()
146 && let Ok(handle) = tokio::runtime::Handle::try_current()
147 {
148 handle.spawn(async move {
149 let _ = conn.rollback().await;
150 });
151 }
152 }
153}