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