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
110pub 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
222pub 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}