Skip to main content

rorm_db/internal/
executor.rs

1use std::future;
2use std::future::ready;
3use std::pin::Pin;
4use std::task::{ready, Context, Poll};
5
6use futures_core::stream;
7use rorm_sql::value::Value;
8use rorm_sql::DBImpl;
9use sqlx::{AssertSqlSafe, SqlSafeStr, SqlStr};
10use tracing::debug;
11
12use crate::executor::{
13    AffectedRows, All, DynamicExecutor, Executor, Nothing, One, Optional, QueryStrategy,
14    QueryStrategyResult, Stream,
15};
16use crate::futures_util::{BoxFuture, BoxStream};
17use crate::internal::any::{AnyExecutor, AnyPool, AnyQueryResult, AnyRow};
18use crate::internal::bind_params::bind_param;
19use crate::transaction::{MaybeOwnedTransaction, Transaction};
20use crate::{Database, Error, Row};
21
22impl<'exe> Executor<'exe> for &'exe mut Transaction {
23    fn execute<Q>(self, query: String, values: Vec<Value<'_>>) -> Q::Result<'exe>
24    where
25        Q: QueryStrategy,
26    {
27        debug!(
28            target: "rorm_db::executor",
29            sql = query,
30            values.len = values.len(),
31            "Executing statement"
32        );
33        Q::execute(&mut self.sqlx, AssertSqlSafe(query).into_sql_str(), values)
34    }
35
36    fn into_dyn(self) -> DynamicExecutor<'exe> {
37        DynamicExecutor::Transaction(self)
38    }
39
40    fn dialect(&self) -> DBImpl {
41        Transaction::dialect(self)
42    }
43
44    fn ensure_transaction(self) -> BoxFuture<'exe, Result<MaybeOwnedTransaction<'exe>, Error>> {
45        Box::pin(ready(Ok(MaybeOwnedTransaction::Borrowed(self))))
46    }
47}
48
49impl<'exe> Executor<'exe> for &'exe Database {
50    fn execute<Q>(self, query: String, values: Vec<Value<'_>>) -> Q::Result<'exe>
51    where
52        Q: QueryStrategy,
53    {
54        debug!(
55            target: "rorm_db::executor",
56            sql = query,
57            values.len = values.len(),
58            "Executing statement"
59        );
60        Q::execute(&self.0, AssertSqlSafe(query).into_sql_str(), values)
61    }
62
63    fn into_dyn(self) -> DynamicExecutor<'exe> {
64        DynamicExecutor::Database(self)
65    }
66
67    fn dialect(&self) -> DBImpl {
68        match self.0 {
69            #[cfg(feature = "postgres")]
70            AnyPool::Postgres(_) => DBImpl::Postgres,
71            #[cfg(feature = "sqlite")]
72            AnyPool::Sqlite(_) => DBImpl::SQLite,
73        }
74    }
75
76    fn ensure_transaction(self) -> BoxFuture<'exe, Result<MaybeOwnedTransaction<'exe>, Error>> {
77        Box::pin(async move {
78            self.start_transaction()
79                .await
80                .map(MaybeOwnedTransaction::Owned)
81        })
82    }
83}
84
85pub trait QueryStrategyImpl: QueryStrategyResult {
86    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
87    where
88        E: AnyExecutor<'exe>;
89}
90
91impl QueryStrategyResult for Nothing {
92    type Result<'query> = NothingFuture<'query>;
93}
94
95impl QueryStrategyImpl for Nothing {
96    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
97    where
98        E: AnyExecutor<'exe>,
99    {
100        let mut query = executor.query(query);
101        for x in values {
102            bind_param(&mut query, x);
103        }
104        NothingFuture {
105            stream: query.fetch_many(),
106        }
107    }
108}
109
110/// [`QueryStrategyResult::Result`] of [`Nothing`]
111pub struct NothingFuture<'stream> {
112    stream: BoxStream<'stream, sqlx::Result<sqlx::Either<AnyQueryResult, AnyRow>>>,
113}
114
115impl future::Future for NothingFuture<'_> {
116    type Output = Result<(), Error>;
117
118    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
119        loop {
120            return Poll::Ready(match ready!(self.stream.as_mut().poll_next(cx)) {
121                None => Ok(()),
122                Some(Err(error)) => Err(error.into()),
123                Some(_either) => continue,
124            });
125        }
126    }
127}
128
129impl QueryStrategyResult for AffectedRows {
130    type Result<'query> = BoxFuture<'query, Result<u64, Error>>;
131}
132
133impl QueryStrategyImpl for AffectedRows {
134    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
135    where
136        E: AnyExecutor<'exe>,
137    {
138        let mut query = executor.query(query);
139        for x in values {
140            bind_param(&mut query, x);
141        }
142        Box::pin(async move { Ok(query.fetch_affected_rows().await?) }) as BoxFuture<_>
143    }
144}
145
146impl QueryStrategyResult for One {
147    type Result<'query> = BoxFuture<'query, Result<Row, Error>>;
148}
149
150impl QueryStrategyImpl for One {
151    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
152    where
153        E: AnyExecutor<'exe>,
154    {
155        let mut query = executor.query(query);
156        for x in values {
157            bind_param(&mut query, x);
158        }
159        Box::pin(async move {
160            Ok(Row(query
161                .fetch_optional()
162                .await?
163                .ok_or(sqlx::Error::RowNotFound)?))
164        }) as BoxFuture<_>
165    }
166}
167
168impl QueryStrategyResult for Optional {
169    type Result<'query> = BoxFuture<'query, Result<Option<Row>, Error>>;
170}
171
172impl QueryStrategyImpl for Optional {
173    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
174    where
175        E: AnyExecutor<'exe>,
176    {
177        let mut query = executor.query(query);
178        for x in values {
179            bind_param(&mut query, x);
180        }
181        Box::pin(async move { Ok(query.fetch_optional().await?.map(Row)) }) as BoxFuture<_>
182    }
183}
184
185impl QueryStrategyResult for All {
186    type Result<'query> = BoxFuture<'query, Result<Vec<Row>, Error>>;
187}
188
189impl QueryStrategyImpl for All {
190    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
191    where
192        E: AnyExecutor<'exe>,
193    {
194        let mut query = executor.query(query);
195        for x in values {
196            bind_param(&mut query, x);
197        }
198        Box::pin(async move { Ok(query.fetch_all().await?.into_iter().map(Row).collect()) })
199            as BoxFuture<_>
200    }
201}
202
203impl QueryStrategyResult for Stream {
204    type Result<'query> = StreamResult<'query>;
205}
206
207impl QueryStrategyImpl for Stream {
208    fn execute<'exe, E>(executor: E, query: SqlStr, values: Vec<Value<'_>>) -> Self::Result<'exe>
209    where
210        E: AnyExecutor<'exe>,
211    {
212        let mut query = executor.query(query);
213        for x in values {
214            bind_param(&mut query, x);
215        }
216        StreamResult {
217            stream: query.fetch_many(),
218        }
219    }
220}
221
222/// [`QueryStrategyResult::Result`] of [`Stream`]
223pub struct StreamResult<'stream> {
224    stream: BoxStream<'stream, sqlx::Result<sqlx::Either<AnyQueryResult, AnyRow>>>,
225}
226
227impl Unpin for StreamResult<'_> {}
228impl stream::Stream for StreamResult<'_> {
229    type Item = Result<Row, Error>;
230
231    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
232        loop {
233            return Poll::Ready(match ready!(self.stream.as_mut().poll_next(cx)) {
234                None => None,
235                Some(Err(error)) => Some(Err(error.into())),
236                Some(Ok(sqlx::Either::Right(row))) => Some(Ok(Row(row))),
237                Some(Ok(sqlx::Either::Left(_result))) => continue,
238            });
239        }
240    }
241}