Skip to main content

reinhardt_query/query/
select.rs

1//! SELECT statement builder
2//!
3//! This module provides the `SelectStatement` type for building SQL SELECT queries.
4
5use crate::{
6	expr::{Condition, ConditionHolder, IntoCondition, SimpleExpr},
7	types::{
8		ColumnRef, DynIden, IntoColumnRef, IntoIden, IntoTableRef, JoinExpr, JoinType, Order,
9		OrderExpr, TableRef, WindowStatement,
10	},
11	value::{IntoValue, Value, Values},
12};
13
14use super::traits::{QueryBuilderTrait, QueryStatementBuilder, QueryStatementWriter};
15
16/// SELECT statement builder
17///
18/// This struct provides a fluent API for constructing SELECT queries.
19///
20/// # Examples
21///
22/// ```rust,ignore
23/// use reinhardt_query::prelude::*;
24///
25/// let query = Query::select()
26///     .column(Expr::col("id"))
27///     .column(Expr::col("name"))
28///     .from("users")
29///     .and_where(Expr::col("active").eq(true))
30///     .order_by("name", Order::Asc)
31///     .limit(10);
32/// ```
33#[derive(Debug, Clone, Default)]
34pub struct SelectStatement {
35	pub(crate) raw_sql: Option<String>,
36	pub(crate) ctes: Vec<CommonTableExpr>,
37	pub(crate) distinct: Option<SelectDistinct>,
38	pub(crate) selects: Vec<SelectExpr>,
39	pub(crate) from: Vec<TableRef>,
40	pub(crate) join: Vec<JoinExpr>,
41	pub(crate) r#where: ConditionHolder,
42	pub(crate) groups: Vec<SimpleExpr>,
43	pub(crate) having: ConditionHolder,
44	pub(crate) unions: Vec<(UnionType, SelectStatement)>,
45	pub(crate) orders: Vec<OrderExpr>,
46	pub(crate) limit: Option<Value>,
47	pub(crate) offset: Option<Value>,
48	pub(crate) lock: Option<LockClause>,
49	pub(crate) windows: Vec<(DynIden, WindowStatement)>,
50}
51
52/// Common Table Expression (CTE) for WITH clause
53///
54/// This represents a single CTE in a WITH clause.
55#[derive(Debug, Clone)]
56pub struct CommonTableExpr {
57	/// CTE name (alias)
58	pub(crate) name: DynIden,
59	/// CTE query
60	pub(crate) query: Box<SelectStatement>,
61	/// Whether this is a RECURSIVE CTE
62	pub(crate) recursive: bool,
63}
64
65/// List of distinct keywords that can be used in select statement
66#[derive(Debug, Clone)]
67#[non_exhaustive]
68pub enum SelectDistinct {
69	/// SELECT ALL
70	All,
71	/// SELECT DISTINCT
72	Distinct,
73	/// SELECT DISTINCTROW (MySQL)
74	DistinctRow,
75	/// SELECT DISTINCT ON (PostgreSQL)
76	DistinctOn(Vec<ColumnRef>),
77}
78
79/// Select expression used in select statement.
80#[derive(Debug, Clone)]
81pub struct SelectExpr {
82	/// The expression to select.
83	pub expr: SimpleExpr,
84	/// Optional alias for the expression (AS clause).
85	pub alias: Option<DynIden>,
86}
87
88/// List of lock types that can be used in select statement
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90#[non_exhaustive]
91pub enum LockType {
92	/// FOR UPDATE
93	Update,
94	/// FOR NO KEY UPDATE (PostgreSQL)
95	NoKeyUpdate,
96	/// FOR SHARE
97	Share,
98	/// FOR KEY SHARE (PostgreSQL)
99	KeyShare,
100}
101
102/// List of lock behavior can be used in select statement
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104#[non_exhaustive]
105pub enum LockBehavior {
106	/// NOWAIT
107	Nowait,
108	/// SKIP LOCKED
109	SkipLocked,
110}
111
112/// Lock clause for SELECT ... FOR UPDATE/SHARE
113// NOTE: Fields are currently unused because FOR UPDATE/SHARE is not yet implemented
114#[allow(dead_code)]
115#[derive(Debug, Clone)]
116pub struct LockClause {
117	pub(crate) r#type: LockType,
118	pub(crate) tables: Vec<TableRef>,
119	pub(crate) behavior: Option<LockBehavior>,
120}
121
122/// List of union types that can be used in union clause
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124#[non_exhaustive]
125pub enum UnionType {
126	/// INTERSECT
127	Intersect,
128	/// UNION
129	Distinct,
130	/// EXCEPT
131	Except,
132	/// UNION ALL
133	All,
134}
135
136impl<T> From<T> for SelectExpr
137where
138	T: Into<SimpleExpr>,
139{
140	fn from(expr: T) -> Self {
141		SelectExpr {
142			expr: expr.into(),
143			alias: None,
144		}
145	}
146}
147
148impl SelectStatement {
149	/// Create a new SELECT statement
150	pub fn new() -> Self {
151		Self::default()
152	}
153
154	/// Create a statement backed by an already-rendered SQL query.
155	pub fn raw(sql: impl Into<String>) -> Self {
156		Self {
157			raw_sql: Some(sql.into()),
158			..Self::default()
159		}
160	}
161
162	/// Take the ownership of data in the current [`SelectStatement`]
163	pub fn take(&mut self) -> Self {
164		Self {
165			raw_sql: self.raw_sql.take(),
166			ctes: std::mem::take(&mut self.ctes),
167			distinct: self.distinct.take(),
168			selects: std::mem::take(&mut self.selects),
169			from: std::mem::take(&mut self.from),
170			join: std::mem::take(&mut self.join),
171			r#where: std::mem::replace(&mut self.r#where, ConditionHolder::new()),
172			groups: std::mem::take(&mut self.groups),
173			having: std::mem::replace(&mut self.having, ConditionHolder::new()),
174			unions: std::mem::take(&mut self.unions),
175			orders: std::mem::take(&mut self.orders),
176			limit: self.limit.take(),
177			offset: self.offset.take(),
178			lock: self.lock.take(),
179			windows: std::mem::take(&mut self.windows),
180		}
181	}
182
183	/// Remove all FROM sources from the statement.
184	pub fn clear_from(&mut self) -> &mut Self {
185		self.from.clear();
186		self
187	}
188
189	// Column selection methods
190
191	/// Add a column to the SELECT clause
192	///
193	/// # Examples
194	///
195	/// ```rust,ignore
196	/// use reinhardt_query::prelude::*;
197	///
198	/// let query = Query::select()
199	///     .column("id")
200	///     .column("name")
201	///     .from("users");
202	/// ```
203	pub fn column<C>(&mut self, col: C) -> &mut Self
204	where
205		C: IntoColumnRef,
206	{
207		self.selects.push(SelectExpr {
208			expr: SimpleExpr::Column(col.into_column_ref()),
209			alias: None,
210		});
211		self
212	}
213
214	/// Add multiple columns to the SELECT clause
215	///
216	/// # Examples
217	///
218	/// ```rust,ignore
219	/// use reinhardt_query::prelude::*;
220	///
221	/// let query = Query::select()
222	///     .columns(["id", "name", "email"])
223	///     .from("users");
224	/// ```
225	pub fn columns<I, C>(&mut self, cols: I) -> &mut Self
226	where
227		I: IntoIterator<Item = C>,
228		C: IntoColumnRef,
229	{
230		for col in cols {
231			self.column(col);
232		}
233		self
234	}
235
236	/// Add an expression to the SELECT clause
237	///
238	/// # Examples
239	///
240	/// ```rust,ignore
241	/// use reinhardt_query::prelude::*;
242	///
243	/// let query = Query::select()
244	///     .expr(Expr::col("price").mul(Expr::col("quantity")))
245	///     .from("orders");
246	/// ```
247	pub fn expr<E>(&mut self, expr: E) -> &mut Self
248	where
249		E: Into<SimpleExpr>,
250	{
251		self.selects.push(SelectExpr {
252			expr: expr.into(),
253			alias: None,
254		});
255		self
256	}
257
258	/// Add an expression with an alias to the SELECT clause
259	///
260	/// # Examples
261	///
262	/// ```rust,ignore
263	/// use reinhardt_query::prelude::*;
264	///
265	/// let query = Query::select()
266	///     .expr_as(Expr::col("price").mul(Expr::col("quantity")), "total")
267	///     .from("orders");
268	/// ```
269	pub fn expr_as<E, A>(&mut self, expr: E, alias: A) -> &mut Self
270	where
271		E: Into<SimpleExpr>,
272		A: IntoIden,
273	{
274		self.selects.push(SelectExpr {
275			expr: expr.into(),
276			alias: Some(alias.into_iden()),
277		});
278		self
279	}
280
281	// FROM clause methods
282
283	/// Add a table to the FROM clause
284	///
285	/// # Examples
286	///
287	/// ```rust,ignore
288	/// use reinhardt_query::prelude::*;
289	///
290	/// let query = Query::select()
291	///     .column("id")
292	///     .from("users");
293	/// ```
294	pub fn from<T>(&mut self, tbl: T) -> &mut Self
295	where
296		T: IntoTableRef,
297	{
298		self.from.push(tbl.into_table_ref());
299		self
300	}
301
302	/// Add a table with alias to the FROM clause
303	///
304	/// Equivalent to `FROM table AS alias`.
305	pub fn from_as<T, A>(&mut self, tbl: T, alias: A) -> &mut Self
306	where
307		T: IntoIden,
308		A: IntoIden,
309	{
310		self.from
311			.push(TableRef::TableAlias(tbl.into_iden(), alias.into_iden()));
312		self
313	}
314
315	/// Add a subquery to the FROM clause
316	///
317	/// Equivalent to `FROM (SELECT ...) AS alias`.
318	pub fn from_subquery(&mut self, query: SelectStatement, alias: impl IntoIden) -> &mut Self {
319		self.from
320			.push(TableRef::SubQuery(Box::new(query), alias.into_iden()));
321		self
322	}
323
324	/// Clear all column selections
325	pub fn clear_selects(&mut self) -> &mut Self {
326		self.selects.clear();
327		self
328	}
329
330	// JOIN clause methods
331
332	/// Add a JOIN clause
333	///
334	/// # Examples
335	///
336	/// ```rust,ignore
337	/// use reinhardt_query::prelude::*;
338	///
339	/// let query = Query::select()
340	///     .from("users")
341	///     .join(
342	///         JoinType::InnerJoin,
343	///         "orders",
344	///         Expr::col(("users", "id")).equals(("orders", "user_id"))
345	///     );
346	/// ```
347	pub fn join<T, C>(&mut self, join: JoinType, tbl: T, condition: C) -> &mut Self
348	where
349		T: IntoTableRef,
350		C: IntoCondition,
351	{
352		self.join.push(JoinExpr {
353			join,
354			table: tbl.into_table_ref(),
355			on: Some(crate::types::JoinOn::Condition(condition.into_condition())),
356		});
357		self
358	}
359
360	/// Add a LEFT JOIN clause
361	///
362	/// # Examples
363	///
364	/// ```rust,ignore
365	/// use reinhardt_query::prelude::*;
366	///
367	/// let query = Query::select()
368	///     .from("users")
369	///     .left_join(
370	///         "orders",
371	///         Expr::col(("users", "id")).equals(("orders", "user_id"))
372	///     );
373	/// ```
374	pub fn left_join<T, C>(&mut self, tbl: T, condition: C) -> &mut Self
375	where
376		T: IntoTableRef,
377		C: IntoCondition,
378	{
379		self.join(JoinType::LeftJoin, tbl, condition)
380	}
381
382	/// Add a RIGHT JOIN clause
383	pub fn right_join<T, C>(&mut self, tbl: T, condition: C) -> &mut Self
384	where
385		T: IntoTableRef,
386		C: IntoCondition,
387	{
388		self.join(JoinType::RightJoin, tbl, condition)
389	}
390
391	/// Add a FULL OUTER JOIN clause
392	pub fn full_outer_join<T, C>(&mut self, tbl: T, condition: C) -> &mut Self
393	where
394		T: IntoTableRef,
395		C: IntoCondition,
396	{
397		self.join(JoinType::FullOuterJoin, tbl, condition)
398	}
399
400	/// Add an INNER JOIN clause
401	pub fn inner_join<T, C>(&mut self, tbl: T, condition: C) -> &mut Self
402	where
403		T: IntoTableRef,
404		C: IntoCondition,
405	{
406		self.join(JoinType::InnerJoin, tbl, condition)
407	}
408
409	/// Add a CROSS JOIN clause
410	pub fn cross_join<T>(&mut self, tbl: T) -> &mut Self
411	where
412		T: IntoTableRef,
413	{
414		self.join.push(JoinExpr {
415			join: JoinType::CrossJoin,
416			table: tbl.into_table_ref(),
417			on: None,
418		});
419		self
420	}
421
422	// WHERE clause methods
423
424	/// Add a condition to the WHERE clause
425	///
426	/// # Examples
427	///
428	/// ```rust,ignore
429	/// use reinhardt_query::prelude::*;
430	///
431	/// let query = Query::select()
432	///     .from("users")
433	///     .and_where(Expr::col("active").eq(true));
434	/// ```
435	pub fn and_where<C>(&mut self, condition: C) -> &mut Self
436	where
437		C: IntoCondition,
438	{
439		self.r#where.add_and(condition);
440		self
441	}
442
443	/// Add a condition to the WHERE clause using Condition
444	pub fn cond_where(&mut self, condition: Condition) -> &mut Self {
445		self.r#where.add_and(condition);
446		self
447	}
448
449	// GROUP BY clause methods
450
451	/// Add a GROUP BY clause
452	///
453	/// # Examples
454	///
455	/// ```rust,ignore
456	/// use reinhardt_query::prelude::*;
457	///
458	/// let query = Query::select()
459	///     .column("category")
460	///     .expr_as(Expr::count("*"), "count")
461	///     .from("products")
462	///     .group_by("category");
463	/// ```
464	pub fn group_by<C>(&mut self, col: C) -> &mut Self
465	where
466		C: IntoColumnRef,
467	{
468		self.groups.push(SimpleExpr::Column(col.into_column_ref()));
469		self
470	}
471
472	/// Add a column to the GROUP BY clause (alias for `group_by`)
473	pub fn group_by_col<C>(&mut self, col: C) -> &mut Self
474	where
475		C: IntoColumnRef,
476	{
477		self.group_by(col)
478	}
479
480	/// Add multiple GROUP BY columns
481	pub fn group_by_columns<I, C>(&mut self, cols: I) -> &mut Self
482	where
483		I: IntoIterator<Item = C>,
484		C: IntoColumnRef,
485	{
486		for col in cols {
487			self.group_by(col);
488		}
489		self
490	}
491
492	// HAVING clause methods
493
494	/// Add a condition to the HAVING clause
495	///
496	/// # Examples
497	///
498	/// ```rust,ignore
499	/// use reinhardt_query::prelude::*;
500	///
501	/// let query = Query::select()
502	///     .column("category")
503	///     .expr_as(Expr::count("*"), "count")
504	///     .from("products")
505	///     .group_by("category")
506	///     .and_having(Expr::count("*").gt(5));
507	/// ```
508	pub fn and_having<C>(&mut self, condition: C) -> &mut Self
509	where
510		C: IntoCondition,
511	{
512		self.having.add_and(condition);
513		self
514	}
515
516	/// Add a condition to the HAVING clause using Condition
517	pub fn cond_having(&mut self, condition: Condition) -> &mut Self {
518		self.having.add_and(condition);
519		self
520	}
521
522	// ORDER BY clause methods
523
524	/// Add an ORDER BY clause
525	///
526	/// # Examples
527	///
528	/// ```rust,ignore
529	/// use reinhardt_query::prelude::*;
530	///
531	/// let query = Query::select()
532	///     .from("users")
533	///     .order_by("name", Order::Asc)
534	///     .order_by("created_at", Order::Desc);
535	/// ```
536	pub fn order_by<C>(&mut self, col: C, order: Order) -> &mut Self
537	where
538		C: IntoColumnRef,
539	{
540		use crate::types::OrderExprKind;
541		self.orders.push(OrderExpr {
542			expr: OrderExprKind::Expr(Box::new(SimpleExpr::Column(col.into_column_ref()))),
543			order,
544			nulls: None,
545		});
546		self
547	}
548
549	/// Add an ORDER BY clause with expression
550	pub fn order_by_expr<E>(&mut self, expr: E, order: Order) -> &mut Self
551	where
552		E: Into<SimpleExpr>,
553	{
554		use crate::types::OrderExprKind;
555		self.orders.push(OrderExpr {
556			expr: OrderExprKind::Expr(Box::new(expr.into())),
557			order,
558			nulls: None,
559		});
560		self
561	}
562
563	// LIMIT and OFFSET methods
564
565	/// Set the LIMIT clause
566	///
567	/// # Examples
568	///
569	/// ```rust,ignore
570	/// use reinhardt_query::prelude::*;
571	///
572	/// let query = Query::select()
573	///     .from("users")
574	///     .limit(10);
575	/// ```
576	pub fn limit<V>(&mut self, limit: V) -> &mut Self
577	where
578		V: IntoValue,
579	{
580		self.limit = Some(limit.into_value());
581		self
582	}
583
584	/// Set the OFFSET clause
585	///
586	/// # Examples
587	///
588	/// ```rust,ignore
589	/// use reinhardt_query::prelude::*;
590	///
591	/// let query = Query::select()
592	///     .from("users")
593	///     .limit(10)
594	///     .offset(20);
595	/// ```
596	pub fn offset<V>(&mut self, offset: V) -> &mut Self
597	where
598		V: IntoValue,
599	{
600		self.offset = Some(offset.into_value());
601		self
602	}
603
604	// DISTINCT methods
605
606	/// Set DISTINCT
607	///
608	/// # Examples
609	///
610	/// ```rust,ignore
611	/// use reinhardt_query::prelude::*;
612	///
613	/// let query = Query::select()
614	///     .distinct()
615	///     .column("category")
616	///     .from("products");
617	/// ```
618	pub fn distinct(&mut self) -> &mut Self {
619		self.distinct = Some(SelectDistinct::Distinct);
620		self
621	}
622
623	/// Set DISTINCT ON (PostgreSQL only)
624	pub fn distinct_on<I, C>(&mut self, cols: I) -> &mut Self
625	where
626		I: IntoIterator<Item = C>,
627		C: IntoColumnRef,
628	{
629		let cols: Vec<ColumnRef> = cols.into_iter().map(|c| c.into_column_ref()).collect();
630		self.distinct = Some(SelectDistinct::DistinctOn(cols));
631		self
632	}
633
634	/// Clear DISTINCT from a statement before a backend-specific row lock.
635	pub fn clear_distinct(&mut self) -> &mut Self {
636		self.distinct = None;
637		self
638	}
639
640	// UNION methods
641
642	/// Add a UNION clause
643	pub fn union(&mut self, query: SelectStatement) -> &mut Self {
644		self.unions.push((UnionType::Distinct, query));
645		self
646	}
647
648	/// Add a UNION ALL clause
649	pub fn union_all(&mut self, query: SelectStatement) -> &mut Self {
650		self.unions.push((UnionType::All, query));
651		self
652	}
653
654	/// Add an INTERSECT clause
655	pub fn intersect(&mut self, query: SelectStatement) -> &mut Self {
656		self.unions.push((UnionType::Intersect, query));
657		self
658	}
659
660	/// Add an EXCEPT clause
661	pub fn except(&mut self, query: SelectStatement) -> &mut Self {
662		self.unions.push((UnionType::Except, query));
663		self
664	}
665
666	// WITH (CTE) methods
667
668	/// Add a Common Table Expression (CTE) to the WITH clause
669	///
670	/// # Examples
671	///
672	/// ```rust,ignore
673	/// use reinhardt_query::prelude::*;
674	///
675	/// let cte = Query::select()
676	///     .column("id")
677	///     .column("name")
678	///     .from("users")
679	///     .and_where(Expr::col("active").eq(true));
680	///
681	/// let query = Query::select()
682	///     .with_cte("active_users", cte)
683	///     .column("*")
684	///     .from("active_users");
685	/// ```
686	pub fn with_cte<N>(&mut self, name: N, query: SelectStatement) -> &mut Self
687	where
688		N: IntoIden,
689	{
690		self.ctes.push(CommonTableExpr {
691			name: name.into_iden(),
692			query: Box::new(query),
693			recursive: false,
694		});
695		self
696	}
697
698	/// Add a RECURSIVE Common Table Expression (CTE) to the WITH clause
699	///
700	/// # Examples
701	///
702	/// ```rust,ignore
703	/// use reinhardt_query::prelude::*;
704	///
705	/// // Recursive CTE for hierarchical data
706	/// let cte = Query::select()
707	///     .column("id")
708	///     .column("parent_id")
709	///     .column("name")
710	///     .from("categories")
711	///     .and_where(Expr::col("parent_id").is_null())
712	///     .union_all(
713	///         Query::select()
714	///             .column(Expr::col(("c", "id")))
715	///             .column(Expr::col(("c", "parent_id")))
716	///             .column(Expr::col(("c", "name")))
717	///             .from_as("categories", "c")
718	///             .join(
719	///                 JoinType::InnerJoin,
720	///                 "category_tree",
721	///                 Expr::col(("c", "parent_id")).eq(Expr::col(("category_tree", "id")))
722	///             )
723	///     );
724	///
725	/// let query = Query::select()
726	///     .with_recursive_cte("category_tree", cte)
727	///     .column("*")
728	///     .from("category_tree");
729	/// ```
730	pub fn with_recursive_cte<N>(&mut self, name: N, query: SelectStatement) -> &mut Self
731	where
732		N: IntoIden,
733	{
734		self.ctes.push(CommonTableExpr {
735			name: name.into_iden(),
736			query: Box::new(query),
737			recursive: true,
738		});
739		self
740	}
741
742	// WINDOW methods
743
744	/// Add a named window specification to the WINDOW clause
745	///
746	/// Named windows can be referenced by window functions using `OVER window_name`.
747	///
748	/// # Examples
749	///
750	/// ```rust,ignore
751	/// use reinhardt_query::prelude::*;
752	/// use reinhardt_query::types::window::WindowStatement;
753	///
754	/// let window = WindowStatement {
755	///     partition_by: vec![Expr::col("department_id").into_simple_expr()],
756	///     order_by: vec![OrderExpr {
757	///         expr: Expr::col("salary").into_simple_expr(),
758	///         order: Order::Desc,
759	///         nulls: None,
760	///     }],
761	///     frame: None,
762	/// };
763	///
764	/// let query = Query::select()
765	///     .column("name")
766	///     .expr_as(Expr::row_number().over_named("w"), "rank")
767	///     .from("employees")
768	///     .window_as("w", window);
769	/// ```
770	pub fn window_as<T>(&mut self, name: T, window: WindowStatement) -> &mut Self
771	where
772		T: IntoIden,
773	{
774		self.windows.push((name.into_iden(), window));
775		self
776	}
777
778	// LOCK methods
779
780	/// Set FOR UPDATE lock
781	pub fn lock(&mut self, lock_type: LockType) -> &mut Self {
782		self.lock = Some(LockClause {
783			r#type: lock_type,
784			tables: Vec::new(),
785			behavior: None,
786		});
787		self
788	}
789
790	/// Set FOR UPDATE lock
791	pub fn lock_exclusive(&mut self) -> &mut Self {
792		self.lock(LockType::Update)
793	}
794
795	/// Set FOR SHARE lock
796	pub fn lock_shared(&mut self) -> &mut Self {
797		self.lock(LockType::Share)
798	}
799
800	// Utility methods
801
802	/// Apply a function conditionally
803	pub fn apply_if<T, F>(&mut self, val: Option<T>, func: F) -> &mut Self
804	where
805		F: FnOnce(&mut Self, T),
806	{
807		if let Some(val) = val {
808			func(self, val);
809		}
810		self
811	}
812
813	/// Conditional execution
814	pub fn conditions<T, F>(&mut self, b: bool, if_true: T, if_false: F) -> &mut Self
815	where
816		T: FnOnce(&mut Self),
817		F: FnOnce(&mut Self),
818	{
819		if b {
820			if_true(self)
821		} else {
822			if_false(self)
823		}
824		self
825	}
826}
827
828impl QueryStatementBuilder for SelectStatement {
829	fn build_any(&self, query_builder: &dyn QueryBuilderTrait) -> (String, Values) {
830		use crate::backend::{
831			MySqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder,
832		};
833		use std::any::Any;
834
835		let any_builder = query_builder as &dyn Any;
836
837		if let Some(pg) = any_builder.downcast_ref::<PostgresQueryBuilder>() {
838			return pg.build_select(self);
839		}
840
841		if let Some(mysql) = any_builder.downcast_ref::<MySqlQueryBuilder>() {
842			return mysql.build_select(self);
843		}
844
845		if let Some(sqlite) = any_builder.downcast_ref::<SqliteQueryBuilder>() {
846			return sqlite.build_select(self);
847		}
848
849		panic!(
850			"Unsupported query builder type. Use PostgresQueryBuilder, MySqlQueryBuilder, or SqliteQueryBuilder."
851		);
852	}
853}
854
855impl QueryStatementWriter for SelectStatement {}