1use std::future::Future;
4
5use futures::TryStreamExt;
6use sqlx::Row as _;
7use sqlx::any::AnyQueryResult;
8use sqlx::{
9 Arguments, ColumnIndex, Database, Decode, Encode, Error, Executor, IntoArguments, SqlStr, Type,
10};
11
12use super::engine::{Claimed, Events, IdAt, undecodable};
13use super::form::advisory::events::Candidates;
14use super::queue::Queue;
15
16#[cfg(feature = "any")]
17mod any;
18pub(crate) mod built_in;
19mod insert;
20pub(crate) mod notify;
21
22#[cfg(feature = "any")]
23pub use any::AnyDialect;
24pub use built_in::{BuiltIn, BuiltInDialect};
25pub use insert::{InsertSql, OnConnection, no_insert};
26pub use notify::Notifies;
27
28pub trait QueueDatabase: Database {
81 #[doc(hidden)]
83 fn bind_str(arguments: &mut Self::Arguments, value: &str) -> Result<(), Error>;
84
85 #[doc(hidden)]
87 fn bind_i64(arguments: &mut Self::Arguments, value: i64) -> Result<(), Error>;
88
89 #[doc(hidden)]
91 fn execute<'c>(
92 conn: &'c mut Self::Connection,
93 sql: &'static str,
94 arguments: Self::Arguments,
95 ) -> impl Future<Output = Result<u64, Error>> + Send + 'c;
96
97 #[doc(hidden)]
100 fn execute_text<'c>(
101 conn: &'c mut Self::Connection,
102 sql: &'static str,
103 ) -> impl Future<Output = Result<(), Error>> + Send + 'c;
104
105 #[doc(hidden)]
109 fn fetch_rows<'c, Row>(
110 conn: &'c mut Self::Connection,
111 sql: &'static str,
112 arguments: Self::Arguments,
113 queue: &'static Queue,
114 out: &'c mut Vec<Claimed<Row>>,
115 ) -> impl Future<Output = Result<(), Error>> + Send + 'c
116 where
117 Row: Events<Self>,
118 Row::Id: for<'r> Decode<'r, Self> + Type<Self>;
119
120 #[doc(hidden)]
122 fn column<T>(row: &Self::Row, name: &str) -> Result<T, Error>
123 where
124 T: for<'r> Decode<'r, Self> + Type<Self>;
125
126 #[doc(hidden)]
128 fn fetch_ids<'c, Id>(
129 conn: &'c mut Self::Connection,
130 sql: &'static str,
131 arguments: Self::Arguments,
132 out: &'c mut Vec<Id>,
133 ) -> impl Future<Output = Result<(), Error>> + Send + 'c
134 where
135 Id: for<'r> Decode<'r, Self> + Type<Self> + Send + Unpin + 'c;
136
137 #[doc(hidden)]
139 fn prepare<'c>(
140 conn: &'c mut Self::Connection,
141 sql: &'static str,
142 ) -> impl Future<Output = Result<(), Error>> + Send + 'c;
143
144 #[doc(hidden)]
147 fn fetch_text<'c>(
148 conn: &'c mut Self::Connection,
149 sql: &'static str,
150 ) -> impl Future<Output = Result<String, Error>> + Send + 'c;
151
152 #[doc(hidden)]
156 fn fetch_flag<'c>(
157 conn: &'c mut Self::Connection,
158 sql: &'static str,
159 arguments: Self::Arguments,
160 ) -> impl Future<Output = Result<bool, Error>> + Send + 'c;
161
162 #[doc(hidden)]
165 fn fetch_count<'c>(
166 conn: &'c mut Self::Connection,
167 sql: &'static str,
168 arguments: Self::Arguments,
169 ) -> impl Future<Output = Result<i64, Error>> + Send + 'c;
170
171 #[doc(hidden)]
174 fn fetch_candidates<'c, Id>(
175 conn: &'c mut Self::Connection,
176 sql: &'static str,
177 arguments: Self::Arguments,
178 out: &'c mut Candidates<Id>,
179 ) -> impl Future<Output = Result<(), Error>> + Send + 'c
180 where
181 Id: for<'r> Decode<'r, Self> + Type<Self> + Send + 'c;
182
183 #[doc(hidden)]
186 fn fetch_found<'c>(
187 conn: &'c mut Self::Connection,
188 sql: &'static str,
189 arguments: Self::Arguments,
190 ) -> impl Future<Output = Result<bool, Error>> + Send + 'c;
191}
192
193impl<DB> QueueDatabase for DB
194where
195 DB: Database,
196 for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,
197 DB::Arguments: IntoArguments<DB>,
198 for<'q> &'q str: Encode<'q, DB> + Type<DB>,
199 for<'r> &'r str: Decode<'r, DB> + ColumnIndex<DB::Row>,
200 for<'a> i64: Encode<'a, DB> + Decode<'a, DB> + Type<DB>,
201 for<'r> String: Decode<'r, DB> + Type<DB>,
202 usize: ColumnIndex<DB::Row>,
203 DB::QueryResult: Into<AnyQueryResult>,
204{
205 fn bind_str(arguments: &mut Self::Arguments, value: &str) -> Result<(), Error> {
206 arguments.add(value).map_err(Error::Encode)
207 }
208
209 fn bind_i64(arguments: &mut Self::Arguments, value: i64) -> Result<(), Error> {
210 arguments.add(value).map_err(Error::Encode)
211 }
212
213 async fn execute(
214 conn: &mut Self::Connection,
215 sql: &'static str,
216 arguments: Self::Arguments,
217 ) -> Result<u64, Error> {
218 let result: AnyQueryResult = sqlx::query_with(sql, arguments).execute(conn).await?.into();
219 Ok(result.rows_affected())
220 }
221
222 async fn execute_text(conn: &mut Self::Connection, sql: &'static str) -> Result<(), Error> {
223 conn.execute(sql).await?;
225 Ok(())
226 }
227
228 async fn fetch_rows<'c, Row>(
229 conn: &'c mut Self::Connection,
230 sql: &'static str,
231 arguments: Self::Arguments,
232 queue: &'static Queue,
233 out: &'c mut Vec<Claimed<Row>>,
234 ) -> Result<(), Error>
235 where
236 Row: Events<Self>,
237 Row::Id: for<'r> Decode<'r, Self> + Type<Self>,
238 {
239 let mut rows = sqlx::query_with::<Self, _>(sql, arguments).fetch(conn);
241 while let Some(raw) = rows.try_next().await? {
242 match Row::from_row(&raw) {
243 Ok(row) => out.push(Claimed::Row(row)),
244 Err(error) => {
245 let id = match queue.id_at {
249 IdAt::First => raw.try_get::<Row::Id, _>(0_usize),
250 IdAt::Named(name) => raw.try_get::<Row::Id, _>(name),
251 };
252 match id {
253 Ok(id) => out.push(Claimed::Undecodable {
254 id,
255 attempt: Row::read_attempt(&raw, queue),
256 error: Box::new(undecodable(error)),
257 }),
258 Err(_) => return Err(error),
259 }
260 }
261 }
262 }
263 Ok(())
264 }
265
266 fn column<T>(row: &Self::Row, name: &str) -> Result<T, Error>
267 where
268 T: for<'r> Decode<'r, Self> + Type<Self>,
269 {
270 row.try_get::<T, _>(name)
271 }
272
273 async fn fetch_ids<'c, Id>(
274 conn: &'c mut Self::Connection,
275 sql: &'static str,
276 arguments: Self::Arguments,
277 out: &'c mut Vec<Id>,
278 ) -> Result<(), Error>
279 where
280 Id: for<'r> Decode<'r, Self> + Type<Self> + Send + Unpin + 'c,
281 {
282 let mut rows = sqlx::query_with::<Self, _>(sql, arguments).fetch(conn);
286 while let Some(row) = rows.try_next().await? {
287 out.push(row.try_get::<Id, _>(0_usize)?);
288 }
289 Ok(())
290 }
291
292 async fn prepare(conn: &mut Self::Connection, sql: &'static str) -> Result<(), Error> {
293 conn.prepare(SqlStr::from_static(sql)).await?;
294 Ok(())
295 }
296
297 fn fetch_text<'c>(
298 conn: &'c mut Self::Connection,
299 sql: &'static str,
300 ) -> impl Future<Output = Result<String, Error>> + Send + 'c {
301 sqlx::query_scalar::<Self, String>(sql).fetch_one(conn)
302 }
303
304 async fn fetch_flag(
305 conn: &mut Self::Connection,
306 sql: &'static str,
307 arguments: Self::Arguments,
308 ) -> Result<bool, Error> {
309 let flag: i64 = sqlx::query_scalar_with::<Self, i64, _>(sql, arguments)
310 .fetch_one(conn)
311 .await?;
312 Ok(flag != 0)
313 }
314
315 fn fetch_count<'c>(
316 conn: &'c mut Self::Connection,
317 sql: &'static str,
318 arguments: Self::Arguments,
319 ) -> impl Future<Output = Result<i64, Error>> + Send + 'c {
320 sqlx::query_scalar_with::<Self, i64, _>(sql, arguments).fetch_one(conn)
321 }
322
323 async fn fetch_candidates<'c, Id>(
324 conn: &'c mut Self::Connection,
325 sql: &'static str,
326 arguments: Self::Arguments,
327 out: &'c mut Candidates<Id>,
328 ) -> Result<(), Error>
329 where
330 Id: for<'r> Decode<'r, Self> + Type<Self> + Send + 'c,
331 {
332 let mut rows = sqlx::query_with::<Self, _>(sql, arguments).fetch(conn);
333 while let Some(row) = rows.try_next().await? {
334 let key = row.try_get::<&str, _>(1_usize)?;
336 out.push(row.try_get::<Id, _>(0_usize)?, key);
337 }
338 Ok(())
339 }
340
341 async fn fetch_found(
342 conn: &mut Self::Connection,
343 sql: &'static str,
344 arguments: Self::Arguments,
345 ) -> Result<bool, Error> {
346 let mut rows = sqlx::query_with::<Self, _>(sql, arguments).fetch(conn);
348 let mut found = false;
349 while rows.try_next().await?.is_some() {
350 found = true;
351 }
352 Ok(found)
353 }
354}