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/// # // Reading the query result requires reading memory allocated by the
46/// # // native sqlite library, which miri cannot track provenance for.
47/// # #[cfg(miri)]
48/// # fn main() {}
49/// # #[cfg(not(miri))]
50/// # fn main() -> QueryResult<()> {
51/// #
52/// # let connection = &mut establish_connection();
53/// // equivalent to `users::table.select(User::as_select()).first(connection)?;
54/// let first_user = User::query().first(connection)?;
55/// let expected = User { id: 1, name: "Sean".into() };
56/// assert_eq!(expected, first_user);
57///
58/// # Ok(())
59/// # }
60/// ```
61///
62/// ## Manual implementation
63///
64/// ```rust
65/// # extern crate diesel;
66/// # extern crate dotenvy;
67/// # include!("../doctest_setup.rs");
68/// #
69///
70/// // it's important to have the right table in scope
71/// use schema::users;
72///
73/// #[derive(Selectable, Queryable, PartialEq, Debug)]
74/// struct User {
75/// id: i32,
76/// name: String,
77/// }
78///
79/// impl<DB: diesel::backend::Backend> diesel::HasQuery<DB> for User {
80/// type BaseQuery = <users::table as diesel::query_builder::AsQuery>::Query;
81///
82/// // internal not stable method
83/// fn base_query() -> Self::BaseQuery {
84/// use diesel::query_builder::AsQuery;
85/// users::table.as_query()
86/// }
87/// }
88///
89/// # // Reading the query result requires reading memory allocated by the
90/// # // native sqlite library, which miri cannot track provenance for.
91/// # #[cfg(miri)]
92/// # fn main() {}
93/// # #[cfg(not(miri))]
94/// # fn main() -> QueryResult<()> {
95/// #
96/// # let connection = &mut establish_connection();
97/// // equivalent to `users::table.select(User::as_select()).first(connection)?;
98/// let first_user = User::query().first(connection)?;
99/// let expected = User { id: 1, name: "Sean".into() };
100/// assert_eq!(expected, first_user);
101///
102/// # Ok(())
103/// # }
104/// ```
105// Ideally we would have a `Queryable<Self::SelectExpression::SqlType, DB> as well here
106// but rustc breaks down if we do that
107// It claimns in that case that it isn't implemented,
108// while it is obviously implemented by the derive
109pub trait HasQuery<DB: Backend>:
110 SelectableHelper<
111 DB,
112 SelectExpression: QueryId
113 // these two bounds are here to get better error messages
114 + AppearsOnTable<<Self::BaseQuery as AcceptedQueries>::From>
115 + ValidGrouping<<Self::BaseQuery as AcceptedQueries>::GroupBy>,
116>
117{
118 /// Base query type defined by the implementing type
119 type BaseQuery: AcceptedQueries + SelectDsl<crate::dsl::AsSelect<Self, DB>, Output: Query>;
120
121 #[doc(hidden)] // that method is for internal use only
122 fn base_query() -> Self::BaseQuery;
123
124 /// Construct the query associated with this type
125 fn query() -> crate::dsl::Select<Self::BaseQuery, crate::dsl::AsSelect<Self, DB>> {
126 Self::base_query().select(Self::as_select())
127 }
128}
129
130use self::private::AcceptedQueries;
131
132mod private {
133 use super::*;
134 pub trait AcceptedQueries {
135 type From;
136 type GroupBy;
137 }
138
139 impl<S, D, W, O, LOf, GB, H, L> AcceptedQueries
140 for SelectStatement<NoFromClause, S, D, W, O, LOf, GB, H, L>
141 where
142 GB: ValidGroupByClause,
143 {
144 type From = NoFromClause;
145
146 type GroupBy = GB::Expressions;
147 }
148
149 impl<F, S, D, W, O, LOf, GB, H, L> AcceptedQueries
150 for SelectStatement<FromClause<F>, S, D, W, O, LOf, GB, H, L>
151 where
152 F: QuerySource,
153 GB: ValidGroupByClause,
154 {
155 type From = F;
156
157 type GroupBy = GB::Expressions;
158 }
159
160 impl<'a, ST, DB, GB> AcceptedQueries for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
161 where
162 GB: ValidGroupByClause,
163 {
164 type From = NoFromClause;
165
166 type GroupBy = GB::Expressions;
167 }
168
169 impl<'a, ST, F, DB, GB> AcceptedQueries for BoxedSelectStatement<'a, ST, FromClause<F>, DB, GB>
170 where
171 F: QuerySource,
172 GB: ValidGroupByClause,
173 {
174 type From = F;
175
176 type GroupBy = GB::Expressions;
177 }
178
179 impl<'a, ST, DB, GB> AcceptedQueries for BoxedCloneSelectStatement<'a, ST, NoFromClause, DB, GB>
180 where
181 GB: ValidGroupByClause,
182 {
183 type From = NoFromClause;
184
185 type GroupBy = GB::Expressions;
186 }
187
188 impl<'a, ST, F, DB, GB> AcceptedQueries for BoxedCloneSelectStatement<'a, ST, FromClause<F>, DB, GB>
189 where
190 F: QuerySource,
191 GB: ValidGroupByClause,
192 {
193 type From = F;
194
195 type GroupBy = GB::Expressions;
196 }
197}