grafbase_sql_ast/ast/
join.rs

1use crate::ast::{ConditionTree, Table};
2
3/// The `JOIN` table and conditions.
4#[derive(Debug, PartialEq, Clone)]
5pub struct JoinData<'a> {
6    pub(crate) table: Table<'a>,
7    pub(crate) conditions: ConditionTree<'a>,
8    #[cfg(feature = "postgresql")]
9    pub(crate) lateral: bool,
10}
11
12impl<'a> JoinData<'a> {
13    /// Implement a join with no conditions.
14    pub fn all_from(table: impl Into<Table<'a>>) -> Self {
15        Self {
16            table: table.into(),
17            conditions: ConditionTree::NoCondition,
18            lateral: false,
19        }
20    }
21
22    /// Join as lateral join.
23    pub fn lateral(&mut self) {
24        self.lateral = true;
25    }
26}
27
28impl<'a, T> From<T> for JoinData<'a>
29where
30    T: Into<Table<'a>>,
31{
32    fn from(table: T) -> Self {
33        Self::all_from(table)
34    }
35}
36
37/// A representation of a `JOIN` statement.
38#[derive(Debug, PartialEq, Clone)]
39pub enum Join<'a> {
40    /// Implements an `INNER JOIN` with given `JoinData`.
41    Inner(JoinData<'a>),
42    /// Implements an `LEFT JOIN` with given `JoinData`.
43    Left(JoinData<'a>),
44    /// Implements an `RIGHT JOIN` with given `JoinData`.
45    Right(JoinData<'a>),
46    /// Implements an `FULL JOIN` with given `JoinData`.
47    Full(JoinData<'a>),
48}
49
50/// An item that can be joined.
51pub trait Joinable<'a> {
52    /// Add the `JOIN` conditions.
53    fn on<T>(self, conditions: T) -> JoinData<'a>
54    where
55        T: Into<ConditionTree<'a>>;
56}
57
58impl<'a, U> Joinable<'a> for U
59where
60    U: Into<Table<'a>>,
61{
62    fn on<T>(self, conditions: T) -> JoinData<'a>
63    where
64        T: Into<ConditionTree<'a>>,
65    {
66        JoinData {
67            table: self.into(),
68            conditions: conditions.into(),
69            lateral: false,
70        }
71    }
72}
73
74impl<'a> Joinable<'a> for JoinData<'a> {
75    fn on<T>(self, conditions: T) -> JoinData<'a>
76    where
77        T: Into<ConditionTree<'a>>,
78    {
79        let conditions = match self.conditions {
80            ConditionTree::NoCondition => conditions.into(),
81            cond => cond.and(conditions.into()),
82        };
83
84        JoinData {
85            table: self.table,
86            conditions,
87            lateral: false,
88        }
89    }
90}