grafbase_sql_ast/ast/select.rs
1use std::borrow::Cow;
2
3use super::{
4 Column, CommonTableExpression, ConditionTree, Expression, ExpressionKind, Grouping,
5 IntoGroupByDefinition, IntoOrderDefinition, Join, JoinData, Ordering, Query, Table,
6};
7
8type Type<'a> = ConditionTree<'a>;
9
10/// A builder for a `SELECT` statement.
11#[derive(Debug, PartialEq, Clone, Default)]
12pub struct Select<'a> {
13 pub(crate) ctes: Vec<CommonTableExpression<'a>>,
14 pub(crate) distinct: bool,
15 pub(crate) tables: Vec<Table<'a>>,
16 pub(crate) columns: Vec<Expression<'a>>,
17 pub(crate) conditions: Option<ConditionTree<'a>>,
18 pub(crate) ordering: Ordering<'a>,
19 pub(crate) grouping: Grouping<'a>,
20 pub(crate) having: Option<Type<'a>>,
21 pub(crate) limit: Option<u32>,
22 pub(crate) offset: Option<u32>,
23 pub(crate) joins: Vec<Join<'a>>,
24 pub(crate) comment: Option<Cow<'a, str>>,
25}
26
27impl<'a> From<Select<'a>> for Expression<'a> {
28 fn from(sel: Select<'a>) -> Expression<'a> {
29 Expression {
30 kind: ExpressionKind::Selection(Box::new(sel)),
31 alias: None,
32 }
33 }
34}
35
36impl<'a> From<Select<'a>> for Query<'a> {
37 fn from(sel: Select<'a>) -> Query<'a> {
38 Query::Select(Box::new(sel))
39 }
40}
41
42impl<'a> Select<'a> {
43 /// Creates a new `SELECT` statement for the given table.
44 ///
45 /// ```rust
46 /// # use grafbase_sql_ast::{ast::*, renderer::{self, Renderer}};
47 /// # fn main() {
48 /// let query = Select::from_table("users");
49 /// let (sql, _) = renderer::Postgres::build(query);
50 ///
51 /// assert_eq!(r#"SELECT "users".* FROM "users""#, sql);
52 /// # }
53 /// ```
54 ///
55 /// The table can be in multiple parts, defining the schema.
56 ///
57 /// ```rust
58 /// # use grafbase_sql_ast::{ast::*, renderer::{self, Renderer}};
59 /// # fn main() {
60 /// let query = Select::from_table(("crm", "users"));
61 /// let (sql, _) = renderer::Postgres::build(query);
62 ///
63 /// assert_eq!(r#"SELECT "crm"."users".* FROM "crm"."users""#, sql);
64 /// # }
65 /// ```
66 ///
67 /// Selecting from a nested `SELECT`.
68 ///
69 /// ```rust
70 /// # use grafbase_sql_ast::{ast::*, renderer::{self, Renderer}};
71 /// # fn main() {
72 /// let mut inner_select = Select::default();
73 /// inner_select.value(1);
74 ///
75 /// let select = Table::from(inner_select).alias("num");
76 /// let query = Select::from_table(select.alias("num"));
77 /// let (sql, params) = renderer::Postgres::build(query);
78 ///
79 /// assert_eq!(r#"SELECT "num".* FROM (SELECT $1) AS "num""#, sql);
80 /// assert_eq!(vec![Value::from(1)], params);
81 /// # }
82 /// ```
83 pub fn from_table<T>(table: T) -> Self
84 where
85 T: Into<Table<'a>>,
86 {
87 Select {
88 tables: vec![table.into()],
89 ..Select::default()
90 }
91 }
92
93 /// Adds a table to be selected.
94 ///
95 /// ```rust
96 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
97 /// # fn main() {
98 /// let mut query = Select::from_table("users");
99 ///
100 /// let mut inner_select = Select::default();
101 /// inner_select.value(1);
102 ///
103 /// query.and_from(Table::from(inner_select).alias("num"));
104 /// query.column(("users", "name"));
105 /// query.value(Table::from("num").asterisk());
106 ///
107 /// let (sql, _) = renderer::Postgres::build(query);
108 ///
109 /// assert_eq!(r#"SELECT "users"."name", "num".* FROM "users", (SELECT $1) AS "num""#, sql);
110 /// # }
111 /// ```
112 pub fn and_from<T>(&mut self, table: T)
113 where
114 T: Into<Table<'a>>,
115 {
116 self.tables.push(table.into());
117 }
118
119 /// Selects a static value as the column.
120 ///
121 /// ```rust
122 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
123 /// # fn main() {
124 /// let mut query = Select::default();
125 /// query.value(1);
126 ///
127 /// let (sql, params) = renderer::Postgres::build(query);
128 ///
129 /// assert_eq!("SELECT $1", sql);
130 /// assert_eq!(vec![Value::from(1)], params);
131 /// # }
132 /// ```
133 pub fn value<T>(&mut self, value: T)
134 where
135 T: Into<Expression<'a>>,
136 {
137 self.columns.push(value.into());
138 }
139
140 /// Adds a column to be selected.
141 ///
142 /// ```rust
143 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
144 /// # fn main() {
145 /// let mut query = Select::from_table("users");
146 ///
147 /// query.column("name");
148 /// query.column(("users", "id"));
149 /// query.column((("crm", "users"), "foo"));
150 ///
151 /// let (sql, _) = renderer::Postgres::build(query);
152 ///
153 /// assert_eq!(r#"SELECT "name", "users"."id", "crm"."users"."foo" FROM "users""#, sql);
154 /// # }
155 /// ```
156 pub fn column<T>(&mut self, column: T)
157 where
158 T: Into<Column<'a>>,
159 {
160 self.columns.push(column.into().into());
161 }
162
163 /// A bulk method to select multiple values.
164 ///
165 /// ```rust
166 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
167 /// # fn main() {
168 /// let mut query = Select::from_table("users");
169 /// query.columns(["foo", "bar"]);
170 ///
171 /// let (sql, _) = renderer::Postgres::build(query);
172 ///
173 /// assert_eq!(r#"SELECT "foo", "bar" FROM "users""#, sql);
174 /// # }
175 /// ```
176 pub fn columns<T, C>(&mut self, columns: T)
177 where
178 T: IntoIterator<Item = C>,
179 C: Into<Column<'a>>,
180 {
181 self.columns = columns.into_iter().map(|c| c.into().into()).collect();
182 }
183
184 /// Adds `DISTINCT` to the select query.
185 ///
186 /// ```rust
187 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
188 /// # fn main() {
189 /// let mut query = Select::from_table("users");
190 ///
191 /// query.column("foo");
192 /// query.column("bar");
193 /// query.distinct();
194 ///
195 /// let (sql, _) = renderer::Postgres::build(query);
196 ///
197 /// assert_eq!(r#"SELECT DISTINCT "foo", "bar" FROM "users""#, sql);
198 /// # }
199 /// ```
200 pub fn distinct(&mut self) {
201 self.distinct = true;
202 }
203
204 /// Adds `WHERE` conditions to the query, replacing the previous conditions.
205 /// See [Comparable](trait.Comparable.html#required-methods) for more
206 /// examples.
207 ///
208 /// ```rust
209 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
210 /// # fn main() {
211 /// let mut query = Select::from_table("users");
212 /// query.so_that("foo".equals("bar"));
213 ///
214 /// let (sql, params) = renderer::Postgres::build(query);
215 ///
216 /// assert_eq!(r#"SELECT "users".* FROM "users" WHERE "foo" = $1"#, sql);
217 ///
218 /// assert_eq!(vec![
219 /// Value::from("bar"),
220 /// ], params);
221 /// # }
222 /// ```
223 pub fn so_that<T>(&mut self, conditions: T)
224 where
225 T: Into<ConditionTree<'a>>,
226 {
227 self.conditions = Some(conditions.into());
228 }
229
230 /// Adds an additional `WHERE` condition to the query combining the possible
231 /// previous condition with `AND`. See
232 /// [Comparable](trait.Comparable.html#required-methods) for more examples.
233 ///
234 /// ```rust
235 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
236 /// # fn main() {
237 /// let mut query = Select::from_table("users");
238 ///
239 /// query.so_that("foo".equals("bar"));
240 /// query.and_where("lol".equals("wtf"));
241 ///
242 /// let (sql, params) = renderer::Postgres::build(query);
243 ///
244 /// assert_eq!(r#"SELECT "users".* FROM "users" WHERE ("foo" = $1 AND "lol" = $2)"#, sql);
245 ///
246 /// assert_eq!(vec![
247 /// Value::from("bar"),
248 /// Value::from("wtf"),
249 /// ], params);
250 /// # }
251 /// ```
252 pub fn and_where<T>(&mut self, conditions: T)
253 where
254 T: Into<ConditionTree<'a>>,
255 {
256 match self.conditions.take() {
257 Some(previous) => {
258 self.conditions = Some(previous.and(conditions.into()));
259 }
260 None => self.so_that(conditions),
261 }
262 }
263
264 /// Adds an additional `WHERE` condition to the query combining the possible
265 /// previous condition with `OR`. See
266 /// [Comparable](trait.Comparable.html#required-methods) for more examples.
267 ///
268 /// ```rust
269 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
270 /// # fn main() {
271 /// let mut query = Select::from_table("users");
272 ///
273 /// query.so_that("foo".equals("bar"));
274 /// query.or_where("lol".equals("wtf"));
275 ///
276 /// let (sql, params) = renderer::Postgres::build(query);
277 ///
278 /// assert_eq!(r#"SELECT "users".* FROM "users" WHERE ("foo" = $1 OR "lol" = $2)"#, sql);
279 ///
280 /// assert_eq!(vec![
281 /// Value::from("bar"),
282 /// Value::from("wtf"),
283 /// ], params);
284 /// # }
285 /// ```
286 pub fn or_where<T>(&mut self, conditions: T)
287 where
288 T: Into<ConditionTree<'a>>,
289 {
290 match self.conditions.take() {
291 Some(previous) => {
292 self.conditions = Some(previous.or(conditions.into()));
293 }
294 None => self.so_that(conditions),
295 }
296 }
297
298 /// Adds `INNER JOIN` clause to the query.
299 ///
300 /// ```rust
301 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
302 /// # fn main() {
303 /// let join = Table::from("posts")
304 /// .alias("p")
305 /// .on(("p", "user_id").equals(Column::from(("users", "id"))));
306 ///
307 /// let mut query = Select::from_table("users");
308 /// query.inner_join(join);
309 ///
310 /// let (sql, _) = renderer::Postgres::build(query);
311 ///
312 /// assert_eq!(
313 /// r#"SELECT "users".* FROM "users" INNER JOIN "posts" AS "p" ON "p"."user_id" = "users"."id""#,
314 /// sql
315 /// );
316 /// # }
317 /// ```
318 pub fn inner_join<J>(&mut self, join: J)
319 where
320 J: Into<JoinData<'a>>,
321 {
322 self.joins.push(Join::Inner(join.into()));
323 }
324
325 /// Adds `LEFT JOIN` clause to the query.
326 ///
327 /// ```rust
328 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
329 /// # fn main() {
330 /// let join = Table::from("posts")
331 /// .alias("p")
332 /// .on(("p", "visible").equals(true));
333 ///
334 /// let mut query = Select::from_table("users");
335 /// query.left_join(join);
336 ///
337 /// let (sql, params) = renderer::Postgres::build(query);
338 ///
339 /// assert_eq!(
340 /// r#"SELECT "users".* FROM "users" LEFT JOIN "posts" AS "p" ON "p"."visible" = $1"#,
341 /// sql
342 /// );
343 ///
344 /// assert_eq!(
345 /// vec![
346 /// Value::from(true),
347 /// ],
348 /// params
349 /// );
350 /// # }
351 /// ```
352 pub fn left_join<J>(&mut self, join: J)
353 where
354 J: Into<JoinData<'a>>,
355 {
356 self.joins.push(Join::Left(join.into()));
357 }
358
359 /// Adds `RIGHT JOIN` clause to the query.
360 ///
361 /// ```rust
362 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
363 /// # fn main() {
364 /// let join = Table::from("posts")
365 /// .alias("p")
366 /// .on(("p", "visible").equals(true));
367 ///
368 ///
369 /// let mut query = Select::from_table("users");
370 /// query.right_join(join);
371 ///
372 /// let (sql, params) = renderer::Postgres::build(query);
373 ///
374 /// assert_eq!(
375 /// r#"SELECT "users".* FROM "users" RIGHT JOIN "posts" AS "p" ON "p"."visible" = $1"#,
376 /// sql
377 /// );
378 ///
379 /// assert_eq!(
380 /// vec![
381 /// Value::from(true),
382 /// ],
383 /// params
384 /// );
385 /// # }
386 /// ```
387 pub fn right_join<J>(&mut self, join: J)
388 where
389 J: Into<JoinData<'a>>,
390 {
391 self.joins.push(Join::Right(join.into()));
392 }
393
394 /// Adds `FULL JOIN` clause to the query.
395 ///
396 /// ```rust
397 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
398 /// # fn main() {
399 /// let join = Table::from("posts")
400 /// .alias("p")
401 /// .on(("p", "visible").equals(true));
402 ///
403 /// let mut query = Select::from_table("users");
404 /// query.full_join(join);
405 ///
406 /// let (sql, params) = renderer::Postgres::build(query);
407 ///
408 /// assert_eq!(
409 /// r#"SELECT "users".* FROM "users" FULL JOIN "posts" AS "p" ON "p"."visible" = $1"#,
410 /// sql
411 /// );
412 ///
413 /// assert_eq!(
414 /// vec![
415 /// Value::from(true),
416 /// ],
417 /// params
418 /// );
419 /// # }
420 /// ```
421 pub fn full_join<J>(&mut self, join: J)
422 where
423 J: Into<JoinData<'a>>,
424 {
425 self.joins.push(Join::Full(join.into()));
426 }
427
428 /// Adds an ordering to the `ORDER BY` section.
429 ///
430 /// ```rust
431 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
432 /// # fn main() {
433 /// let mut query = Select::from_table("users");
434 /// query.order_by("foo");
435 /// query.order_by("baz".ascend());
436 /// query.order_by("bar".descend());
437 ///
438 /// let (sql, _) = renderer::Postgres::build(query);
439 ///
440 /// assert_eq!(r#"SELECT "users".* FROM "users" ORDER BY "foo", "baz" ASC, "bar" DESC"#, sql);
441 /// # }
442 pub fn order_by<T>(&mut self, value: T)
443 where
444 T: IntoOrderDefinition<'a>,
445 {
446 self.ordering.append(value.into_order_definition());
447 }
448
449 /// Adds a grouping to the `GROUP BY` section.
450 ///
451 /// This does not check if the grouping is actually valid in respect to aggregated columns.
452 ///
453 /// ```rust
454 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
455 /// # fn main() {
456 /// let mut query = Select::from_table("users");
457 ///
458 /// query.column("foo");
459 /// query.column("bar");
460 /// query.group_by("foo");
461 /// query.group_by("bar");
462 ///
463 /// let (sql, _) = renderer::Postgres::build(query);
464 ///
465 /// assert_eq!(r#"SELECT "foo", "bar" FROM "users" GROUP BY "foo", "bar""#, sql);
466 /// # }
467 pub fn group_by<T>(&mut self, value: T)
468 where
469 T: IntoGroupByDefinition<'a>,
470 {
471 self.grouping.append(value.into_group_by_definition());
472 }
473
474 /// Adds group conditions to a query. Should be combined together with a
475 /// [group_by](struct.Select.html#method.group_by) statement.
476 ///
477 /// ```rust
478 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
479 /// # fn main() {
480 /// let mut query = Select::from_table("users");
481 ///
482 /// query.column("foo");
483 /// query.column("bar");
484 /// query.group_by("foo");
485 /// query.having("foo".greater_than(100));
486 ///
487 /// let (sql, params) = renderer::Postgres::build(query);
488 ///
489 /// assert_eq!(r#"SELECT "foo", "bar" FROM "users" GROUP BY "foo" HAVING "foo" > $1"#, sql);
490 /// assert_eq!(vec![Value::from(100)], params);
491 /// # }
492 pub fn having<T>(&mut self, conditions: T)
493 where
494 T: Into<ConditionTree<'a>>,
495 {
496 self.having = Some(conditions.into());
497 }
498
499 /// Sets the `LIMIT` value.
500 ///
501 /// ```rust
502 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
503 /// # fn main() {
504 /// let mut query = Select::from_table("users");
505 /// query.limit(10);
506 ///
507 /// let (sql, params) = renderer::Postgres::build(query);
508 ///
509 /// assert_eq!(r#"SELECT "users".* FROM "users" LIMIT $1"#, sql);
510 /// assert_eq!(vec![Value::from(10_i64)], params);
511 /// # }
512 pub fn limit(&mut self, limit: u32) {
513 self.limit = Some(limit);
514 }
515
516 /// Sets the `OFFSET` value.
517 ///
518 /// ```rust
519 /// # use grafbase_sql_ast::{ast::*, renderer::{Renderer, self}};
520 /// # fn main() {
521 /// let mut query = Select::from_table("users");
522 /// query.offset(10);
523 ///
524 /// let (sql, params) = renderer::Postgres::build(query);
525 ///
526 /// assert_eq!(r#"SELECT "users".* FROM "users" OFFSET $1"#, sql);
527 /// assert_eq!(vec![Value::from(10_i64)], params);
528 /// # }
529 pub fn offset(&mut self, offset: u32) {
530 self.offset = Some(offset);
531 }
532
533 /// Adds a common table expression to the select.
534 pub fn with(&mut self, cte: CommonTableExpression<'a>) {
535 self.ctes.push(cte);
536 }
537}