diesel/query_source/mod.rs
1//! Types related to describing schema, and interactions between tables.
2//!
3//! Most traits in this module are derived or generated by [`table!`].
4//!
5//! [`table!`]: crate::table!
6
7pub(crate) mod aliasing;
8pub(crate) mod joins;
9mod peano_numbers;
10use crate::expression::{Expression, SelectableExpression, ValidGrouping};
11use crate::query_builder::nodes::StaticQueryFragment;
12use crate::query_builder::*;
13
14pub use self::aliasing::{Alias, AliasSource, AliasedField};
15pub use self::joins::JoinTo;
16pub use self::peano_numbers::*;
17pub(crate) use self::private::Pick;
18
19/// Represents a type which can appear in the `FROM` clause. Apps should not
20/// need to concern themselves with this trait.
21///
22/// Types which implement this trait include:
23/// - Tables generated by the `table!` macro
24/// - Internal structs which represent joins
25/// - A select statement which has had no query builder methods called on it,
26/// other than those which can affect the from clause.
27pub trait QuerySource {
28 /// The type returned by `from_clause`
29 type FromClause;
30 /// The type returned by `default_selection`
31 type DefaultSelection: SelectableExpression<Self>;
32
33 /// The actual `FROM` clause of this type. This is typically only called in
34 /// `QueryFragment` implementations.
35 // from here is something different than from in rust
36 // as this literally refers to SQL from.
37 #[allow(clippy::wrong_self_convention)]
38 fn from_clause(&self) -> Self::FromClause;
39 /// The default select clause of this type, which should be used if no
40 /// select clause was explicitly specified. This should always be a tuple of
41 /// all the desired columns, not `star`
42 fn default_selection(&self) -> Self::DefaultSelection;
43}
44
45/// A column on a database table. Types which implement this trait should have
46/// been generated by the [`table!` macro](crate::table!).
47// TODO: diesel 3.0 change the super trait here to `QueryRelationField`
48pub trait Column: Expression {
49 /// The table which this column belongs to
50 type Table: Table;
51
52 /// The name of this column
53 const NAME: &'static str;
54}
55
56/// A field on a database relation. Types which implement this trait
57/// should have been generated by the [`table!` macro](crate::table!) or
58/// the [`view!` macro](crate::view!
59pub trait QueryRelationField: Expression {
60 /// The query relation which this field belongs to
61 type QueryRelation: QueryRelation;
62
63 /// The name of this field
64 const NAME: &'static str;
65}
66
67impl<C> QueryRelationField for C
68where
69 C: Column,
70{
71 type QueryRelation = C::Table;
72
73 const NAME: &'static str = <C as Column>::NAME;
74}
75
76/// A SQL database relation that can be queried
77///
78/// This includes tables and database views
79///
80/// Types which implement this trait are usually generated by the [`table!` macro](crate::table!)
81pub trait QueryRelation: QuerySource + AsQuery + Sized {
82 /// The type returned by `all_columns`
83 type AllColumns: SelectableExpression<Self> + ValidGrouping<()>;
84 /// Returns a tuple of all columns belonging to this table.
85 fn all_columns() -> Self::AllColumns;
86}
87
88/// A SQL database view. Types which implement this trait should have been
89/// generated by the [`view!` macro](crate::view!).
90pub trait View: QueryRelation + private::Sealed {}
91
92/// A SQL database table. Types which implement this trait should have been
93/// generated by the [`table!` macro](crate::table!).
94// TODO: diesel 3.0 change the super trait here to `QueryRelation`
95pub trait Table: QuerySource + AsQuery + Sized {
96 /// The type returned by `primary_key`
97 type PrimaryKey: SelectableExpression<Self> + ValidGrouping<()>;
98 /// The type returned by `all_columns`
99 // TODO: diesel 3.0 drop this in favour of QueryRelation::AllColumns
100 type AllColumns: SelectableExpression<Self> + ValidGrouping<()>;
101
102 /// Returns the primary key of this table.
103 ///
104 /// If the table has a composite primary key, this will be a tuple.
105 fn primary_key(&self) -> Self::PrimaryKey;
106 /// Returns a tuple of all columns belonging to this table.
107 // TODO: diesel 3.0 drop this in favour of QueryRelation::all_columns
108 fn all_columns() -> Self::AllColumns;
109}
110
111impl<T> QueryRelation for T
112where
113 T: Table,
114{
115 type AllColumns = <T as Table>::AllColumns;
116
117 fn all_columns() -> Self::AllColumns {
118 <T as Table>::all_columns()
119 }
120}
121
122/// Determines how many times `QS` appears in `Self`
123///
124/// This trait is primarily used to determine whether or not a column is
125/// selectable from a given from clause. A column can be selected if its table
126/// appears in the from clause *exactly once*.
127///
128/// We do not allow the same table to appear in a query multiple times in any
129/// context where referencing that table would be ambiguous (depending on the
130/// context and backend being used, this may or may not be something that would
131/// otherwise result in a runtime error).
132#[diagnostic::on_unimplemented(
133 note = "double check that `{QS}` and `{Self}` appear in the same `allow_tables_to_appear_in_same_query!` \ncall if both are tables",
134 note = "double check that any two aliases to the same table in `{QS}` and `{Self}` appear in the same `alias!` call"
135)]
136pub trait AppearsInFromClause<QS> {
137 /// How many times does `QS` appear in `Self`?
138 type Count;
139}
140
141/// Allows Diesel to implement some internal traits for two tables that are distinct.
142///
143/// (Notably, a bunch of [`AppearsInFromClause`] for the tables and their aliases.)
144///
145/// This trait is implemented by the
146/// [`allow_tables_to_appear_in_same_query!`](crate::allow_tables_to_appear_in_same_query)
147/// macro.
148///
149/// Troubleshooting
150/// ---------------
151/// If you encounter an error mentioning this trait, it could mean that either:
152/// - You are attempting to use tables that don't belong to the same database together
153/// (no call to [`allow_tables_to_appear_in_same_query!`](crate::allow_tables_to_appear_in_same_query) was made)
154/// - You are attempting to use two aliases to the same table in the same query, but they
155/// were declared through different calls to [`alias!`](crate::alias)
156#[diagnostic::on_unimplemented(
157 note = "double check that `{T}` and `{Self}` appear in the same `allow_tables_to_appear_in_same_query!` \ncall if both are tables"
158)]
159pub trait TableNotEqual<T: QueryRelation>: QueryRelation {}
160
161impl<T1, T2> AppearsInFromClause<T2> for T1
162where
163 T1: TableNotEqual<T2> + QueryRelation,
164 T2: QueryRelation,
165{
166 type Count = Never;
167}
168
169pub(crate) mod private {
170 use super::{Never, Once};
171
172 /// Used to determine which of two from clauses contains a given table.
173 ///
174 /// This trait can be used to emulate "or" conditions in where clauses when
175 /// we want a trait to be implemented with one of two type parameters.
176 ///
177 /// For example, if we wanted to write:
178 ///
179 /// ```rust,ignore
180 /// where
181 /// T: SelectableExpression<Left> | SelectableExpression<Right>,
182 /// ```
183 ///
184 /// we can emulate this by writing:
185 ///
186 /// ```rust,ignore
187 /// where
188 /// Left: AppearsInFromClause<T::Table>,
189 /// Right: AppearsInFromClause<T::Table>,
190 /// (Left::Count, Right::Count): Pick<Left, Right>,
191 /// T: SelectableExpression<
192 /// <(Left::Count, Right::Count) as Pick<Left, Right>>::Selection,
193 /// >,
194 /// ```
195 ///
196 /// In order to acquire the counts in the first place, we must already know
197 /// the table we're searching for.
198 #[doc(hidden)] // This is used as part of the `table!` implementation
199 pub trait Pick<Left, Right> {
200 /// The selected type.
201 ///
202 /// For `(Once, Never)` this type will be `Left`. For `(Never, Once)`, this type will be
203 /// `Right`
204 type Selection;
205 }
206
207 impl<Left, Right> Pick<Left, Right> for (Once, Never) {
208 type Selection = Left;
209 }
210
211 impl<Left, Right> Pick<Left, Right> for (Never, Once) {
212 type Selection = Right;
213 }
214
215 /// A helper trait to prevent down stream crates form implementing certain traits
216 #[doc(hidden)]
217 pub trait Sealed {}
218
219 /// A helper trait to mark "plain" tables/views as created by `diesel::table!`/`diesel::view!`
220 #[doc(hidden)]
221 pub trait PlainQuerySource: super::QueryRelation {}
222}
223
224#[doc(hidden)]
225#[allow(
226 non_camel_case_types,
227 missing_debug_implementations,
228 missing_copy_implementations
229)]
230/// Everything in this module is here to give something more helpful than:
231///
232/// > (Never, Never): Pick<table1, table2> is not satisfied
233///
234/// Any of these impls can be deleted if they are getting in the way of
235/// other functionality. Any code which is using these impls is already
236/// failing to compile.
237mod impls_which_are_only_here_to_improve_error_messages {
238 use super::*;
239
240 pub struct this_table_doesnt_appear_in_the_from_clause_of_your_query;
241
242 impl<Left, Right> Pick<Left, Right> for (Never, Never) {
243 type Selection = this_table_doesnt_appear_in_the_from_clause_of_your_query;
244 }
245
246 pub struct this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
247
248 impl<Left, Right, OtherCount> Pick<Left, Right> for (MoreThanOnce, OtherCount) {
249 type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
250 }
251
252 impl<Left, Right> Pick<Left, Right> for (Never, MoreThanOnce) {
253 type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
254 }
255
256 impl<Left, Right> Pick<Left, Right> for (Once, MoreThanOnce) {
257 type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
258 }
259}
260
261/// Max length for columns of type Char/Varchar...
262///
263/// If a given column has a such constraint, this trait will be implemented and specify that
264/// length.
265pub trait SizeRestrictedColumn: Column {
266 /// Max length of that column
267 const MAX_LENGTH: usize;
268}
269
270/// A table with a column the database fills from an `AUTO_INCREMENT` counter
271/// when an insert does not provide a value (MySQL and MariaDB).
272///
273/// Sealed, implemented only by the [`table!`](crate::table!) macro for tables
274/// marking a column with `#[auto_increment]`, an attribute `diesel
275/// print-schema` emits for those backends.
276///
277/// The trait itself needs only a backend feature, so a generated `schema.rs`
278/// compiles under every feature combination. Its consumer,
279/// `InsertStatement::execute_returning_id`, additionally requires the `mysql`
280/// or `mariadb` connection feature.
281#[diagnostic::on_unimplemented(
282 message = "`{Self}` has no column marked `#[auto_increment]`",
283 note = "annotate the generated column in your `table!` definition with `#[auto_increment]`, \
284 or regenerate your schema with a diesel CLI that emits it, \
285 if the database table has an `AUTO_INCREMENT` column"
286)]
287#[cfg(any(feature = "mysql_backend", feature = "mariadb_backend"))]
288pub trait AutoIncrementTable: Table + private::Sealed {
289 /// The column filled from the table's `AUTO_INCREMENT` counter.
290 ///
291 /// Recorded for future use, `execute_returning_id` does not consult it.
292 type AutoIncrementColumn: Column<Table = Self>;
293}
294
295/// A helper trait to access the name of a table
296/// and the optionally the name of the schema the table belongs to
297///
298/// Usually you would like to use the `QueryFragment` implementation
299/// for the table type instead to correctly construct the relevant SQL
300/// fragment including correctly quoting all involved names
301pub trait NamedTable
302where
303 Self: Table,
304{
305 /// The schema name
306 fn schema(&self) -> Option<&str>;
307 /// The table name
308 fn table(&self) -> &str;
309}
310
311impl<T> NamedTable for T
312where
313 T: Table + StaticQueryFragment,
314 T::Component: NamedTableHelper,
315{
316 fn schema(&self) -> Option<&'static str> {
317 T::STATIC_COMPONENT.schema()
318 }
319
320 fn table(&self) -> &'static str {
321 T::STATIC_COMPONENT.table()
322 }
323}
324
325// an internal helper trait that doesn't require table as super trait
326trait NamedTableHelper {
327 fn schema(&self) -> Option<&str>;
328 fn table(&self) -> &str;
329}
330
331impl NamedTableHelper for crate::query_builder::nodes::Identifier<'static> {
332 fn schema(&self) -> Option<&'static str> {
333 None
334 }
335
336 fn table(&self) -> &'static str {
337 self.0
338 }
339}
340
341impl<M> NamedTableHelper
342 for crate::query_builder::nodes::InfixNode<
343 crate::query_builder::nodes::Identifier<'static>,
344 crate::query_builder::nodes::Identifier<'static>,
345 M,
346 >
347{
348 fn schema(&self) -> Option<&'static str> {
349 Some(self.lhs.0)
350 }
351
352 fn table(&self) -> &'static str {
353 self.rhs.0
354 }
355}
356
357/// A helper trait to access associated information for a given column
358///
359/// Usually you want to use the [`QueryFragment`] implementation for
360/// your column type to construct a correctly quoted query
361/// fragment containing the fully qualified identifier
362// This is not bound to Column as super trait as `diesel-dynamic-schema`
363// doesn't implement the Column trait for it's column type
364pub trait ColumnHasTable {
365 /// The table type of this column
366 type Table;
367
368 /// The table the column belongs to
369 fn table(&self) -> Self::Table;
370 /// The name of the table
371 fn name(&self) -> &str;
372}
373
374impl<C> ColumnHasTable for C
375where
376 C: Column,
377 C::Table: Default,
378{
379 type Table = C::Table;
380
381 fn table(&self) -> Self::Table {
382 Default::default()
383 }
384
385 fn name(&self) -> &str {
386 C::NAME
387 }
388}