diesel_async/run_query_dsl/
mod.rs

1use crate::AsyncConnection;
2use diesel::associations::HasTable;
3use diesel::query_builder::IntoUpdateTarget;
4use diesel::result::QueryResult;
5use diesel::AsChangeset;
6use futures_core::future::BoxFuture;
7use futures_core::Stream;
8use futures_util::{future, stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
9use std::future::Future;
10use std::pin::Pin;
11
12/// The traits used by `QueryDsl`.
13///
14/// Each trait in this module represents exactly one method from [`RunQueryDsl`].
15/// Apps should general rely on [`RunQueryDsl`] directly, rather than these traits.
16/// However, generic code may need to include a where clause that references
17/// these traits.
18pub mod methods {
19    use super::*;
20    use diesel::backend::Backend;
21    use diesel::deserialize::FromSqlRow;
22    use diesel::expression::QueryMetadata;
23    use diesel::query_builder::{AsQuery, QueryFragment, QueryId};
24    use diesel::query_dsl::CompatibleType;
25    use futures_util::{Future, Stream, TryFutureExt};
26
27    /// The `execute` method
28    ///
29    /// This trait should not be relied on directly by most apps. Its behavior is
30    /// provided by [`RunQueryDsl`]. However, you may need a where clause on this trait
31    /// to call `execute` from generic code.
32    ///
33    /// [`RunQueryDsl`]: super::RunQueryDsl
34    pub trait ExecuteDsl<Conn, DB = <Conn as AsyncConnection>::Backend>
35    where
36        Conn: AsyncConnection<Backend = DB>,
37        DB: Backend,
38    {
39        /// Execute this command
40        fn execute<'conn, 'query>(
41            query: Self,
42            conn: &'conn mut Conn,
43        ) -> Conn::ExecuteFuture<'conn, 'query>
44        where
45            Self: 'query;
46    }
47
48    impl<Conn, DB, T> ExecuteDsl<Conn, DB> for T
49    where
50        Conn: AsyncConnection<Backend = DB>,
51        DB: Backend,
52        T: QueryFragment<DB> + QueryId + Send,
53    {
54        fn execute<'conn, 'query>(
55            query: Self,
56            conn: &'conn mut Conn,
57        ) -> Conn::ExecuteFuture<'conn, 'query>
58        where
59            Self: 'query,
60        {
61            conn.execute_returning_count(query)
62        }
63    }
64
65    /// The `load` method
66    ///
67    /// This trait should not be relied on directly by most apps. Its behavior is
68    /// provided by [`RunQueryDsl`]. However, you may need a where clause on this trait
69    /// to call `load` from generic code.
70    ///
71    /// [`RunQueryDsl`]: super::RunQueryDsl
72    pub trait LoadQuery<'query, Conn: AsyncConnection, U> {
73        /// The future returned by [`LoadQuery::internal_load`]
74        type LoadFuture<'conn>: Future<Output = QueryResult<Self::Stream<'conn>>> + Send
75        where
76            Conn: 'conn;
77        /// The inner stream returned by [`LoadQuery::internal_load`]
78        type Stream<'conn>: Stream<Item = QueryResult<U>> + Send
79        where
80            Conn: 'conn;
81
82        /// Load this query
83        fn internal_load(self, conn: &mut Conn) -> Self::LoadFuture<'_>;
84    }
85
86    impl<'query, Conn, DB, T, U, ST> LoadQuery<'query, Conn, U> for T
87    where
88        Conn: AsyncConnection<Backend = DB>,
89        U: Send,
90        DB: Backend + 'static,
91        T: AsQuery + Send + 'query,
92        T::Query: QueryFragment<DB> + QueryId + Send + 'query,
93        T::SqlType: CompatibleType<U, DB, SqlType = ST>,
94        U: FromSqlRow<ST, DB> + Send + 'static,
95        DB: QueryMetadata<T::SqlType>,
96        ST: 'static,
97    {
98        type LoadFuture<'conn>
99            = future::MapOk<
100            Conn::LoadFuture<'conn, 'query>,
101            fn(Conn::Stream<'conn, 'query>) -> Self::Stream<'conn>,
102        >
103        where
104            Conn: 'conn;
105
106        type Stream<'conn>
107            = stream::Map<
108            Conn::Stream<'conn, 'query>,
109            fn(QueryResult<Conn::Row<'conn, 'query>>) -> QueryResult<U>,
110        >
111        where
112            Conn: 'conn;
113
114        fn internal_load(self, conn: &mut Conn) -> Self::LoadFuture<'_> {
115            conn.load(self)
116                .map_ok(map_result_stream_future::<U, _, _, DB, ST>)
117        }
118    }
119
120    #[allow(clippy::type_complexity)]
121    fn map_result_stream_future<'s, 'a, U, S, R, DB, ST>(
122        stream: S,
123    ) -> stream::Map<S, fn(QueryResult<R>) -> QueryResult<U>>
124    where
125        S: Stream<Item = QueryResult<R>> + Send + 's,
126        R: diesel::row::Row<'a, DB> + 's,
127        DB: Backend + 'static,
128        U: FromSqlRow<ST, DB> + 'static,
129        ST: 'static,
130    {
131        stream.map(map_row_helper::<_, DB, U, ST>)
132    }
133
134    fn map_row_helper<'a, R, DB, U, ST>(row: QueryResult<R>) -> QueryResult<U>
135    where
136        U: FromSqlRow<ST, DB>,
137        R: diesel::row::Row<'a, DB>,
138        DB: Backend,
139    {
140        U::build_from_row(&row?).map_err(diesel::result::Error::DeserializationError)
141    }
142}
143
144/// The return types produced by the various [`RunQueryDsl`] methods
145///
146// We cannot box these types as this would require specifying a lifetime,
147// but concrete connection implementations might want to have control
148// about that so that they can support multiple simultaneous queries on
149// the same connection
150#[allow(type_alias_bounds)] // we need these bounds otherwise we cannot use GAT's
151pub mod return_futures {
152    use super::methods::LoadQuery;
153    use diesel::QueryResult;
154    use futures_util::{future, stream};
155    use std::pin::Pin;
156
157    /// The future returned by [`RunQueryDsl::load`](super::RunQueryDsl::load)
158    /// and [`RunQueryDsl::get_results`](super::RunQueryDsl::get_results)
159    ///
160    /// This is essentially `impl Future<Output = QueryResult<Vec<U>>>`
161    pub type LoadFuture<'conn, 'query, Q: LoadQuery<'query, Conn, U>, Conn, U> = future::AndThen<
162        Q::LoadFuture<'conn>,
163        stream::TryCollect<Q::Stream<'conn>, Vec<U>>,
164        fn(Q::Stream<'conn>) -> stream::TryCollect<Q::Stream<'conn>, Vec<U>>,
165    >;
166
167    /// The future returned by [`RunQueryDsl::get_result`](super::RunQueryDsl::get_result)
168    ///
169    /// This is essentially `impl Future<Output = QueryResult<U>>`
170    pub type GetResult<'conn, 'query, Q: LoadQuery<'query, Conn, U>, Conn, U> = future::AndThen<
171        Q::LoadFuture<'conn>,
172        future::Map<
173            stream::StreamFuture<Pin<Box<Q::Stream<'conn>>>>,
174            fn((Option<QueryResult<U>>, Pin<Box<Q::Stream<'conn>>>)) -> QueryResult<U>,
175        >,
176        fn(
177            Q::Stream<'conn>,
178        ) -> future::Map<
179            stream::StreamFuture<Pin<Box<Q::Stream<'conn>>>>,
180            fn((Option<QueryResult<U>>, Pin<Box<Q::Stream<'conn>>>)) -> QueryResult<U>,
181        >,
182    >;
183}
184
185/// Methods used to execute queries.
186pub trait RunQueryDsl<Conn>: Sized {
187    /// Executes the given command, returning the number of rows affected.
188    ///
189    /// `execute` is usually used in conjunction with [`insert_into`](diesel::insert_into()),
190    /// [`update`](diesel::update()) and [`delete`](diesel::delete()) where the number of
191    /// affected rows is often enough information.
192    ///
193    /// When asking the database to return data from a query, [`load`](crate::run_query_dsl::RunQueryDsl::load()) should
194    /// probably be used instead.
195    ///
196    /// # Example
197    ///
198    /// ```rust
199    /// # include!("../doctest_setup.rs");
200    /// #
201    /// use diesel_async::RunQueryDsl;
202    ///
203    /// # #[tokio::main(flavor = "current_thread")]
204    /// # async fn main() {
205    /// #     run_test().await;
206    /// # }
207    /// #
208    /// # async fn run_test() -> QueryResult<()> {
209    /// #     use diesel::insert_into;
210    /// #     use schema::users::dsl::*;
211    /// #     let connection = &mut establish_connection().await;
212    /// let inserted_rows = insert_into(users)
213    ///     .values(name.eq("Ruby"))
214    ///     .execute(connection)
215    ///     .await?;
216    /// assert_eq!(1, inserted_rows);
217    ///
218    /// # #[cfg(not(feature = "sqlite"))]
219    /// let inserted_rows = insert_into(users)
220    ///     .values(&vec![name.eq("Jim"), name.eq("James")])
221    ///     .execute(connection)
222    ///     .await?;
223    /// # #[cfg(not(feature = "sqlite"))]
224    /// assert_eq!(2, inserted_rows);
225    /// #     Ok(())
226    /// # }
227    /// ```
228    fn execute<'conn, 'query>(self, conn: &'conn mut Conn) -> Conn::ExecuteFuture<'conn, 'query>
229    where
230        Conn: AsyncConnection + Send,
231        Self: methods::ExecuteDsl<Conn> + 'query,
232    {
233        methods::ExecuteDsl::execute(self, conn)
234    }
235
236    /// Executes the given query, returning a [`Vec`] with the returned rows.
237    ///
238    /// When using the query builder, the return type can be
239    /// a tuple of the values, or a struct which implements [`Queryable`].
240    ///
241    /// When this method is called on [`sql_query`],
242    /// the return type can only be a struct which implements [`QueryableByName`]
243    ///
244    /// For insert, update, and delete operations where only a count of affected is needed,
245    /// [`execute`] should be used instead.
246    ///
247    /// [`Queryable`]: diesel::deserialize::Queryable
248    /// [`QueryableByName`]: diesel::deserialize::QueryableByName
249    /// [`execute`]: crate::run_query_dsl::RunQueryDsl::execute()
250    /// [`sql_query`]: diesel::sql_query()
251    ///
252    /// # Examples
253    ///
254    /// ## Returning a single field
255    ///
256    /// ```rust
257    /// # include!("../doctest_setup.rs");
258    /// #
259    /// use diesel_async::{RunQueryDsl, AsyncConnection};
260    ///
261    /// #
262    /// # #[tokio::main(flavor = "current_thread")]
263    /// # async fn main() {
264    /// #     run_test().await;
265    /// # }
266    /// #
267    /// # async fn run_test() -> QueryResult<()> {
268    /// #     use diesel::insert_into;
269    /// #     use schema::users::dsl::*;
270    /// #     let connection = &mut establish_connection().await;
271    /// let data = users.select(name)
272    ///     .load::<String>(connection)
273    ///     .await?;
274    /// assert_eq!(vec!["Sean", "Tess"], data);
275    /// #     Ok(())
276    /// # }
277    /// ```
278    ///
279    /// ## Returning a tuple
280    ///
281    /// ```rust
282    /// # include!("../doctest_setup.rs");
283    /// use diesel_async::RunQueryDsl;
284    ///
285    /// #
286    /// # #[tokio::main(flavor = "current_thread")]
287    /// # async fn main() {
288    /// #     run_test().await;
289    /// # }
290    /// #
291    /// # async fn run_test() -> QueryResult<()> {
292    /// #     use diesel::insert_into;
293    /// #     use schema::users::dsl::*;
294    /// #     let connection = &mut establish_connection().await;
295    /// let data = users
296    ///     .load::<(i32, String)>(connection)
297    ///     .await?;
298    /// let expected_data = vec![
299    ///     (1, String::from("Sean")),
300    ///     (2, String::from("Tess")),
301    /// ];
302    /// assert_eq!(expected_data, data);
303    /// #     Ok(())
304    /// # }
305    /// ```
306    ///
307    /// ## Returning a struct
308    ///
309    /// ```rust
310    /// # include!("../doctest_setup.rs");
311    /// use diesel_async::RunQueryDsl;
312    ///
313    /// #
314    /// #[derive(Queryable, PartialEq, Debug)]
315    /// struct User {
316    ///     id: i32,
317    ///     name: String,
318    /// }
319    ///
320    /// # #[tokio::main(flavor = "current_thread")]
321    /// # async fn main() {
322    /// #     run_test().await;
323    /// # }
324    /// #
325    /// # async fn run_test() -> QueryResult<()> {
326    /// #     use diesel::insert_into;
327    /// #     use schema::users::dsl::*;
328    /// #     let connection = &mut establish_connection().await;
329    /// let data = users
330    ///     .load::<User>(connection)
331    ///     .await?;
332    /// let expected_data = vec![
333    ///     User { id: 1, name: String::from("Sean") },
334    ///     User { id: 2, name: String::from("Tess") },
335    /// ];
336    /// assert_eq!(expected_data, data);
337    /// #     Ok(())
338    /// # }
339    /// ```
340    fn load<'query, 'conn, U>(
341        self,
342        conn: &'conn mut Conn,
343    ) -> return_futures::LoadFuture<'conn, 'query, Self, Conn, U>
344    where
345        U: Send,
346        Conn: AsyncConnection,
347        Self: methods::LoadQuery<'query, Conn, U> + 'query,
348    {
349        fn collect_result<U, S>(stream: S) -> stream::TryCollect<S, Vec<U>>
350        where
351            S: Stream<Item = QueryResult<U>>,
352        {
353            stream.try_collect()
354        }
355        self.internal_load(conn).and_then(collect_result::<U, _>)
356    }
357
358    /// Executes the given query, returning a [`Stream`] with the returned rows.
359    ///
360    /// **You should normally prefer to use [`RunQueryDsl::load`] instead**. This method
361    /// is provided for situations where the result needs to be collected into a different
362    /// container than a [`Vec`]
363    ///
364    /// When using the query builder, the return type can be
365    /// a tuple of the values, or a struct which implements [`Queryable`].
366    ///
367    /// When this method is called on [`sql_query`],
368    /// the return type can only be a struct which implements [`QueryableByName`]
369    ///
370    /// For insert, update, and delete operations where only a count of affected is needed,
371    /// [`execute`] should be used instead.
372    ///
373    /// [`Queryable`]: diesel::deserialize::Queryable
374    /// [`QueryableByName`]: diesel::deserialize::QueryableByName
375    /// [`execute`]: crate::run_query_dsl::RunQueryDsl::execute()
376    /// [`sql_query`]: diesel::sql_query()
377    ///
378    /// # Examples
379    ///
380    /// ## Returning a single field
381    ///
382    /// ```rust
383    /// # include!("../doctest_setup.rs");
384    /// #
385    /// use diesel_async::RunQueryDsl;
386    ///
387    /// # #[tokio::main(flavor = "current_thread")]
388    /// # async fn main() {
389    /// #     run_test().await;
390    /// # }
391    /// #
392    /// # async fn run_test() -> QueryResult<()> {
393    /// #     use diesel::insert_into;
394    /// #     use schema::users::dsl::*;
395    /// #     use futures_util::stream::TryStreamExt;
396    /// #     let connection = &mut establish_connection().await;
397    /// let data = users.select(name)
398    ///     .load_stream::<String>(connection)
399    ///     .await?
400    ///     .try_fold(Vec::new(), |mut acc, item| {
401    ///          acc.push(item);
402    ///          std::future::ready(Ok(acc))
403    ///      })
404    ///     .await?;
405    /// assert_eq!(vec!["Sean", "Tess"], data);
406    /// #     Ok(())
407    /// # }
408    /// ```
409    ///
410    /// ## Returning a tuple
411    ///
412    /// ```rust
413    /// # include!("../doctest_setup.rs");
414    /// use diesel_async::RunQueryDsl;
415    /// #
416    /// # #[tokio::main(flavor = "current_thread")]
417    /// # async fn main() {
418    /// #     run_test().await;
419    /// # }
420    /// #
421    /// # async fn run_test() -> QueryResult<()> {
422    /// #     use diesel::insert_into;
423    /// #     use schema::users::dsl::*;
424    /// #     use futures_util::stream::TryStreamExt;
425    /// #     let connection = &mut establish_connection().await;
426    /// let data = users
427    ///     .load_stream::<(i32, String)>(connection)
428    ///     .await?
429    ///     .try_fold(Vec::new(), |mut acc, item| {
430    ///          acc.push(item);
431    ///          std::future::ready(Ok(acc))
432    ///      })
433    ///     .await?;
434    /// let expected_data = vec![
435    ///     (1, String::from("Sean")),
436    ///     (2, String::from("Tess")),
437    /// ];
438    /// assert_eq!(expected_data, data);
439    /// #     Ok(())
440    /// # }
441    /// ```
442    ///
443    /// ## Returning a struct
444    ///
445    /// ```rust
446    /// # include!("../doctest_setup.rs");
447    /// #
448    /// use diesel_async::RunQueryDsl;
449    ///
450    /// #[derive(Queryable, PartialEq, Debug)]
451    /// struct User {
452    ///     id: i32,
453    ///     name: String,
454    /// }
455    ///
456    /// # #[tokio::main(flavor = "current_thread")]
457    /// # async fn main() {
458    /// #     run_test().await;
459    /// # }
460    /// #
461    /// # async fn run_test() -> QueryResult<()> {
462    /// #     use diesel::insert_into;
463    /// #     use schema::users::dsl::*;
464    /// #     use futures_util::stream::TryStreamExt;
465    /// #     let connection = &mut establish_connection().await;
466    /// let data = users
467    ///     .load_stream::<User>(connection)
468    ///     .await?
469    ///     .try_fold(Vec::new(), |mut acc, item| {
470    ///          acc.push(item);
471    ///          std::future::ready(Ok(acc))
472    ///      })
473    ///     .await?;
474    /// let expected_data = vec![
475    ///     User { id: 1, name: String::from("Sean") },
476    ///     User { id: 2, name: String::from("Tess") },
477    /// ];
478    /// assert_eq!(expected_data, data);
479    /// #     Ok(())
480    /// # }
481    /// ```
482    fn load_stream<'conn, 'query, U>(self, conn: &'conn mut Conn) -> Self::LoadFuture<'conn>
483    where
484        Conn: AsyncConnection,
485        U: 'conn,
486        Self: methods::LoadQuery<'query, Conn, U> + 'query,
487    {
488        self.internal_load(conn)
489    }
490
491    /// Runs the command, and returns the affected row.
492    ///
493    /// `Err(NotFound)` will be returned if the query affected 0 rows. You can
494    /// call `.optional()` on the result of this if the command was optional to
495    /// get back a `Result<Option<U>>`
496    ///
497    /// When this method is called on an insert, update, or delete statement,
498    /// it will implicitly add a `RETURNING *` to the query,
499    /// unless a returning clause was already specified.
500    ///
501    /// This method only returns the first row that was affected, even if more
502    /// rows are affected.
503    ///
504    /// # Example
505    ///
506    /// ```rust
507    /// # include!("../doctest_setup.rs");
508    /// use diesel_async::RunQueryDsl;
509    ///
510    /// #
511    /// # #[tokio::main(flavor = "current_thread")]
512    /// # async fn main() {
513    /// #     run_test().await;
514    /// # }
515    /// #
516    /// # #[cfg(feature = "postgres")]
517    /// # async fn run_test() -> QueryResult<()> {
518    /// #     use diesel::{insert_into, update};
519    /// #     use schema::users::dsl::*;
520    /// #     let connection = &mut establish_connection().await;
521    /// let inserted_row = insert_into(users)
522    ///     .values(name.eq("Ruby"))
523    ///     .get_result(connection)
524    ///     .await?;
525    /// assert_eq!((3, String::from("Ruby")), inserted_row);
526    ///
527    /// // This will return `NotFound`, as there is no user with ID 4
528    /// let update_result = update(users.find(4))
529    ///     .set(name.eq("Jim"))
530    ///     .get_result::<(i32, String)>(connection)
531    ///     .await;
532    /// assert_eq!(Err(diesel::NotFound), update_result);
533    /// #     Ok(())
534    /// # }
535    /// #
536    /// # #[cfg(not(feature = "postgres"))]
537    /// # async fn run_test() -> QueryResult<()> {
538    /// #     Ok(())
539    /// # }
540    /// ```
541    fn get_result<'query, 'conn, U>(
542        self,
543        conn: &'conn mut Conn,
544    ) -> return_futures::GetResult<'conn, 'query, Self, Conn, U>
545    where
546        U: Send + 'conn,
547        Conn: AsyncConnection,
548        Self: methods::LoadQuery<'query, Conn, U> + 'query,
549    {
550        #[allow(clippy::type_complexity)]
551        fn get_next_stream_element<S, U>(
552            stream: S,
553        ) -> future::Map<
554            stream::StreamFuture<Pin<Box<S>>>,
555            fn((Option<QueryResult<U>>, Pin<Box<S>>)) -> QueryResult<U>,
556        >
557        where
558            S: Stream<Item = QueryResult<U>>,
559        {
560            fn map_option_to_result<U, S>(
561                (o, _): (Option<QueryResult<U>>, Pin<Box<S>>),
562            ) -> QueryResult<U> {
563                match o {
564                    Some(s) => s,
565                    None => Err(diesel::result::Error::NotFound),
566                }
567            }
568
569            Box::pin(stream).into_future().map(map_option_to_result)
570        }
571
572        self.load_stream(conn).and_then(get_next_stream_element)
573    }
574
575    /// Runs the command, returning an `Vec` with the affected rows.
576    ///
577    /// This method is an alias for [`load`], but with a name that makes more
578    /// sense for insert, update, and delete statements.
579    ///
580    /// [`load`]: crate::run_query_dsl::RunQueryDsl::load()
581    fn get_results<'query, 'conn, U>(
582        self,
583        conn: &'conn mut Conn,
584    ) -> return_futures::LoadFuture<'conn, 'query, Self, Conn, U>
585    where
586        U: Send,
587        Conn: AsyncConnection,
588        Self: methods::LoadQuery<'query, Conn, U> + 'query,
589    {
590        self.load(conn)
591    }
592
593    /// Attempts to load a single record.
594    ///
595    /// This method is equivalent to `.limit(1).get_result()`
596    ///
597    /// Returns `Ok(record)` if found, and `Err(NotFound)` if no results are
598    /// returned. If the query truly is optional, you can call `.optional()` on
599    /// the result of this to get a `Result<Option<U>>`.
600    ///
601    /// # Example:
602    ///
603    /// ```rust
604    /// # include!("../doctest_setup.rs");
605    /// use diesel_async::RunQueryDsl;
606    ///
607    /// #
608    /// # #[tokio::main(flavor = "current_thread")]
609    /// # async fn main() {
610    /// #     run_test();
611    /// # }
612    /// #
613    /// # async fn run_test() -> QueryResult<()> {
614    /// #     use schema::users::dsl::*;
615    /// #     let connection = &mut establish_connection().await;
616    /// for n in &["Sean", "Pascal"] {
617    ///     diesel::insert_into(users)
618    ///         .values(name.eq(n))
619    ///         .execute(connection)
620    ///         .await?;
621    /// }
622    ///
623    /// let first_name = users.order(id)
624    ///     .select(name)
625    ///     .first(connection)
626    ///     .await;
627    /// assert_eq!(Ok(String::from("Sean")), first_name);
628    ///
629    /// let not_found = users
630    ///     .filter(name.eq("Foo"))
631    ///     .first::<(i32, String)>(connection)
632    ///     .await;
633    /// assert_eq!(Err(diesel::NotFound), not_found);
634    /// #     Ok(())
635    /// # }
636    /// ```
637    fn first<'query, 'conn, U>(
638        self,
639        conn: &'conn mut Conn,
640    ) -> return_futures::GetResult<'conn, 'query, diesel::dsl::Limit<Self>, Conn, U>
641    where
642        U: Send + 'conn,
643        Conn: AsyncConnection,
644        Self: diesel::query_dsl::methods::LimitDsl,
645        diesel::dsl::Limit<Self>: methods::LoadQuery<'query, Conn, U> + Send + 'query,
646    {
647        diesel::query_dsl::methods::LimitDsl::limit(self, 1).get_result(conn)
648    }
649}
650
651impl<T, Conn> RunQueryDsl<Conn> for T {}
652
653/// Sugar for types which implement both `AsChangeset` and `Identifiable`
654///
655/// On backends which support the `RETURNING` keyword,
656/// `foo.save_changes(&conn)` is equivalent to
657/// `update(&foo).set(&foo).get_result(&conn)`.
658/// On other backends, two queries will be executed.
659///
660/// # Example
661///
662/// ```rust
663/// # include!("../doctest_setup.rs");
664/// # use schema::animals;
665/// #
666/// use diesel_async::{SaveChangesDsl, AsyncConnection};
667///
668/// #[derive(Queryable, Debug, PartialEq)]
669/// struct Animal {
670///    id: i32,
671///    species: String,
672///    legs: i32,
673///    name: Option<String>,
674/// }
675///
676/// #[derive(AsChangeset, Identifiable)]
677/// #[diesel(table_name = animals)]
678/// struct AnimalForm<'a> {
679///     id: i32,
680///     name: &'a str,
681/// }
682///
683/// # #[tokio::main(flavor = "current_thread")]
684/// # async fn main() {
685/// #     run_test().await.unwrap();
686/// # }
687/// #
688/// # async fn run_test() -> QueryResult<()> {
689/// #     use self::animals::dsl::*;
690/// #     let connection = &mut establish_connection().await;
691/// let form = AnimalForm { id: 2, name: "Super scary" };
692/// # #[cfg(not(feature = "sqlite"))]
693/// let changed_animal = form.save_changes(connection).await?;
694/// let expected_animal = Animal {
695///     id: 2,
696///     species: String::from("spider"),
697///     legs: 8,
698///     name: Some(String::from("Super scary")),
699/// };
700/// # #[cfg(not(feature = "sqlite"))]
701/// assert_eq!(expected_animal, changed_animal);
702/// #     Ok(())
703/// # }
704/// ```
705pub trait SaveChangesDsl<Conn> {
706    /// See the trait documentation
707    fn save_changes<'life0, 'async_trait, T>(
708        self,
709        connection: &'life0 mut Conn,
710    ) -> impl Future<Output = QueryResult<T>> + Send + 'async_trait
711    where
712        Self: Sized + diesel::prelude::Identifiable,
713        Conn: UpdateAndFetchResults<Self, T>,
714        T: 'async_trait,
715        'life0: 'async_trait,
716        Self: ::core::marker::Send + 'async_trait,
717    {
718        connection.update_and_fetch(self)
719    }
720}
721
722impl<T, Conn> SaveChangesDsl<Conn> for T where
723    T: Copy + AsChangeset<Target = <T as HasTable>::Table> + IntoUpdateTarget
724{
725}
726
727/// A trait defining how to update a record and fetch the updated entry
728/// on a certain backend.
729///
730/// The only case where it is required to work with this trait is while
731/// implementing a new connection type.
732/// Otherwise use [`SaveChangesDsl`]
733///
734/// For implementing this trait for a custom backend:
735/// * The `Changes` generic parameter represents the changeset that should be stored
736/// * The `Output` generic parameter represents the type of the response.
737pub trait UpdateAndFetchResults<Changes, Output>: AsyncConnection
738where
739    Changes: diesel::prelude::Identifiable + HasTable,
740{
741    /// See the traits documentation.
742    fn update_and_fetch<'conn, 'changes>(
743        &'conn mut self,
744        changeset: Changes,
745    ) -> BoxFuture<'changes, QueryResult<Output>>
746    // cannot use impl future due to rustc bugs
747    // https://github.com/rust-lang/rust/issues/135619
748    //impl Future<Output = QueryResult<Output>> + Send + 'changes
749    where
750        Changes: 'changes,
751        'conn: 'changes,
752        Self: 'changes;
753}
754
755#[cfg(feature = "mysql")]
756impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
757    for crate::AsyncMysqlConnection
758where
759    Output: Send + 'static,
760    Changes:
761        Copy + AsChangeset<Target = Tab> + Send + diesel::associations::Identifiable<Table = Tab>,
762    Tab: diesel::Table + diesel::query_dsl::methods::FindDsl<Changes::Id> + 'b,
763    diesel::dsl::Find<Tab, Changes::Id>: IntoUpdateTarget<Table = Tab, WhereClause = V>,
764    diesel::query_builder::UpdateStatement<Tab, V, Changes::Changeset>:
765        diesel::query_builder::AsQuery,
766    diesel::dsl::Update<Changes, Changes>: methods::ExecuteDsl<Self>,
767    V: Send + 'b,
768    Changes::Changeset: Send + 'b,
769    Changes::Id: 'b,
770    Tab::FromClause: Send,
771    diesel::dsl::Find<Changes::Table, Changes::Id>:
772        methods::LoadQuery<'b, crate::AsyncMysqlConnection, Output> + Send,
773{
774    fn update_and_fetch<'conn, 'changes>(
775        &'conn mut self,
776        changeset: Changes,
777    ) -> BoxFuture<'changes, QueryResult<Output>>
778    where
779        Changes: 'changes,
780        Changes::Changeset: 'changes,
781        'conn: 'changes,
782        Self: 'changes,
783    {
784        async move {
785            diesel::update(changeset)
786                .set(changeset)
787                .execute(self)
788                .await?;
789            Changes::table().find(changeset.id()).get_result(self).await
790        }
791        .boxed()
792    }
793}
794
795#[cfg(feature = "postgres")]
796impl<'b, Changes, Output, Tab, V> UpdateAndFetchResults<Changes, Output>
797    for crate::AsyncPgConnection
798where
799    Output: Send + 'static,
800    Changes:
801        Copy + AsChangeset<Target = Tab> + Send + diesel::associations::Identifiable<Table = Tab>,
802    Tab: diesel::Table + diesel::query_dsl::methods::FindDsl<Changes::Id> + 'b,
803    diesel::dsl::Find<Tab, Changes::Id>: IntoUpdateTarget<Table = Tab, WhereClause = V>,
804    diesel::query_builder::UpdateStatement<Tab, V, Changes::Changeset>:
805        diesel::query_builder::AsQuery,
806    diesel::dsl::Update<Changes, Changes>: methods::LoadQuery<'b, Self, Output>,
807    V: Send + 'b,
808    Changes::Changeset: Send + 'b,
809    Tab::FromClause: Send,
810{
811    fn update_and_fetch<'conn, 'changes>(
812        &'conn mut self,
813        changeset: Changes,
814    ) -> BoxFuture<'changes, QueryResult<Output>>
815    where
816        Changes: 'changes,
817        Changes::Changeset: 'changes,
818        'conn: 'changes,
819        Self: 'changes,
820    {
821        async move {
822            diesel::update(changeset)
823                .set(changeset)
824                .get_result(self)
825                .await
826        }
827        .boxed()
828    }
829}