1
- use super :: { Column , Comparable , ConditionTree , DefaultValue , ExpressionKind , IndexDefinition } ;
1
+ use super :: { Column , Comparable , ConditionTree , DefaultValue , ExpressionKind , IndexDefinition , Join , JoinData } ;
2
2
use crate :: {
3
3
ast:: { Expression , Row , Select , Values } ,
4
4
error:: { Error , ErrorKind } ,
@@ -19,6 +19,7 @@ pub trait Aliasable<'a> {
19
19
/// Either an identifier or a nested query.
20
20
pub enum TableType < ' a > {
21
21
Table ( Cow < ' a , str > ) ,
22
+ JoinedTable ( ( Cow < ' a , str > , Vec < Join < ' a > > ) ) ,
22
23
Query ( Select < ' a > ) ,
23
24
Values ( Values < ' a > ) ,
24
25
}
@@ -126,6 +127,194 @@ impl<'a> Table<'a> {
126
127
127
128
Ok ( result)
128
129
}
130
+
131
+ /// Adds a `LEFT JOIN` clause to the query, specifically for that table.
132
+ /// Useful to positionally add a JOIN clause in case you are selecting from multiple tables.
133
+ ///
134
+ /// ```rust
135
+ /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}};
136
+ /// # fn main() -> Result<(), quaint::error::Error> {
137
+ /// let join = "posts".alias("p").on(("p", "visible").equals(true));
138
+ /// let joined_table = Table::from("users").left_join(join);
139
+ /// let query = Select::from_table(joined_table).and_from("comments");
140
+ /// let (sql, params) = Sqlite::build(query)?;
141
+ ///
142
+ /// assert_eq!(
143
+ /// "SELECT `users`.*, `comments`.* FROM \
144
+ /// `users` LEFT JOIN `posts` AS `p` ON `p`.`visible` = ?, \
145
+ /// `comments`",
146
+ /// sql
147
+ /// );
148
+ ///
149
+ /// assert_eq!(
150
+ /// vec![
151
+ /// Value::from(true),
152
+ /// ],
153
+ /// params
154
+ /// );
155
+ /// # Ok(())
156
+ /// # }
157
+ /// ```
158
+ pub fn left_join < J > ( mut self , join : J ) -> Self
159
+ where
160
+ J : Into < JoinData < ' a > > ,
161
+ {
162
+ match self . typ {
163
+ TableType :: Table ( table_name) => {
164
+ self . typ = TableType :: JoinedTable ( ( table_name, vec ! [ Join :: Left ( join. into( ) ) ] ) )
165
+ }
166
+ TableType :: JoinedTable ( ( _, ref mut joins) ) => joins. push ( Join :: Left ( join. into ( ) ) ) ,
167
+ TableType :: Query ( _) => {
168
+ panic ! ( "You cannot left_join on a table of type Query" )
169
+ }
170
+ TableType :: Values ( _) => {
171
+ panic ! ( "You cannot left_join on a table of type Values" )
172
+ }
173
+ }
174
+
175
+ self
176
+ }
177
+
178
+ /// Adds an `INNER JOIN` clause to the query, specifically for that table.
179
+ /// Useful to positionally add a JOIN clause in case you are selecting from multiple tables.
180
+ ///
181
+ /// ```rust
182
+ /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}};
183
+ /// # fn main() -> Result<(), quaint::error::Error> {
184
+ /// let join = "posts".alias("p").on(("p", "visible").equals(true));
185
+ /// let joined_table = Table::from("users").inner_join(join);
186
+ /// let query = Select::from_table(joined_table).and_from("comments");
187
+ /// let (sql, params) = Sqlite::build(query)?;
188
+ ///
189
+ /// assert_eq!(
190
+ /// "SELECT `users`.*, `comments`.* FROM \
191
+ /// `users` INNER JOIN `posts` AS `p` ON `p`.`visible` = ?, \
192
+ /// `comments`",
193
+ /// sql
194
+ /// );
195
+ ///
196
+ /// assert_eq!(
197
+ /// vec![
198
+ /// Value::from(true),
199
+ /// ],
200
+ /// params
201
+ /// );
202
+ /// # Ok(())
203
+ /// # }
204
+ /// ```
205
+ pub fn inner_join < J > ( mut self , join : J ) -> Self
206
+ where
207
+ J : Into < JoinData < ' a > > ,
208
+ {
209
+ match self . typ {
210
+ TableType :: Table ( table_name) => {
211
+ self . typ = TableType :: JoinedTable ( ( table_name, vec ! [ Join :: Inner ( join. into( ) ) ] ) )
212
+ }
213
+ TableType :: JoinedTable ( ( _, ref mut joins) ) => joins. push ( Join :: Inner ( join. into ( ) ) ) ,
214
+ TableType :: Query ( _) => {
215
+ panic ! ( "You cannot inner_join on a table of type Query" )
216
+ }
217
+ TableType :: Values ( _) => {
218
+ panic ! ( "You cannot inner_join on a table of type Values" )
219
+ }
220
+ }
221
+
222
+ self
223
+ }
224
+
225
+ /// Adds a `RIGHT JOIN` clause to the query, specifically for that table.
226
+ /// Useful to positionally add a JOIN clause in case you are selecting from multiple tables.
227
+ ///
228
+ /// ```rust
229
+ /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}};
230
+ /// # fn main() -> Result<(), quaint::error::Error> {
231
+ /// let join = "posts".alias("p").on(("p", "visible").equals(true));
232
+ /// let joined_table = Table::from("users").right_join(join);
233
+ /// let query = Select::from_table(joined_table).and_from("comments");
234
+ /// let (sql, params) = Sqlite::build(query)?;
235
+ ///
236
+ /// assert_eq!(
237
+ /// "SELECT `users`.*, `comments`.* FROM \
238
+ /// `users` RIGHT JOIN `posts` AS `p` ON `p`.`visible` = ?, \
239
+ /// `comments`",
240
+ /// sql
241
+ /// );
242
+ ///
243
+ /// assert_eq!(
244
+ /// vec![
245
+ /// Value::from(true),
246
+ /// ],
247
+ /// params
248
+ /// );
249
+ /// # Ok(())
250
+ /// # }
251
+ /// ```
252
+ pub fn right_join < J > ( mut self , join : J ) -> Self
253
+ where
254
+ J : Into < JoinData < ' a > > ,
255
+ {
256
+ match self . typ {
257
+ TableType :: Table ( table_name) => {
258
+ self . typ = TableType :: JoinedTable ( ( table_name, vec ! [ Join :: Right ( join. into( ) ) ] ) )
259
+ }
260
+ TableType :: JoinedTable ( ( _, ref mut joins) ) => joins. push ( Join :: Right ( join. into ( ) ) ) ,
261
+ TableType :: Query ( _) => {
262
+ panic ! ( "You cannot right_join on a table of type Query" )
263
+ }
264
+ TableType :: Values ( _) => {
265
+ panic ! ( "You cannot right_join on a table of type Values" )
266
+ }
267
+ }
268
+
269
+ self
270
+ }
271
+
272
+ /// Adds a `FULL JOIN` clause to the query, specifically for that table.
273
+ /// Useful to positionally add a JOIN clause in case you are selecting from multiple tables.
274
+ ///
275
+ /// ```rust
276
+ /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}};
277
+ /// # fn main() -> Result<(), quaint::error::Error> {
278
+ /// let join = "posts".alias("p").on(("p", "visible").equals(true));
279
+ /// let joined_table = Table::from("users").full_join(join);
280
+ /// let query = Select::from_table(joined_table).and_from("comments");
281
+ /// let (sql, params) = Sqlite::build(query)?;
282
+ ///
283
+ /// assert_eq!(
284
+ /// "SELECT `users`.*, `comments`.* FROM \
285
+ /// `users` FULL JOIN `posts` AS `p` ON `p`.`visible` = ?, \
286
+ /// `comments`",
287
+ /// sql
288
+ /// );
289
+ ///
290
+ /// assert_eq!(
291
+ /// vec![
292
+ /// Value::from(true),
293
+ /// ],
294
+ /// params
295
+ /// );
296
+ /// # Ok(())
297
+ /// # }
298
+ /// ```
299
+ pub fn full_join < J > ( mut self , join : J ) -> Self
300
+ where
301
+ J : Into < JoinData < ' a > > ,
302
+ {
303
+ match self . typ {
304
+ TableType :: Table ( table_name) => {
305
+ self . typ = TableType :: JoinedTable ( ( table_name, vec ! [ Join :: Full ( join. into( ) ) ] ) )
306
+ }
307
+ TableType :: JoinedTable ( ( _, ref mut joins) ) => joins. push ( Join :: Full ( join. into ( ) ) ) ,
308
+ TableType :: Query ( _) => {
309
+ panic ! ( "You cannot full_join on a table of type Query" )
310
+ }
311
+ TableType :: Values ( _) => {
312
+ panic ! ( "You cannot full_join on a table of type Values" )
313
+ }
314
+ }
315
+
316
+ self
317
+ }
129
318
}
130
319
131
320
impl < ' a > From < & ' a str > for Table < ' a > {
0 commit comments