diesel/query_source/
joins.rs

1use super::{AppearsInFromClause, Plus, QuerySource};
2use backend::Backend;
3use expression::grouped::Grouped;
4use expression::nullable::Nullable;
5use expression::SelectableExpression;
6use prelude::*;
7use query_builder::*;
8use result::QueryResult;
9use sql_types::Bool;
10use util::TupleAppend;
11
12#[derive(Debug, Clone, Copy, QueryId)]
13/// A query source representing the join between two tables
14pub struct Join<Left, Right, Kind> {
15    left: Left,
16    right: Right,
17    kind: Kind,
18}
19
20#[derive(Debug, Clone, Copy, QueryId)]
21#[doc(hidden)]
22/// A query source representing the join between two tables with an explicit
23/// `ON` given. `Join` should usually be referenced instead, as all "type
24/// safety" traits are implemented in terms of `Join` implementing them.
25pub struct JoinOn<Join, On> {
26    join: Join,
27    on: On,
28}
29
30impl<Left, Right, Kind> Join<Left, Right, Kind> {
31    pub fn new(left: Left, right: Right, kind: Kind) -> Self {
32        Join {
33            left: left,
34            right: right,
35            kind: kind,
36        }
37    }
38
39    #[doc(hidden)]
40    pub fn on<On>(self, on: On) -> JoinOn<Self, On> {
41        JoinOn { join: self, on: on }
42    }
43}
44
45impl<Left, Right> QuerySource for Join<Left, Right, Inner>
46where
47    Left: QuerySource + AppendSelection<Right::DefaultSelection>,
48    Right: QuerySource,
49    Left::Output: SelectableExpression<Self>,
50    Self: Clone,
51{
52    type FromClause = Self;
53    type DefaultSelection = Left::Output;
54
55    fn from_clause(&self) -> Self::FromClause {
56        self.clone()
57    }
58
59    fn default_selection(&self) -> Self::DefaultSelection {
60        self.left.append_selection(self.right.default_selection())
61    }
62}
63
64impl<Left, Right> QuerySource for Join<Left, Right, LeftOuter>
65where
66    Left: QuerySource + AppendSelection<Nullable<Right::DefaultSelection>>,
67    Right: QuerySource,
68    Left::Output: SelectableExpression<Self>,
69    Self: Clone,
70{
71    type FromClause = Self;
72    type DefaultSelection = Left::Output;
73
74    fn from_clause(&self) -> Self::FromClause {
75        self.clone()
76    }
77
78    fn default_selection(&self) -> Self::DefaultSelection {
79        self.left
80            .append_selection(self.right.default_selection().nullable())
81    }
82}
83
84impl<Join, On> QuerySource for JoinOn<Join, On>
85where
86    Join: QuerySource,
87    On: AppearsOnTable<Join::FromClause, SqlType = Bool> + Clone,
88    Join::DefaultSelection: SelectableExpression<Self>,
89{
90    type FromClause = Grouped<nodes::InfixNode<'static, Join::FromClause, On>>;
91    type DefaultSelection = Join::DefaultSelection;
92
93    fn from_clause(&self) -> Self::FromClause {
94        Grouped(nodes::InfixNode::new(
95            self.join.from_clause(),
96            self.on.clone(),
97            " ON ",
98        ))
99    }
100
101    fn default_selection(&self) -> Self::DefaultSelection {
102        self.join.default_selection()
103    }
104}
105
106impl<Left, Right, Kind, DB> QueryFragment<DB> for Join<Left, Right, Kind>
107where
108    DB: Backend,
109    Left: QuerySource,
110    Left::FromClause: QueryFragment<DB>,
111    Right: QuerySource,
112    Right::FromClause: QueryFragment<DB>,
113    Kind: QueryFragment<DB>,
114{
115    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
116        self.left.from_clause().walk_ast(out.reborrow())?;
117        self.kind.walk_ast(out.reborrow())?;
118        out.push_sql(" JOIN ");
119        self.right.from_clause().walk_ast(out.reborrow())?;
120        Ok(())
121    }
122}
123
124impl<Left, Right, Kind, T> SelectableExpression<Join<Left, Right, Kind>> for Nullable<T>
125where
126    T: SelectableExpression<Join<Left, Right, Inner>>,
127    Nullable<T>: AppearsOnTable<Join<Left, Right, Kind>>,
128{
129}
130
131// FIXME: Remove this when overlapping marker traits are stable
132impl<Join, On, T> SelectableExpression<JoinOn<Join, On>> for Nullable<T>
133where
134    Nullable<T>: SelectableExpression<Join>,
135    Nullable<T>: AppearsOnTable<JoinOn<Join, On>>,
136{
137}
138
139// FIXME: Remove this when overlapping marker traits are stable
140impl<From, T> SelectableExpression<SelectStatement<From>> for Nullable<T>
141where
142    Nullable<T>: SelectableExpression<From>,
143    Nullable<T>: AppearsOnTable<SelectStatement<From>>,
144{
145}
146
147// FIXME: We want these blanket impls when overlapping marker traits are stable
148// impl<T, Join, On> SelectableExpression<JoinOn<Join, On>> for T where
149//     T: SelectableExpression<Join> + AppearsOnTable<JoinOn<Join, On>>,
150// {
151// }
152
153/// Indicates that two tables can be joined without an explicit `ON` clause.
154///
155/// Implementations of this trait are generated by invoking [`joinable!`].
156/// Implementing this trait means that you can call
157/// `left_table.inner_join(right_table)`, without supplying the `ON` clause
158/// explicitly. To join two tables which do not implement this trait, you will
159/// need to call [`.on`].
160///
161/// See [`joinable!`] and [`inner_join`] for usage examples.
162///
163/// [`joinable!`]: ../macro.joinable.html
164/// [`.on`]: ../query_dsl/trait.JoinOnDsl.html#method.on
165/// [`inner_join`]: ../query_dsl/trait.QueryDsl.html#method.inner_join
166pub trait JoinTo<T> {
167    #[doc(hidden)]
168    type FromClause;
169    #[doc(hidden)]
170    type OnClause;
171    #[doc(hidden)]
172    fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause);
173}
174
175#[doc(hidden)]
176/// Used to ensure the sql type of `left.join(mid).join(right)` is
177/// `(Left, Mid, Right)` and not `((Left, Mid), Right)`. This needs
178/// to be separate from `TupleAppend` because we still want to keep
179/// the column lists (which are tuples) separate.
180pub trait AppendSelection<Selection> {
181    type Output;
182
183    fn append_selection(&self, selection: Selection) -> Self::Output;
184}
185
186impl<T: Table, Selection> AppendSelection<Selection> for T {
187    type Output = (T::AllColumns, Selection);
188
189    fn append_selection(&self, selection: Selection) -> Self::Output {
190        (T::all_columns(), selection)
191    }
192}
193
194impl<Left, Mid, Selection, Kind> AppendSelection<Selection> for Join<Left, Mid, Kind>
195where
196    Self: QuerySource,
197    <Self as QuerySource>::DefaultSelection: TupleAppend<Selection>,
198{
199    type Output = <<Self as QuerySource>::DefaultSelection as TupleAppend<Selection>>::Output;
200
201    fn append_selection(&self, selection: Selection) -> Self::Output {
202        self.default_selection().tuple_append(selection)
203    }
204}
205
206impl<Join, On, Selection> AppendSelection<Selection> for JoinOn<Join, On>
207where
208    Join: AppendSelection<Selection>,
209{
210    type Output = Join::Output;
211
212    fn append_selection(&self, selection: Selection) -> Self::Output {
213        self.join.append_selection(selection)
214    }
215}
216
217#[doc(hidden)]
218#[derive(Debug, Clone, Copy, Default, QueryId)]
219pub struct Inner;
220
221impl<DB: Backend> QueryFragment<DB> for Inner {
222    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
223        out.push_sql(" INNER");
224        Ok(())
225    }
226}
227
228#[doc(hidden)]
229#[derive(Debug, Clone, Copy, Default, QueryId)]
230pub struct LeftOuter;
231
232impl<DB: Backend> QueryFragment<DB> for LeftOuter {
233    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
234        out.push_sql(" LEFT OUTER");
235        Ok(())
236    }
237}
238
239impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind>
240where
241    Left: JoinTo<Right>,
242{
243    type FromClause = Left::FromClause;
244    type OnClause = Left::OnClause;
245
246    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
247        Left::join_target(rhs)
248    }
249}
250
251impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On>
252where
253    Join: JoinTo<Right>,
254{
255    type FromClause = Join::FromClause;
256    type OnClause = Join::OnClause;
257
258    fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
259        Join::join_target(rhs)
260    }
261}
262
263impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind>
264where
265    Left: AppearsInFromClause<T>,
266    Right: AppearsInFromClause<T>,
267    Left::Count: Plus<Right::Count>,
268{
269    type Count = <Left::Count as Plus<Right::Count>>::Output;
270}
271
272impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On>
273where
274    Join: AppearsInFromClause<T>,
275{
276    type Count = Join::Count;
277}
278
279#[doc(hidden)]
280#[derive(Debug, Clone, Copy)]
281pub struct OnClauseWrapper<Source, On> {
282    source: Source,
283    on: On,
284}
285
286impl<Source, On> OnClauseWrapper<Source, On> {
287    pub fn new(source: Source, on: On) -> Self {
288        OnClauseWrapper { source, on }
289    }
290}
291
292impl<Lhs, Rhs, On> JoinTo<OnClauseWrapper<Rhs, On>> for Lhs
293where
294    Lhs: Table,
295{
296    type FromClause = Rhs;
297    type OnClause = On;
298
299    fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
300        (rhs.source, rhs.on)
301    }
302}