diesel/query_dsl/
load_dsl.rs

1use self::private::LoadIter;
2use super::RunQueryDsl;
3use crate::backend::Backend;
4use crate::connection::{Connection, DefaultLoadingMode, LoadConnection};
5use crate::deserialize::FromSqlRow;
6use crate::expression::QueryMetadata;
7use crate::query_builder::{AsQuery, QueryFragment, QueryId};
8use crate::result::QueryResult;
9
10#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
11pub use self::private::CompatibleType;
12
13#[cfg(not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))]
14pub(crate) use self::private::CompatibleType;
15
16/// The `load` method
17///
18/// This trait should not be relied on directly by most apps. Its behavior is
19/// provided by [`RunQueryDsl`]. However, you may need a where clause on this trait
20/// to call `load` from generic code.
21///
22/// [`RunQueryDsl`]: crate::RunQueryDsl
23pub trait LoadQuery<'query, Conn, U, B = DefaultLoadingMode>: RunQueryDsl<Conn> {
24    /// Return type of `LoadQuery::internal_load`
25    type RowIter<'conn>: Iterator<Item = QueryResult<U>>
26    where
27        Conn: 'conn;
28
29    /// Load this query
30    #[diesel_derives::__diesel_public_if(
31        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
32    )]
33    fn internal_load(self, conn: &mut Conn) -> QueryResult<Self::RowIter<'_>>;
34}
35
36#[doc(hidden)]
37#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
38#[deprecated(note = "Use `LoadQuery::Iter` directly")]
39pub type LoadRet<'conn, 'query, Q, C, U, B = DefaultLoadingMode> =
40    <Q as LoadQuery<'query, C, U, B>>::RowIter<'conn>;
41
42impl<'query, Conn, T, U, DB, B> LoadQuery<'query, Conn, U, B> for T
43where
44    Conn: Connection<Backend = DB> + LoadConnection<B>,
45    T: AsQuery + RunQueryDsl<Conn>,
46    T::Query: QueryFragment<DB> + QueryId + 'query,
47    T::SqlType: CompatibleType<U, DB>,
48    DB: Backend + QueryMetadata<T::SqlType> + 'static,
49    U: FromSqlRow<<T::SqlType as CompatibleType<U, DB>>::SqlType, DB> + 'static,
50    <T::SqlType as CompatibleType<U, DB>>::SqlType: 'static,
51{
52    type RowIter<'conn>
53        = LoadIter<
54        U,
55        <Conn as LoadConnection<B>>::Cursor<'conn, 'query>,
56        <T::SqlType as CompatibleType<U, DB>>::SqlType,
57        DB,
58    >
59    where
60        Conn: 'conn;
61
62    fn internal_load(self, conn: &mut Conn) -> QueryResult<Self::RowIter<'_>> {
63        const {
64            // that's required to force evaluating
65            // this constant
66            let _ = T::Query::IS_WINDOW_FUNCTION;
67        }
68        Ok(LoadIter {
69            cursor: conn.load(self.as_query())?,
70            _marker: Default::default(),
71        })
72    }
73}
74
75/// The `execute` method
76///
77/// This trait should not be relied on directly by most apps. Its behavior is
78/// provided by [`RunQueryDsl`]. However, you may need a where clause on this trait
79/// to call `execute` from generic code.
80///
81/// [`RunQueryDsl`]: crate::RunQueryDsl
82pub trait ExecuteDsl<Conn: Connection<Backend = DB>, DB: Backend = <Conn as Connection>::Backend>:
83    Sized
84{
85    /// Execute this command
86    fn execute(query: Self, conn: &mut Conn) -> QueryResult<usize>;
87}
88
89use crate::result::Error;
90
91impl<Conn, DB, T> ExecuteDsl<Conn, DB> for T
92where
93    Conn: Connection<Backend = DB>,
94    DB: Backend,
95    T: QueryFragment<DB> + QueryId,
96{
97    fn execute(query: T, conn: &mut Conn) -> Result<usize, Error> {
98        conn.execute_returning_count(&query)
99    }
100}
101
102// These types and traits are not part of the public API.
103//
104// * CompatibleType as we consider this as "sealed" trait. It shouldn't
105// be implemented by a third party
106// * LoadIter as it's an implementation detail
107mod private {
108    use crate::backend::Backend;
109    use crate::deserialize::FromSqlRow;
110    use crate::expression::select_by::SelectBy;
111    use crate::expression::{Expression, TypedExpressionType};
112    use crate::sql_types::{SqlType, Untyped};
113    use crate::{QueryResult, Selectable};
114
115    #[allow(missing_debug_implementations)]
116    pub struct LoadIter<U, C, ST, DB> {
117        pub(super) cursor: C,
118        pub(super) _marker: std::marker::PhantomData<(ST, U, DB)>,
119    }
120
121    impl<'a, C, U, ST, DB, R> LoadIter<U, C, ST, DB>
122    where
123        DB: Backend,
124        C: Iterator<Item = QueryResult<R>>,
125        R: crate::row::Row<'a, DB>,
126        U: FromSqlRow<ST, DB>,
127    {
128        pub(super) fn map_row(row: Option<QueryResult<R>>) -> Option<QueryResult<U>> {
129            match row? {
130                Ok(row) => Some(
131                    U::build_from_row(&row).map_err(crate::result::Error::DeserializationError),
132                ),
133                Err(e) => Some(Err(e)),
134            }
135        }
136    }
137
138    impl<'a, C, U, ST, DB, R> Iterator for LoadIter<U, C, ST, DB>
139    where
140        DB: Backend,
141        C: Iterator<Item = QueryResult<R>>,
142        R: crate::row::Row<'a, DB>,
143        U: FromSqlRow<ST, DB>,
144    {
145        type Item = QueryResult<U>;
146
147        fn next(&mut self) -> Option<Self::Item> {
148            Self::map_row(self.cursor.next())
149        }
150
151        fn size_hint(&self) -> (usize, Option<usize>) {
152            self.cursor.size_hint()
153        }
154
155        fn count(self) -> usize
156        where
157            Self: Sized,
158        {
159            self.cursor.count()
160        }
161
162        fn last(self) -> Option<Self::Item>
163        where
164            Self: Sized,
165        {
166            Self::map_row(self.cursor.last())
167        }
168
169        fn nth(&mut self, n: usize) -> Option<Self::Item> {
170            Self::map_row(self.cursor.nth(n))
171        }
172    }
173
174    impl<'a, C, U, ST, DB, R> ExactSizeIterator for LoadIter<U, C, ST, DB>
175    where
176        DB: Backend,
177        C: ExactSizeIterator + Iterator<Item = QueryResult<R>>,
178        R: crate::row::Row<'a, DB>,
179        U: FromSqlRow<ST, DB>,
180    {
181        fn len(&self) -> usize {
182            self.cursor.len()
183        }
184    }
185
186    #[cfg_attr(
187        docsrs,
188        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
189    )]
190    #[diagnostic::on_unimplemented(
191        note = "this is a mismatch between what your query returns and what your type expects the query to return",
192        note = "the fields in your struct need to match the fields returned by your query in count, order and type",
193        note = "consider using `#[diesel(check_for_backend({DB}))]` on either `#[derive(Selectable)]` or `#[derive(QueryableByName)]` \n\
194                on your struct `{U}` and in your query `.select({U}::as_select())` to get a better error message"
195    )]
196    pub trait CompatibleType<U, DB> {
197        type SqlType;
198    }
199
200    impl<ST, U, DB> CompatibleType<U, DB> for ST
201    where
202        DB: Backend,
203        ST: SqlType + crate::sql_types::SingleValue,
204        U: FromSqlRow<ST, DB>,
205    {
206        type SqlType = ST;
207    }
208
209    impl<U, DB> CompatibleType<U, DB> for Untyped
210    where
211        U: FromSqlRow<Untyped, DB>,
212        DB: Backend,
213    {
214        type SqlType = Untyped;
215    }
216
217    impl<U, DB, E, ST> CompatibleType<U, DB> for SelectBy<U, DB>
218    where
219        DB: Backend,
220        ST: SqlType + TypedExpressionType,
221        U: Selectable<DB, SelectExpression = E>,
222        E: Expression<SqlType = ST>,
223        U: FromSqlRow<ST, DB>,
224    {
225        type SqlType = ST;
226    }
227}