sql_middleware/sqlite/connection/
dml.rs

1use std::sync::Arc;
2
3use crate::middleware::SqlMiddlewareDbError;
4use crate::types::RowValues;
5
6use super::{SqliteConnection, run_blocking};
7use crate::sqlite::config::SqliteManager;
8use crate::sqlite::params::Params;
9use bb8::PooledConnection;
10
11impl SqliteConnection {
12    /// Execute a batch of statements; wraps in a transaction when not already inside one.
13    ///
14    /// # Errors
15    /// Returns `SqlMiddlewareDbError` if acquiring the `SQLite` guard or executing the batch fails.
16    pub async fn execute_batch(&mut self, query: &str) -> Result<(), SqlMiddlewareDbError> {
17        self.ensure_not_in_tx("execute batch")?;
18        let sql_owned = query.to_owned();
19        run_blocking(self.conn_handle(), move |guard| {
20            if guard.is_autocommit() {
21                let tx = guard
22                    .transaction()
23                    .map_err(SqlMiddlewareDbError::SqliteError)?;
24                tx.execute_batch(&sql_owned)
25                    .map_err(SqlMiddlewareDbError::SqliteError)?;
26                tx.commit().map_err(SqlMiddlewareDbError::SqliteError)
27            } else {
28                guard
29                    .execute_batch(&sql_owned)
30                    .map_err(SqlMiddlewareDbError::SqliteError)
31            }
32        })
33        .await
34    }
35
36    /// Execute a DML statement and return rows affected.
37    ///
38    /// # Errors
39    /// Returns `SqlMiddlewareDbError` if preparing or executing the statement fails.
40    pub async fn execute_dml(
41        &mut self,
42        query: &str,
43        params: &[rusqlite::types::Value],
44    ) -> Result<usize, SqlMiddlewareDbError> {
45        self.ensure_not_in_tx("execute dml")?;
46        let sql_owned = query.to_owned();
47        let params_owned = params.to_vec();
48        run_blocking(self.conn_handle(), move |guard| {
49            let mut stmt = guard
50                .prepare_cached(&sql_owned)
51                .map_err(SqlMiddlewareDbError::SqliteError)?;
52            let refs: Vec<&dyn rusqlite::ToSql> = params_owned
53                .iter()
54                .map(|v| v as &dyn rusqlite::ToSql)
55                .collect();
56            let affected = stmt
57                .execute(&refs[..])
58                .map_err(SqlMiddlewareDbError::SqliteError)?;
59            Ok(affected)
60        })
61        .await
62    }
63
64    /// Execute a DML statement inside an open transaction.
65    ///
66    /// # Errors
67    /// Returns `SqlMiddlewareDbError` if the guard fails or the transaction is not active.
68    pub async fn execute_dml_in_tx(
69        &mut self,
70        query: &str,
71        params: &[rusqlite::types::Value],
72    ) -> Result<usize, SqlMiddlewareDbError> {
73        if !self.in_transaction {
74            return Err(SqlMiddlewareDbError::ExecutionError(
75                "SQLite transaction not active".into(),
76            ));
77        }
78        let sql_owned = query.to_owned();
79        let params_owned = params.to_vec();
80        run_blocking(self.conn_handle(), move |guard| {
81            let mut stmt = guard
82                .prepare_cached(&sql_owned)
83                .map_err(SqlMiddlewareDbError::SqliteError)?;
84            let refs: Vec<&dyn rusqlite::ToSql> = params_owned
85                .iter()
86                .map(|v| v as &dyn rusqlite::ToSql)
87                .collect();
88            let affected = stmt
89                .execute(&refs[..])
90                .map_err(SqlMiddlewareDbError::SqliteError)?;
91            Ok(affected)
92        })
93        .await
94    }
95
96    /// Execute a batch inside an open transaction without implicit commit.
97    ///
98    /// # Errors
99    /// Returns `SqlMiddlewareDbError` if the guard fails or the transaction is not active.
100    pub async fn execute_batch_in_tx(&mut self, sql: &str) -> Result<(), SqlMiddlewareDbError> {
101        if !self.in_transaction {
102            return Err(SqlMiddlewareDbError::ExecutionError(
103                "SQLite transaction not active".into(),
104            ));
105        }
106        let sql_owned = sql.to_owned();
107        run_blocking(self.conn_handle(), move |guard| {
108            guard
109                .execute_batch(&sql_owned)
110                .map_err(SqlMiddlewareDbError::SqliteError)
111        })
112        .await
113    }
114}
115
116/// Adapter for query builder dml (typed-sqlite target).
117///
118/// # Errors
119/// Returns `SqlMiddlewareDbError` if converting parameters or executing the statement fails.
120pub async fn dml(
121    conn: &mut PooledConnection<'static, SqliteManager>,
122    query: &str,
123    params: &[RowValues],
124) -> Result<usize, SqlMiddlewareDbError> {
125    let converted = Params::convert(params)?.0;
126    let sql_owned = query.to_owned();
127    let params_owned = converted.clone();
128    let handle = Arc::clone(&*conn);
129    run_blocking(handle, move |guard| {
130        let mut stmt = guard
131            .prepare_cached(&sql_owned)
132            .map_err(SqlMiddlewareDbError::SqliteError)?;
133        let refs: Vec<&dyn rusqlite::ToSql> = params_owned
134            .iter()
135            .map(|v| v as &dyn rusqlite::ToSql)
136            .collect();
137        let affected = stmt
138            .execute(&refs[..])
139            .map_err(SqlMiddlewareDbError::SqliteError)?;
140        Ok(affected)
141    })
142    .await
143}