Skip to main content

sql_middleware/query_builder/
dml.rs

1use crate::error::SqlMiddlewareDbError;
2use crate::executor::{
3    QueryTarget, QueryTargetKind, execute_dml_dispatch, execute_dml_prepared_dispatch,
4};
5use crate::pool::MiddlewarePoolConnection;
6use crate::translation::PrepareMode;
7use crate::types::{RowValues, StatementCacheMode};
8
9#[cfg(feature = "postgres")]
10use crate::postgres::typed::PgManager;
11#[cfg(feature = "sqlite")]
12use crate::sqlite::config::SqliteManager;
13#[cfg(feature = "mssql")]
14use crate::typed_mssql::MssqlManager;
15#[cfg(feature = "turso")]
16use crate::typed_turso::TursoManager;
17#[cfg(any(
18    feature = "postgres",
19    feature = "sqlite",
20    feature = "turso",
21    feature = "mssql"
22))]
23use bb8::PooledConnection;
24
25use super::{QueryBuilder, translate_query_for_target};
26
27impl QueryBuilder<'_, '_> {
28    /// Execute a DML statement and return rows affected.
29    ///
30    /// # Errors
31    /// Returns an error if placeholder translation fails or the backend DML execution fails.
32    pub async fn dml(self) -> Result<usize, SqlMiddlewareDbError> {
33        let translated = translate_query_for_target(
34            &self.target,
35            self.sql.as_ref(),
36            self.params.as_ref(),
37            self.options,
38        );
39        let use_prepare = matches!(self.options.prepare, PrepareMode::Prepared);
40        let statement_cache_mode = self
41            .options
42            .statement_cache
43            .unwrap_or(self.target.statement_cache_mode);
44
45        match self.target {
46            QueryTarget {
47                kind: QueryTargetKind::Connection(conn),
48                ..
49            } => {
50                dml_on_connection(
51                    conn,
52                    translated.as_ref(),
53                    self.params.as_ref(),
54                    use_prepare,
55                    statement_cache_mode,
56                )
57                .await
58            }
59            #[cfg(feature = "sqlite")]
60            QueryTarget {
61                kind:
62                    QueryTargetKind::TypedSqlite { conn } | QueryTargetKind::TypedSqliteTx { conn },
63                ..
64            } => {
65                dml_typed_sqlite(
66                    conn,
67                    translated.as_ref(),
68                    self.params.as_ref(),
69                    statement_cache_mode,
70                )
71                .await
72            }
73            #[cfg(feature = "postgres")]
74            QueryTarget {
75                kind:
76                    QueryTargetKind::TypedPostgres { conn } | QueryTargetKind::TypedPostgresTx { conn },
77                ..
78            } => {
79                dml_typed_postgres(conn, translated.as_ref(), self.params.as_ref(), use_prepare)
80                    .await
81            }
82            #[cfg(feature = "turso")]
83            QueryTarget {
84                kind: QueryTargetKind::TypedTurso { conn } | QueryTargetKind::TypedTursoTx { conn },
85                ..
86            } => {
87                dml_typed_turso(
88                    conn,
89                    translated.as_ref(),
90                    self.params.as_ref(),
91                    statement_cache_mode,
92                )
93                .await
94            }
95            #[cfg(feature = "mssql")]
96            QueryTarget {
97                kind: QueryTargetKind::TypedMssql { conn } | QueryTargetKind::TypedMssqlTx { conn },
98                ..
99            } => dml_typed_mssql(conn, translated.as_ref(), self.params.as_ref()).await,
100            #[cfg(feature = "postgres")]
101            QueryTarget {
102                kind: QueryTargetKind::PostgresTx(tx),
103                ..
104            } => {
105                if use_prepare {
106                    let prepared = tx.prepare(translated.as_ref()).await?;
107                    tx.execute(&prepared)
108                        .params(self.params.as_ref())
109                        .run()
110                        .await
111                } else {
112                    tx.execute_dml(translated.as_ref(), self.params.as_ref())
113                        .await
114                }
115            }
116            #[cfg(feature = "mssql")]
117            QueryTarget {
118                kind: QueryTargetKind::MssqlTx(tx),
119                ..
120            } => {
121                if use_prepare {
122                    let prepared = tx.prepare(translated.as_ref())?;
123                    tx.execute(&prepared)
124                        .params(self.params.as_ref())
125                        .run()
126                        .await
127                } else {
128                    tx.execute_dml(translated.as_ref(), self.params.as_ref())
129                        .await
130                }
131            }
132            #[cfg(feature = "turso")]
133            QueryTarget {
134                kind: QueryTargetKind::TursoTx(tx),
135                ..
136            } => {
137                if use_prepare {
138                    let mut prepared = tx.prepare(translated.as_ref()).await?;
139                    tx.execute(&mut prepared)
140                        .params(self.params.as_ref())
141                        .run()
142                        .await
143                } else {
144                    tx.execute_dml(translated.as_ref(), self.params.as_ref())
145                        .await
146                }
147            }
148        }
149    }
150}
151
152async fn dml_on_connection(
153    conn: &mut MiddlewarePoolConnection,
154    query: &str,
155    params: &[RowValues],
156    use_prepare: bool,
157    statement_cache_mode: StatementCacheMode,
158) -> Result<usize, SqlMiddlewareDbError> {
159    if use_prepare {
160        execute_dml_prepared_dispatch(conn, query, params, statement_cache_mode).await
161    } else {
162        execute_dml_dispatch(conn, query, params, statement_cache_mode).await
163    }
164}
165
166#[cfg(feature = "sqlite")]
167async fn dml_typed_sqlite(
168    conn: &mut PooledConnection<'static, SqliteManager>,
169    query: &str,
170    params: &[RowValues],
171    statement_cache_mode: StatementCacheMode,
172) -> Result<usize, SqlMiddlewareDbError> {
173    crate::sqlite::connection::dml_with_cache_mode(conn, query, params, statement_cache_mode).await
174}
175
176#[cfg(feature = "postgres")]
177async fn dml_typed_postgres(
178    conn: &mut PooledConnection<'static, PgManager>,
179    query: &str,
180    params: &[RowValues],
181    use_prepare: bool,
182) -> Result<usize, SqlMiddlewareDbError> {
183    if use_prepare {
184        crate::typed_postgres::dml_prepared(conn, query, params).await
185    } else {
186        crate::typed_postgres::dml(conn, query, params).await
187    }
188}
189
190#[cfg(feature = "turso")]
191async fn dml_typed_turso(
192    conn: &mut PooledConnection<'static, TursoManager>,
193    query: &str,
194    params: &[RowValues],
195    _statement_cache_mode: StatementCacheMode,
196) -> Result<usize, SqlMiddlewareDbError> {
197    crate::typed_turso::dml(conn, query, params).await
198}
199
200#[cfg(feature = "mssql")]
201async fn dml_typed_mssql(
202    conn: &mut PooledConnection<'static, MssqlManager>,
203    query: &str,
204    params: &[RowValues],
205) -> Result<usize, SqlMiddlewareDbError> {
206    crate::typed_mssql::dml(conn, query, params).await
207}