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
use query_builder::AsQuery; use query_source::{joins, Table, JoinTo}; #[doc(hidden)] /// `JoinDsl` support trait to emulate associated type constructors pub trait InternalJoinDsl<Rhs, Kind, On> { type Output: AsQuery; fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output; } impl<T, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On> for T where T: Table + AsQuery, T::Query: InternalJoinDsl<Rhs, Kind, On>, { type Output = <T::Query as InternalJoinDsl<Rhs, Kind, On>>::Output; fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output { self.as_query().join(rhs, kind, on) } } #[doc(hidden)] /// `JoinDsl` support trait to emulate associated type constructors and grab /// the known on clause from the associations API pub trait JoinWithImplicitOnClause<Rhs, Kind> { type Output: AsQuery; fn join_with_implicit_on_clause(self, rhs: Rhs, kind: Kind) -> Self::Output; } impl<Lhs, Rhs, Kind> JoinWithImplicitOnClause<Rhs, Kind> for Lhs where Lhs: JoinTo<Rhs>, Lhs: InternalJoinDsl<Rhs, Kind, <Lhs as JoinTo<Rhs>>::JoinOnClause>, { type Output = <Lhs as InternalJoinDsl<Rhs, Kind, Lhs::JoinOnClause>>::Output; fn join_with_implicit_on_clause(self, rhs: Rhs, kind: Kind) -> Self::Output { self.join(rhs, kind, Lhs::join_on_clause()) } } /// Methods allowing various joins between two or more tables. /// /// Joining between two tables requires a [`#[belongs_to]` /// association][associations] that defines the relationship. /// /// You can join to as many tables as you'd like in a query, with the /// restriction that no table can appear in the query more than once. The reason /// for this restriction is that one of the appearances would require aliasing, /// and we do not currently have a fleshed out story for dealing with table /// aliases. /// /// You may also need to call [`enable_multi_table_joins!`][] (particularly if /// you see an unexpected error about `AppearsInFromClause`). See the /// documentation for [`enable_multi_table_joins!`][] for details. /// /// Diesel expects multi-table joins to be semantically grouped based on the /// relationships. For example, `users.inner_join(posts.inner_join(comments))` /// is not the same as `users.inner_join(posts).inner_join(comments)`. The first /// would deserialize into `(User, (Post, Comment))` and generate the following /// SQL: /// /// ```sql /// SELECT * FROM users /// INNER JOIN posts ON posts.user_id = users.id /// INNER JOIN comments ON comments.post_id = posts.id /// ``` /// /// While the second query would deserialize into `(User, Post, Comment)` and /// generate the following SQL: /// /// ```sql /// SELECT * FROM users /// INNER JOIN posts ON posts.user_id = users.id /// INNER JOIN comments ON comments.user_id = users.id /// ``` /// /// [associations]: ../associations/index.html /// [`enable_multi_table_joins!`]: ../macro.enable_multi_table_joins.html pub trait JoinDsl: Sized { /// Join two tables using a SQL `INNER JOIN`. The `ON` clause is defined /// via the [associations API](../associations/index.html). fn inner_join<Rhs>(self, rhs: Rhs) -> Self::Output where Self: JoinWithImplicitOnClause<Rhs, joins::Inner>, { self.join_with_implicit_on_clause(rhs, joins::Inner) } /// Join two tables using a SQL `LEFT OUTER JOIN`. The `ON` clause is defined /// via the [associations API](../associations/index.html). fn left_outer_join<Rhs>(self, rhs: Rhs) -> Self::Output where Self: JoinWithImplicitOnClause<Rhs, joins::LeftOuter>, { self.join_with_implicit_on_clause(rhs, joins::LeftOuter) } /// Alias for `left_outer_join` fn left_join<Rhs>(self, rhs: Rhs) -> Self::Output where Self: JoinWithImplicitOnClause<Rhs, joins::LeftOuter>, { self.left_outer_join(rhs) } } impl<T: AsQuery> JoinDsl for T { }