chain_builder/query/join/
join_methods.rs

1//! JOIN methods for building JOIN clauses
2
3use super::{JoinBuilder, JoinStatement};
4use crate::query::QueryBuilder;
5use serde_json::Value;
6
7/// Trait for JOIN operations
8pub trait JoinMethods {
9    /// Add a JOIN clause
10    fn join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
11
12    /// Add an INNER JOIN clause
13    fn inner_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
14
15    /// Add a LEFT JOIN clause
16    fn left_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
17
18    /// Add a RIGHT JOIN clause
19    fn right_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
20
21    /// Add a LEFT OUTER JOIN clause
22    fn left_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
23
24    /// Add a RIGHT OUTER JOIN clause
25    fn right_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
26
27    /// Add a FULL OUTER JOIN clause
28    fn full_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
29
30    /// Add a CROSS JOIN clause
31    fn cross_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder));
32
33    /// Add a JOIN USING clause
34    fn join_using(&mut self, table: &str, columns: Vec<String>);
35
36    /// Add a raw JOIN clause
37    fn raw_join(&mut self, raw: &str, val: Option<Vec<Value>>);
38}
39
40impl JoinMethods for QueryBuilder {
41    fn join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
42        let mut join = JoinBuilder {
43            table: table.to_string(),
44            statement: vec![],
45            join_type: "JOIN".into(),
46            raw: None,
47            as_name: None,
48        };
49        on(&mut join);
50        self.join.push(join);
51    }
52
53    fn inner_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
54        let mut join = JoinBuilder {
55            table: table.to_string(),
56            statement: vec![],
57            join_type: "INNER JOIN".into(),
58            raw: None,
59            as_name: None,
60        };
61        on(&mut join);
62        self.join.push(join);
63    }
64
65    fn left_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
66        let mut join = JoinBuilder {
67            table: table.to_string(),
68            statement: vec![],
69            join_type: "LEFT JOIN".into(),
70            raw: None,
71            as_name: None,
72        };
73        on(&mut join);
74        self.join.push(join);
75    }
76
77    fn right_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
78        let mut join = JoinBuilder {
79            table: table.to_string(),
80            statement: vec![],
81            join_type: "RIGHT JOIN".into(),
82            raw: None,
83            as_name: None,
84        };
85        on(&mut join);
86        self.join.push(join);
87    }
88
89    fn left_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
90        let mut join = JoinBuilder {
91            table: table.to_string(),
92            statement: vec![],
93            join_type: "LEFT OUTER JOIN".into(),
94            raw: None,
95            as_name: None,
96        };
97        on(&mut join);
98        self.join.push(join);
99    }
100
101    fn right_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
102        let mut join = JoinBuilder {
103            table: table.to_string(),
104            statement: vec![],
105            join_type: "RIGHT OUTER JOIN".into(),
106            raw: None,
107            as_name: None,
108        };
109        on(&mut join);
110        self.join.push(join);
111    }
112
113    fn cross_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
114        let mut join = JoinBuilder {
115            table: table.to_string(),
116            statement: vec![],
117            join_type: "CROSS JOIN".into(),
118            raw: None,
119            as_name: None,
120        };
121        on(&mut join);
122        self.join.push(join);
123    }
124
125    fn full_outer_join(&mut self, table: &str, on: impl FnOnce(&mut JoinBuilder)) {
126        let mut join = JoinBuilder {
127            table: table.to_string(),
128            statement: vec![],
129            join_type: "FULL OUTER JOIN".into(),
130            raw: None,
131            as_name: None,
132        };
133        on(&mut join);
134        self.join.push(join);
135    }
136
137    fn join_using(&mut self, table: &str, columns: Vec<String>) {
138        let columns_str = columns.join(", ");
139        let sql = format!("JOIN {} USING ({})", table, columns_str);
140        self.raw_join(&sql, None);
141    }
142
143    fn raw_join(&mut self, raw: &str, val: Option<Vec<Value>>) {
144        self.join.push(JoinBuilder {
145            table: raw.to_string(),
146            statement: vec![],
147            join_type: "".into(),
148            raw: Some((raw.to_string(), val)),
149            as_name: None,
150        });
151    }
152}
153
154impl JoinBuilder {
155    /// Set table alias
156    pub fn as_name(&mut self, name: &str) -> &mut Self {
157        self.as_name = Some(name.to_string());
158        self
159    }
160
161    /// Add ON condition with column comparison
162    pub fn on(&mut self, column: &str, operator: &str, column2: &str) -> &mut Self {
163        self.statement.push(JoinStatement::On(
164            column.to_string(),
165            operator.to_string(),
166            column2.to_string(),
167        ));
168        self
169    }
170
171    /// Start an OR chain for complex JOIN conditions
172    pub fn or(&mut self) -> &mut JoinBuilder {
173        let mut chain = self.clone();
174        chain.statement = vec![];
175        self.statement.push(JoinStatement::OrChain(Box::new(chain)));
176        // SAFETY: unwrap() is safe because we just pushed an OrChain
177        self.statement.last_mut().unwrap().as_mut_join_builder()
178    }
179
180    /// Add ON condition with value comparison
181    pub fn on_val(&mut self, column: &str, operator: &str, value: Value) -> &mut Self {
182        self.statement.push(JoinStatement::OnVal(
183            column.to_string(),
184            operator.to_string(),
185            value,
186        ));
187        self
188    }
189
190    /// Add raw ON condition
191    pub fn on_raw(&mut self, raw: &str, val: Option<Vec<Value>>) -> &mut Self {
192        self.statement
193            .push(JoinStatement::OnRaw(raw.to_string(), val));
194        self
195    }
196}