Skip to main content

diesel/query_builder/
has_query.rs

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