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