1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Types related to describing schema, and interactions between tables.
//!
//! Most traits in this module are derived or generated by [`table!`].
//!
//! [`table!`]: crate::table!
#[doc(hidden)]
pub mod joins;
mod peano_numbers;

use crate::expression::{Expression, SelectableExpression, ValidGrouping};
use crate::query_builder::*;

pub use self::joins::JoinTo;
pub use self::peano_numbers::*;

/// Represents a type which can appear in the `FROM` clause. Apps should not
/// need to concern themselves with this trait.
///
/// Types which implement this trait include:
/// - Tables generated by the `table!` macro
/// - Internal structs which represent joins
/// - A select statement which has had no query builder methods called on it,
///   other than those which can affect the from clause.
pub trait QuerySource {
    /// The type returned by `from_clause`
    type FromClause;
    /// The type returned by `default_selection`
    type DefaultSelection: SelectableExpression<Self>;

    /// The actual `FROM` clause of this type. This is typically only called in
    /// `QueryFragment` implementations.
    fn from_clause(&self) -> Self::FromClause;
    /// The default select clause of this type, which should be used if no
    /// select clause was explicitly specified. This should always be a tuple of
    /// all the desired columns, not `star`
    fn default_selection(&self) -> Self::DefaultSelection;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!` macro](crate::table!).
pub trait Column: Expression {
    /// The table which this column belongs to
    type Table: Table;

    /// The name of this column
    const NAME: &'static str;
}

/// A SQL database table. Types which implement this trait should have been
/// generated by the [`table!` macro](crate::table!).
pub trait Table: QuerySource + AsQuery + Sized {
    /// The type returned by `primary_key`
    type PrimaryKey: SelectableExpression<Self> + ValidGrouping<()>;
    /// The type returned by `all_columns`
    type AllColumns: SelectableExpression<Self> + ValidGrouping<()>;

    /// Returns the primary key of this table.
    ///
    /// If the table has a composite primary key, this will be a tuple.
    fn primary_key(&self) -> Self::PrimaryKey;
    /// Returns a tuple of all columns belonging to this table.
    fn all_columns() -> Self::AllColumns;
}

/// Determines how many times `Self` appears in `QS`
///
/// This trait is primarily used to determine whether or not a column is
/// selectable from a given from clause. A column can be selected if its table
/// appears in the from clause *exactly once*.
///
/// We do not allow the same table to appear in a query multiple times in any
/// context where referencing that table would be ambiguous (depending on the
/// context and backend being used, this may or may not be something that would
/// otherwise result in a runtime error).
pub trait AppearsInFromClause<QS> {
    /// How many times does `Self` appear in `QS`?
    type Count;
}

#[doc(hidden)]
/// Used to determine which of two from clauses contains a given table.
///
/// This trait can be used to emulate "or" conditions in where clauses when
/// we want a trait to be implemented with one of two type parameters.
///
/// For example, if we wanted to write:
///
/// ```rust,ignore
/// where
///     T: SelectableExpression<Left> | SelectableExpression<Right>,
/// ```
///
/// we can emulate this by writing:
///
/// ```rust,ignore
/// where
///     Left: AppearsInFromClause<T::Table>,
///     Right: AppearsInFromClause<T::Table>,
///     (Left::Count, Right::Count): Pick<Left, Right>,
///     T: SelectableExpression<
///         <(Left::Count, Right::Count) as Pick<Left, Right>>::Selection,
///     >,
/// ```
///
/// In order to aquire the counts in the first place, we must already know
/// the table we're searching for.
pub trait Pick<Left, Right> {
    /// The selected type.
    ///
    /// For `(Once, Never)` this type will be `Left`. For `(Never, Once)`, this type will be
    /// `Right`
    type Selection;
}

impl<Left, Right> Pick<Left, Right> for (Once, Never) {
    type Selection = Left;
}

impl<Left, Right> Pick<Left, Right> for (Never, Once) {
    type Selection = Right;
}

#[doc(hidden)]
#[allow(
    non_camel_case_types,
    missing_debug_implementations,
    missing_copy_implementations
)]
/// Everything in this module is here to give something more helpful than:
///
/// > (Never, Never): Pick<table1, table2> is not satisifed
///
/// Any of these impls can be deleted if they are getting in the way of
/// other functionality. Any code which is using these impls is already
/// failing to compile.
mod impls_which_are_only_here_to_improve_error_messages {
    use super::*;

    pub struct this_table_doesnt_appear_in_the_from_clause_of_your_query;

    impl<Left, Right> Pick<Left, Right> for (Never, Never) {
        type Selection = this_table_doesnt_appear_in_the_from_clause_of_your_query;
    }

    pub struct this_table_appears_in_your_query_more_than_once_and_must_be_aliased;

    impl<Left, Right, OtherCount> Pick<Left, Right> for (MoreThanOnce, OtherCount) {
        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
    }

    impl<Left, Right> Pick<Left, Right> for (Never, MoreThanOnce) {
        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
    }

    impl<Left, Right> Pick<Left, Right> for (Once, MoreThanOnce) {
        type Selection = this_table_appears_in_your_query_more_than_once_and_must_be_aliased;
    }
}