1use super::{AppearsInFromClause, Plus, QueryRelation};
2use crate::backend::Backend;
3use crate::backend::DieselReserveSpecialization;
4use crate::expression::grouped::Grouped;
5use crate::expression::nullable::Nullable;
6use crate::prelude::*;
7use crate::query_builder::*;
8use crate::query_dsl::InternalJoinDsl;
9use crate::sql_types::BoolOrNullableBool;
10use crate::util::TupleAppend;
11
12pub struct Join<Left: QuerySource, Right: QuerySource, Kind> {
14 left: FromClause<Left>,
15 right: FromClause<Right>,
16 kind: Kind,
17}
18
19impl<Left, Right, Kind> Clone for Join<Left, Right, Kind>
20where
21 Left: QuerySource,
22 FromClause<Left>: Clone,
23 Right: QuerySource,
24 FromClause<Right>: Clone,
25 Kind: Clone,
26{
27 fn clone(&self) -> Self {
28 Self {
29 left: self.left.clone(),
30 right: self.right.clone(),
31 kind: self.kind.clone(),
32 }
33 }
34}
35
36impl<Left, Right, Kind> Copy for Join<Left, Right, Kind>
37where
38 Left: QuerySource,
39 FromClause<Left>: Copy,
40 Right: QuerySource,
41 FromClause<Right>: Copy,
42 Kind: Copy,
43{
44}
45
46impl<Left, Right, Kind> std::fmt::Debug for Join<Left, Right, Kind>
47where
48 Left: QuerySource,
49 FromClause<Left>: std::fmt::Debug,
50 Right: QuerySource,
51 FromClause<Right>: std::fmt::Debug,
52 Kind: std::fmt::Debug,
53{
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("Join")
56 .field("left", &self.left)
57 .field("right", &self.right)
58 .field("kind", &self.kind)
59 .finish()
60 }
61}
62
63impl<Left, Right, Kind> QueryId for Join<Left, Right, Kind>
64where
65 Left: QueryId + QuerySource + 'static,
66 Right: QueryId + QuerySource + 'static,
67 Kind: QueryId,
68{
69 type QueryId = Join<Left, Right, Kind::QueryId>;
70
71 const HAS_STATIC_QUERY_ID: bool =
72 Left::HAS_STATIC_QUERY_ID && Right::HAS_STATIC_QUERY_ID && Kind::HAS_STATIC_QUERY_ID;
73}
74
75#[derive(#[automatically_derived]
impl<Join: ::core::fmt::Debug, On: ::core::fmt::Debug> ::core::fmt::Debug for
JoinOn<Join, On> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "JoinOn",
"join", &self.join, "on", &&self.on)
}
}Debug, #[automatically_derived]
impl<Join: ::core::clone::Clone, On: ::core::clone::Clone>
::core::clone::Clone for JoinOn<Join, On> {
#[inline]
fn clone(&self) -> JoinOn<Join, On> {
JoinOn {
join: ::core::clone::Clone::clone(&self.join),
on: ::core::clone::Clone::clone(&self.on),
}
}
}Clone, #[automatically_derived]
impl<Join: ::core::marker::Copy, On: ::core::marker::Copy>
::core::marker::Copy for JoinOn<Join, On> {
}Copy, const _: () =
{
use diesel;
#[allow(non_camel_case_types)]
impl<Join: diesel::query_builder::QueryId,
On: diesel::query_builder::QueryId> diesel::query_builder::QueryId
for JoinOn<Join, On> {
type QueryId =
JoinOn<<Join as diesel::query_builder::QueryId>::QueryId,
<On as diesel::query_builder::QueryId>::QueryId>;
const HAS_STATIC_QUERY_ID: bool =
<Join as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID
&&
<On as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID
&& true;
const IS_WINDOW_FUNCTION: bool =
<Join as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
||
<On as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
|| false;
}
};QueryId)]
76#[doc(hidden)]
77pub struct JoinOn<Join, On> {
81 join: Join,
82 on: On,
83}
84
85impl<Left, Right, Kind> Join<Left, Right, Kind>
86where
87 Left: QuerySource,
88 Right: QuerySource,
89{
90 pub(crate) fn new(left: Left, right: Right, kind: Kind) -> Self {
91 Join {
92 left: FromClause::new(left),
93 right: FromClause::new(right),
94 kind,
95 }
96 }
97
98 pub(crate) fn on<On>(self, on: On) -> JoinOn<Self, On> {
99 JoinOn { join: self, on: on }
100 }
101}
102
103impl<Left, Right> QuerySource for Join<Left, Right, Inner>
104where
105 Left: QuerySource + AppendSelection<Right::DefaultSelection>,
106 Right: QuerySource,
107 Left::Output: AppearsOnTable<Self>,
108 Self: Clone,
109{
110 type FromClause = Self;
111 type DefaultSelection = self::private::SkipSelectableExpressionBoundCheckWrapper<Left::Output>;
119
120 fn from_clause(&self) -> Self::FromClause {
121 self.clone()
122 }
123
124 fn default_selection(&self) -> Self::DefaultSelection {
125 self::private::SkipSelectableExpressionBoundCheckWrapper(
126 self.left
127 .source
128 .append_selection(self.right.source.default_selection()),
129 )
130 }
131}
132
133impl<Left, Right> QuerySource for Join<Left, Right, LeftOuter>
134where
135 Left: QuerySource + AppendSelection<Nullable<Right::DefaultSelection>>,
136 Right: QuerySource,
137 Left::Output: AppearsOnTable<Self>,
138 Self: Clone,
139{
140 type FromClause = Self;
141 type DefaultSelection = self::private::SkipSelectableExpressionBoundCheckWrapper<Left::Output>;
149
150 fn from_clause(&self) -> Self::FromClause {
151 self.clone()
152 }
153
154 fn default_selection(&self) -> Self::DefaultSelection {
155 self::private::SkipSelectableExpressionBoundCheckWrapper(
156 self.left
157 .source
158 .append_selection(self.right.source.default_selection().nullable()),
159 )
160 }
161}
162
163#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OnKeyword {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "OnKeyword")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for OnKeyword {
#[inline]
fn clone(&self) -> OnKeyword { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OnKeyword { }Copy)]
164pub struct OnKeyword;
165
166impl<DB: Backend> nodes::MiddleFragment<DB> for OnKeyword {
167 fn push_sql(&self, mut pass: AstPass<'_, '_, DB>) {
168 pass.push_sql(" ON ");
169 }
170}
171
172impl<Join, On> QuerySource for JoinOn<Join, On>
173where
174 Join: QuerySource,
175 On: AppearsOnTable<Join::FromClause> + Clone,
176 On::SqlType: BoolOrNullableBool,
177 Join::DefaultSelection: SelectableExpression<Self>,
178{
179 type FromClause = Grouped<nodes::InfixNode<Join::FromClause, On, OnKeyword>>;
180 type DefaultSelection = Join::DefaultSelection;
181
182 fn from_clause(&self) -> Self::FromClause {
183 Grouped(nodes::InfixNode::new(
184 self.join.from_clause(),
185 self.on.clone(),
186 OnKeyword,
187 ))
188 }
189
190 fn default_selection(&self) -> Self::DefaultSelection {
191 self.join.default_selection()
192 }
193}
194
195impl<Left, Right, Kind, DB> QueryFragment<DB> for Join<Left, Right, Kind>
196where
197 DB: Backend + DieselReserveSpecialization,
198 Left: QuerySource,
199 Left::FromClause: QueryFragment<DB>,
200 Right: QuerySource,
201 Right::FromClause: QueryFragment<DB>,
202 Kind: QueryFragment<DB>,
203{
204 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
205 self.left.from_clause.walk_ast(out.reborrow())?;
206 self.kind.walk_ast(out.reborrow())?;
207 out.push_sql(" JOIN ");
208 self.right.from_clause.walk_ast(out.reborrow())?;
209 Ok(())
210 }
211}
212
213#[diagnostic::on_unimplemented(
227 message = "cannot join `{T}` to `{Self}` due to missing relation",
228 note = "joining tables directly either requires a `diesel::joinable!` definition \
229 or calling `JoinOnDsl::on` to manually specify the `ON` clause of the join`"
230)]
231pub trait JoinTo<T> {
232 #[doc(hidden)]
233 type FromClause;
234 #[doc(hidden)]
235 type OnClause;
236 #[doc(hidden)]
237 fn join_target(rhs: T) -> (Self::FromClause, Self::OnClause);
238}
239
240#[doc(hidden)]
241pub trait AppendSelection<Selection> {
246 type Output;
247
248 fn append_selection(&self, selection: Selection) -> Self::Output;
249}
250
251impl<T, Selection> AppendSelection<Selection> for T
252where
253 T: QueryRelation,
254{
255 type Output = (T::AllColumns, Selection);
256
257 fn append_selection(&self, selection: Selection) -> Self::Output {
258 (T::all_columns(), selection)
259 }
260}
261
262impl<Left, Mid, Selection, Kind> AppendSelection<Selection> for Join<Left, Mid, Kind>
263where
264 Left: QuerySource,
265 Mid: QuerySource,
266 Self: QuerySource,
267 <Self as QuerySource>::DefaultSelection: TupleAppend<Selection>,
268{
269 type Output = <<Self as QuerySource>::DefaultSelection as TupleAppend<Selection>>::Output;
270
271 fn append_selection(&self, selection: Selection) -> Self::Output {
272 self.default_selection().tuple_append(selection)
273 }
274}
275
276impl<Join, On, Selection> AppendSelection<Selection> for JoinOn<Join, On>
277where
278 Join: AppendSelection<Selection>,
279{
280 type Output = Join::Output;
281
282 fn append_selection(&self, selection: Selection) -> Self::Output {
283 self.join.append_selection(selection)
284 }
285}
286
287#[doc(hidden)]
288#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Inner {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Inner")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Inner {
#[inline]
fn clone(&self) -> Inner { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Inner { }Copy, #[automatically_derived]
impl ::core::default::Default for Inner {
#[inline]
fn default() -> Inner { Inner {} }
}Default, const _: () =
{
use diesel;
#[allow(non_camel_case_types)]
impl diesel::query_builder::QueryId for Inner {
type QueryId = Inner<>;
const HAS_STATIC_QUERY_ID: bool = true;
const IS_WINDOW_FUNCTION: bool = false;
}
};QueryId)]
289pub struct Inner;
290
291impl<DB> QueryFragment<DB> for Inner
292where
293 DB: Backend + DieselReserveSpecialization,
294{
295 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
296 out.push_sql(" INNER");
297 Ok(())
298 }
299}
300
301#[doc(hidden)]
302#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LeftOuter {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "LeftOuter")
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for LeftOuter {
#[inline]
fn clone(&self) -> LeftOuter { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for LeftOuter { }Copy, #[automatically_derived]
impl ::core::default::Default for LeftOuter {
#[inline]
fn default() -> LeftOuter { LeftOuter {} }
}Default, const _: () =
{
use diesel;
#[allow(non_camel_case_types)]
impl diesel::query_builder::QueryId for LeftOuter {
type QueryId = LeftOuter<>;
const HAS_STATIC_QUERY_ID: bool = true;
const IS_WINDOW_FUNCTION: bool = false;
}
};QueryId)]
303pub struct LeftOuter;
304
305impl<DB> QueryFragment<DB> for LeftOuter
306where
307 DB: Backend + DieselReserveSpecialization,
308{
309 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
310 out.push_sql(" LEFT OUTER");
311 Ok(())
312 }
313}
314
315impl<Left, Mid, Right, Kind> JoinTo<Right> for Join<Left, Mid, Kind>
316where
317 Left: JoinTo<Right> + QuerySource,
318 Mid: QuerySource,
319{
320 type FromClause = <Left as JoinTo<Right>>::FromClause;
321 type OnClause = Left::OnClause;
322
323 fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
324 Left::join_target(rhs)
325 }
326}
327
328impl<Join, On, Right> JoinTo<Right> for JoinOn<Join, On>
329where
330 Join: JoinTo<Right>,
331{
332 type FromClause = Join::FromClause;
333 type OnClause = Join::OnClause;
334
335 fn join_target(rhs: Right) -> (Self::FromClause, Self::OnClause) {
336 Join::join_target(rhs)
337 }
338}
339
340impl<T, Left, Right, Kind> AppearsInFromClause<T> for Join<Left, Right, Kind>
341where
342 Left: AppearsInFromClause<T> + QuerySource,
343 Right: AppearsInFromClause<T> + QuerySource,
344 Left::Count: Plus<Right::Count>,
345{
346 type Count = <Left::Count as Plus<Right::Count>>::Output;
347}
348
349impl<T, Join, On> AppearsInFromClause<T> for JoinOn<Join, On>
350where
351 Join: AppearsInFromClause<T>,
352{
353 type Count = Join::Count;
354}
355
356#[doc(hidden)]
357#[derive(#[automatically_derived]
impl<Source: ::core::fmt::Debug, On: ::core::fmt::Debug> ::core::fmt::Debug
for OnClauseWrapper<Source, On> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"OnClauseWrapper", "source", &self.source, "on", &&self.on)
}
}Debug, #[automatically_derived]
impl<Source: ::core::clone::Clone, On: ::core::clone::Clone>
::core::clone::Clone for OnClauseWrapper<Source, On> {
#[inline]
fn clone(&self) -> OnClauseWrapper<Source, On> {
OnClauseWrapper {
source: ::core::clone::Clone::clone(&self.source),
on: ::core::clone::Clone::clone(&self.on),
}
}
}Clone, #[automatically_derived]
impl<Source: ::core::marker::Copy, On: ::core::marker::Copy>
::core::marker::Copy for OnClauseWrapper<Source, On> {
}Copy)]
358pub struct OnClauseWrapper<Source, On> {
359 pub(crate) source: Source,
360 pub(crate) on: On,
361}
362
363impl<Source, On> OnClauseWrapper<Source, On> {
364 pub fn new(source: Source, on: On) -> Self {
365 OnClauseWrapper { source, on }
366 }
367}
368
369impl<Lhs, Rhs, On> JoinTo<OnClauseWrapper<Rhs, On>> for Lhs
370where
371 Lhs: QueryRelation,
372{
373 type FromClause = Rhs;
374 type OnClause = On;
375
376 fn join_target(rhs: OnClauseWrapper<Rhs, On>) -> (Self::FromClause, Self::OnClause) {
377 (rhs.source, rhs.on)
378 }
379}
380
381impl<Lhs, Rhs, On> JoinTo<Rhs> for OnClauseWrapper<Lhs, On>
382where
383 Lhs: JoinTo<Rhs>,
384{
385 type FromClause = <Lhs as JoinTo<Rhs>>::FromClause;
386 type OnClause = <Lhs as JoinTo<Rhs>>::OnClause;
387
388 fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
389 <Lhs as JoinTo<Rhs>>::join_target(rhs)
390 }
391}
392
393impl<Rhs, Kind, On1, On2, Lhs> InternalJoinDsl<Rhs, Kind, On1> for OnClauseWrapper<Lhs, On2>
394where
395 Lhs: InternalJoinDsl<Rhs, Kind, On1>,
396{
397 type Output = OnClauseWrapper<<Lhs as InternalJoinDsl<Rhs, Kind, On1>>::Output, On2>;
398
399 fn join(self, rhs: Rhs, kind: Kind, on: On1) -> Self::Output {
400 OnClauseWrapper {
401 source: self.source.join(rhs, kind, on),
402 on: self.on,
403 }
404 }
405}
406
407impl<Qs, On> QueryDsl for OnClauseWrapper<Qs, On> {}
408
409#[doc(hidden)]
410pub trait ToInnerJoin {
418 type InnerJoin;
419}
420
421impl<Left, Right, Kind> ToInnerJoin for Join<Left, Right, Kind>
422where
423 Left: ToInnerJoin + QuerySource,
424 Left::InnerJoin: QuerySource,
425 Right: ToInnerJoin + QuerySource,
426 Right::InnerJoin: QuerySource,
427{
428 type InnerJoin = Join<Left::InnerJoin, Right::InnerJoin, Inner>;
429}
430
431impl<Join, On> ToInnerJoin for JoinOn<Join, On>
432where
433 Join: ToInnerJoin,
434{
435 type InnerJoin = JoinOn<Join::InnerJoin, On>;
436}
437
438impl<From> ToInnerJoin for SelectStatement<FromClause<From>>
439where
440 From: ToInnerJoin + QuerySource,
441 From::InnerJoin: QuerySource,
442{
443 type InnerJoin = SelectStatement<FromClause<From::InnerJoin>>;
444}
445
446impl<T: Table> ToInnerJoin for T {
447 type InnerJoin = T;
448}
449
450mod private {
451 use crate::backend::Backend;
452 use crate::expression::{Expression, ValidGrouping};
453 use crate::query_builder::{AstPass, QueryFragment, SelectClauseExpression};
454 use crate::{AppearsOnTable, QueryResult, SelectableExpression};
455
456 #[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for
SkipSelectableExpressionBoundCheckWrapper<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"SkipSelectableExpressionBoundCheckWrapper", &&self.0)
}
}Debug, const _: () =
{
use diesel;
#[allow(non_camel_case_types)]
impl<T: diesel::query_builder::QueryId> diesel::query_builder::QueryId
for SkipSelectableExpressionBoundCheckWrapper<T> {
type QueryId =
SkipSelectableExpressionBoundCheckWrapper<<T as
diesel::query_builder::QueryId>::QueryId>;
const HAS_STATIC_QUERY_ID: bool =
<T as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
true;
const IS_WINDOW_FUNCTION: bool =
<T as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION ||
false;
}
};crate::query_builder::QueryId, #[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for
SkipSelectableExpressionBoundCheckWrapper<T> {
}Copy, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for
SkipSelectableExpressionBoundCheckWrapper<T> {
#[inline]
fn clone(&self) -> SkipSelectableExpressionBoundCheckWrapper<T> {
SkipSelectableExpressionBoundCheckWrapper(::core::clone::Clone::clone(&self.0))
}
}Clone)]
457 pub struct SkipSelectableExpressionBoundCheckWrapper<T>(pub(super) T);
458
459 impl<DB, T> QueryFragment<DB> for SkipSelectableExpressionBoundCheckWrapper<T>
460 where
461 T: QueryFragment<DB>,
462 DB: Backend,
463 {
464 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
465 self.0.walk_ast(pass)
466 }
467 }
468
469 impl<T> ValidGrouping<()> for SkipSelectableExpressionBoundCheckWrapper<T> {
472 type IsAggregate = crate::expression::is_aggregate::No;
473 }
474
475 impl<QS, T> SelectClauseExpression<QS> for SkipSelectableExpressionBoundCheckWrapper<T>
477 where
478 T: SelectClauseExpression<QS>,
479 {
480 type Selection = T::Selection;
481
482 type SelectClauseSqlType = T::SelectClauseSqlType;
483 }
484
485 impl<QS, T> SelectableExpression<QS> for SkipSelectableExpressionBoundCheckWrapper<T> where
490 Self: AppearsOnTable<QS>
491 {
492 }
493
494 impl<QS, T> AppearsOnTable<QS> for SkipSelectableExpressionBoundCheckWrapper<T> where
495 Self: Expression
496 {
497 }
498
499 impl<T> Expression for SkipSelectableExpressionBoundCheckWrapper<T>
502 where
503 T: Expression,
504 {
505 type SqlType = T::SqlType;
506 }
507
508 impl<T, Selection> crate::util::TupleAppend<Selection>
509 for SkipSelectableExpressionBoundCheckWrapper<T>
510 where
511 T: crate::util::TupleAppend<Selection>,
512 {
513 type Output = T::Output;
515
516 fn tuple_append(self, right: Selection) -> Self::Output {
517 self.0.tuple_append(right)
518 }
519 }
520}