diesel/query_builder/
has_query.rs

1use super::group_by_clause::ValidGroupByClause;
2use super::{BoxedSelectStatement, FromClause, NoFromClause, Query, QueryId, SelectStatement};
3use crate::backend::Backend;
4use crate::expression::ValidGrouping;
5use crate::query_dsl::methods::SelectDsl;
6use crate::{AppearsOnTable, QuerySource, SelectableHelper};
7pub use diesel_derives::HasQuery;
8
9/// Trait indicating that a base query can be constructed for this type
10///
11/// Types which implement `HasQuery` have a default query for loading
12/// the relevant data from the database associated with this type.
13///
14/// Consumers of this trait should use the `query()` associated function
15/// to construct a query including a matching select clause for their type
16///
17/// This trait can be [derived](derive@HasTable)
18///
19/// It's important to note that for Diesel mappings between the database and rust types always happen
20/// on query and not on table level. This enables you to write several queries related to the
21/// same table, while a single query could be related to zero or multiple tables.
22///
23/// # Example
24///
25/// ## With derive
26///
27/// ```rust
28/// # extern crate diesel;
29/// # extern crate dotenvy;
30/// # include!("../doctest_setup.rs");
31/// #
32///
33/// // it's important to have the right table in scope
34/// use schema::users;
35///
36/// #[derive(HasQuery, PartialEq, Debug)]
37/// struct User {
38///     id: i32,
39///     name: String,
40/// }
41///
42/// # fn main() -> QueryResult<()> {
43/// #
44/// #     let connection = &mut establish_connection();
45/// // equivalent to `users::table.select(User::as_select()).first(connection)?;
46/// let first_user = User::query().first(connection)?;
47/// let expected = User { id: 1, name: "Sean".into() };
48/// assert_eq!(expected, first_user);
49///
50/// #     Ok(())
51/// # }
52/// ```
53///
54/// ## Manual implementation
55///
56/// ```rust
57/// # extern crate diesel;
58/// # extern crate dotenvy;
59/// # include!("../doctest_setup.rs");
60/// #
61///
62/// // it's important to have the right table in scope
63/// use schema::users;
64///
65/// #[derive(Selectable, Queryable, PartialEq, Debug)]
66/// struct User {
67///     id: i32,
68///     name: String,
69/// }
70///
71/// impl<DB: diesel::backend::Backend> diesel::HasQuery<DB> for User {
72///    type BaseQuery = <users::table as diesel::query_builder::AsQuery>::Query;
73///
74///    // internal not stable method
75///    fn base_query() -> Self::BaseQuery {
76///        use diesel::query_builder::AsQuery;
77///        users::table.as_query()
78///    }
79/// }
80///
81/// # fn main() -> QueryResult<()> {
82/// #
83/// #     let connection = &mut establish_connection();
84/// // equivalent to `users::table.select(User::as_select()).first(connection)?;
85/// let first_user = User::query().first(connection)?;
86/// let expected = User { id: 1, name: "Sean".into() };
87/// assert_eq!(expected, first_user);
88///
89/// #     Ok(())
90/// # }
91/// ```
92// Ideally we would have a `Queryable<Self::SelectExpression::SqlType, DB> as well here
93// but rustc breaks down if we do that
94// It claimns in that case that it isn't implemented,
95// while it is obviously implemented by the derive
96pub trait HasQuery<DB: Backend>:
97    SelectableHelper<
98    DB,
99    SelectExpression: QueryId
100            // these two bounds are here to get better error messages
101                          + AppearsOnTable<<Self::BaseQuery as AcceptedQueries>::From>
102                          + ValidGrouping<<Self::BaseQuery as AcceptedQueries>::GroupBy>,
103>
104{
105    /// Base query type defined by the implementing type
106    type BaseQuery: AcceptedQueries + SelectDsl<crate::dsl::AsSelect<Self, DB>, Output: Query>;
107
108    #[doc(hidden)] // that method is for internal use only
109    fn base_query() -> Self::BaseQuery;
110
111    /// Construct the query associated with this type
112    fn query() -> crate::dsl::Select<Self::BaseQuery, crate::dsl::AsSelect<Self, DB>> {
113        Self::base_query().select(Self::as_select())
114    }
115}
116
117use self::private::AcceptedQueries;
118
119mod private {
120    use super::*;
121    pub trait AcceptedQueries {
122        type From;
123        type GroupBy;
124    }
125
126    impl<S, D, W, O, LOf, GB, H, L> AcceptedQueries
127        for SelectStatement<NoFromClause, S, D, W, O, LOf, GB, H, L>
128    where
129        GB: ValidGroupByClause,
130    {
131        type From = NoFromClause;
132
133        type GroupBy = GB::Expressions;
134    }
135
136    impl<F, S, D, W, O, LOf, GB, H, L> AcceptedQueries
137        for SelectStatement<FromClause<F>, S, D, W, O, LOf, GB, H, L>
138    where
139        F: QuerySource,
140        GB: ValidGroupByClause,
141    {
142        type From = F;
143
144        type GroupBy = GB::Expressions;
145    }
146
147    impl<'a, ST, DB, GB> AcceptedQueries for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
148    where
149        GB: ValidGroupByClause,
150    {
151        type From = NoFromClause;
152
153        type GroupBy = GB::Expressions;
154    }
155
156    impl<'a, ST, F, DB, GB> AcceptedQueries for BoxedSelectStatement<'a, ST, FromClause<F>, DB, GB>
157    where
158        F: QuerySource,
159        GB: ValidGroupByClause,
160    {
161        type From = F;
162
163        type GroupBy = GB::Expressions;
164    }
165}