Skip to main content

sql_middleware/sqlite/connection/
dml.rs

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