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;
10
11use crate::expression::{Expression, SelectableExpression, ValidGrouping};
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 `Self` appears in `QS`
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 `Self` appear in `QS`?
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 [`allow_tables_to_appear_in_same_query!`] macro.
146///
147/// Troubleshooting
148/// ---------------
149/// If you encounter an error mentioning this trait, it could mean that either:
150/// - You are attempting to use tables that don't belong to the same database together
151///   (no call to [`allow_tables_to_appear_in_same_query!`] was made)
152/// - You are attempting to use two aliases to the same table in the same query, but they
153///   were declared through different calls to [`alias!`](crate::alias)
154#[diagnostic::on_unimplemented(
155    note = "double check that `{T}` and `{Self}` appear in the same `allow_tables_to_appear_in_same_query!` \ncall if both are tables"
156)]
157pub trait TableNotEqual<T: QueryRelation>: QueryRelation {}
158
159impl<T1, T2> AppearsInFromClause<T2> for T1
160where
161    T1: TableNotEqual<T2> + QueryRelation,
162    T2: QueryRelation,
163{
164    type Count = Never;
165}
166
167pub(crate) mod private {
168    use super::{Never, Once};
169
170    /// Used to determine which of two from clauses contains a given table.
171    ///
172    /// This trait can be used to emulate "or" conditions in where clauses when
173    /// we want a trait to be implemented with one of two type parameters.
174    ///
175    /// For example, if we wanted to write:
176    ///
177    /// ```rust,ignore
178    /// where
179    ///     T: SelectableExpression<Left> | SelectableExpression<Right>,
180    /// ```
181    ///
182    /// we can emulate this by writing:
183    ///
184    /// ```rust,ignore
185    /// where
186    ///     Left: AppearsInFromClause<T::Table>,
187    ///     Right: AppearsInFromClause<T::Table>,
188    ///     (Left::Count, Right::Count): Pick<Left, Right>,
189    ///     T: SelectableExpression<
190    ///         <(Left::Count, Right::Count) as Pick<Left, Right>>::Selection,
191    ///     >,
192    /// ```
193    ///
194    /// In order to acquire the counts in the first place, we must already know
195    /// the table we're searching for.
196    #[doc(hidden)] // This is used as part of the `table!` implementation
197    pub trait Pick<Left, Right> {
198        /// The selected type.
199        ///
200        /// For `(Once, Never)` this type will be `Left`. For `(Never, Once)`, this type will be
201        /// `Right`
202        type Selection;
203    }
204
205    impl<Left, Right> Pick<Left, Right> for (Once, Never) {
206        type Selection = Left;
207    }
208
209    impl<Left, Right> Pick<Left, Right> for (Never, Once) {
210        type Selection = Right;
211    }
212
213    /// A helper trait to prevent down stream crates form implementing certain traits
214    #[doc(hidden)]
215    pub trait Sealed {}
216
217    /// A helper trait to mark "plain" tables/views as created by `diesel::table!`/`diesel::view!`
218    #[doc(hidden)]
219    pub trait PlainQuerySource: super::QueryRelation {}
220}
221
222#[doc(hidden)]
223#[allow(
224    non_camel_case_types,
225    missing_debug_implementations,
226    missing_copy_implementations
227)]
228/// Everything in this module is here to give something more helpful than:
229///
230/// > (Never, Never): Pick<table1, table2> is not satisfied
231///
232/// Any of these impls can be deleted if they are getting in the way of
233/// other functionality. Any code which is using these impls is already
234/// failing to compile.
235mod impls_which_are_only_here_to_improve_error_messages {
236    use super::*;
237
238    pub struct this_table_doesnt_appear_in_the_from_clause_of_your_query;
239
240    impl<Left, Right> Pick<Left, Right> for (Never, Never) {
241        type Selection = this_table_doesnt_appear_in_the_from_clause_of_your_query;
242    }
243
244    pub struct this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
245
246    impl<Left, Right, OtherCount> Pick<Left, Right> for (MoreThanOnce, OtherCount) {
247        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
248    }
249
250    impl<Left, Right> Pick<Left, Right> for (Never, MoreThanOnce) {
251        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
252    }
253
254    impl<Left, Right> Pick<Left, Right> for (Once, MoreThanOnce) {
255        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
256    }
257}
258
259/// Max length for columns of type Char/Varchar...
260///
261/// If a given column has a such constraint, this trait will be implemented and specify that
262/// length.
263pub trait SizeRestrictedColumn: Column {
264    /// Max length of that column
265    const MAX_LENGTH: usize;
266}