drizzle_sqlite/builder/select.rs
1use crate::helpers;
2use crate::traits::SQLiteTable;
3use crate::values::SQLiteValue;
4use drizzle_core::{SQLTable, ToSQL};
5use paste::paste;
6use std::fmt::Debug;
7use std::marker::PhantomData;
8
9// Import the ExecutableState trait
10use super::ExecutableState;
11
12//------------------------------------------------------------------------------
13// Type State Markers
14//------------------------------------------------------------------------------
15
16/// Marker for the initial state of SelectBuilder.
17#[derive(Debug, Clone, Copy, Default)]
18pub struct SelectInitial;
19
20impl SelectInitial {
21 /// Creates a new SelectInitial marker
22 #[inline]
23 pub const fn new() -> Self {
24 Self
25 }
26}
27
28/// Marker for the state after FROM clause
29#[derive(Debug, Clone, Copy, Default)]
30pub struct SelectFromSet;
31
32/// Marker for the state after JOIN clause
33#[derive(Debug, Clone, Copy, Default)]
34pub struct SelectJoinSet;
35
36/// Marker for the state after WHERE clause
37#[derive(Debug, Clone, Copy, Default)]
38pub struct SelectWhereSet;
39
40/// Marker for the state after GROUP BY clause
41#[derive(Debug, Clone, Copy, Default)]
42pub struct SelectGroupSet;
43
44/// Marker for the state after ORDER BY clause
45#[derive(Debug, Clone, Copy, Default)]
46pub struct SelectOrderSet;
47
48/// Marker for the state after LIMIT clause
49#[derive(Debug, Clone, Copy, Default)]
50pub struct SelectLimitSet;
51
52/// Marker for the state after OFFSET clause
53#[derive(Debug, Clone, Copy, Default)]
54pub struct SelectOffsetSet;
55
56/// Marker for the state after set operations (UNION/INTERSECT/EXCEPT)
57#[derive(Debug, Clone, Copy, Default)]
58pub struct SelectSetOpSet;
59
60// Const constructors for all marker types
61impl SelectFromSet {
62 #[inline]
63 pub const fn new() -> Self {
64 Self
65 }
66}
67impl SelectJoinSet {
68 #[inline]
69 pub const fn new() -> Self {
70 Self
71 }
72}
73impl SelectWhereSet {
74 #[inline]
75 pub const fn new() -> Self {
76 Self
77 }
78}
79impl SelectGroupSet {
80 #[inline]
81 pub const fn new() -> Self {
82 Self
83 }
84}
85impl SelectOrderSet {
86 #[inline]
87 pub const fn new() -> Self {
88 Self
89 }
90}
91impl SelectLimitSet {
92 #[inline]
93 pub const fn new() -> Self {
94 Self
95 }
96}
97impl SelectOffsetSet {
98 #[inline]
99 pub const fn new() -> Self {
100 Self
101 }
102}
103impl SelectSetOpSet {
104 #[inline]
105 pub const fn new() -> Self {
106 Self
107 }
108}
109
110#[doc(hidden)]
111macro_rules! join_impl {
112 () => {
113 join_impl!(natural);
114 join_impl!(natural_left);
115 join_impl!(left);
116 join_impl!(left_outer);
117 join_impl!(natural_left_outer);
118 join_impl!(natural_right);
119 join_impl!(right);
120 join_impl!(right_outer);
121 join_impl!(natural_right_outer);
122 join_impl!(natural_full);
123 join_impl!(full);
124 join_impl!(full_outer);
125 join_impl!(natural_full_outer);
126 join_impl!(inner);
127 join_impl!(cross);
128 };
129 ($type:ident) => {
130 paste! {
131 pub fn [<$type _join>]<U: SQLiteTable<'a>>(
132 self,
133 table: U,
134 condition: impl ToSQL<'a, SQLiteValue<'a>>,
135 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
136 SelectBuilder {
137 sql: self.sql.append(helpers::[<$type _join>](table, condition)),
138 schema: PhantomData,
139 state: PhantomData,
140 table: PhantomData,
141 }
142 }
143 }
144 };
145}
146
147// Mark states that can execute queries as implementing the ExecutableState trait
148impl ExecutableState for SelectFromSet {}
149impl ExecutableState for SelectWhereSet {}
150impl ExecutableState for SelectLimitSet {}
151impl ExecutableState for SelectOffsetSet {}
152impl ExecutableState for SelectOrderSet {}
153impl ExecutableState for SelectGroupSet {}
154impl ExecutableState for SelectJoinSet {}
155impl ExecutableState for SelectSetOpSet {}
156
157#[doc(hidden)]
158pub trait AsCteState {}
159
160impl AsCteState for SelectFromSet {}
161impl AsCteState for SelectJoinSet {}
162impl AsCteState for SelectWhereSet {}
163impl AsCteState for SelectGroupSet {}
164impl AsCteState for SelectOrderSet {}
165impl AsCteState for SelectLimitSet {}
166impl AsCteState for SelectOffsetSet {}
167
168//------------------------------------------------------------------------------
169// SelectBuilder Definition
170//------------------------------------------------------------------------------
171
172/// Builds a SELECT query specifically for SQLite.
173///
174/// `SelectBuilder` provides a type-safe, fluent API for constructing SELECT statements
175/// with compile-time verification of query structure and table relationships.
176///
177/// ## Type Parameters
178///
179/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
180/// - `State`: The current builder state, enforcing proper query construction order
181/// - `Table`: The primary table being queried (when applicable)
182///
183/// ## Query Building Flow
184///
185/// 1. Start with `QueryBuilder::select()` to specify columns
186/// 2. Add `from()` to specify the source table
187/// 3. Optionally add joins, conditions, grouping, ordering, and limits
188///
189/// ## Basic Usage
190///
191/// ```rust
192/// # mod drizzle {
193/// # pub mod core { pub use drizzle_core::*; }
194/// # pub mod error { pub use drizzle_core::error::*; }
195/// # pub mod types { pub use drizzle_types::*; }
196/// # pub mod migrations { pub use drizzle_migrations::*; }
197/// # pub use drizzle_types::Dialect;
198/// # pub use drizzle_types as ddl;
199/// # pub mod sqlite {
200/// # pub use drizzle_sqlite::{*, attrs::*};
201/// # pub mod prelude {
202/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
203/// # pub use drizzle_sqlite::{*, attrs::*};
204/// # pub use drizzle_core::*;
205/// # }
206/// # }
207/// # }
208/// use drizzle::sqlite::prelude::*;
209/// use drizzle::sqlite::builder::QueryBuilder;
210///
211/// #[SQLiteTable(name = "users")]
212/// struct User {
213/// #[column(primary)]
214/// id: i32,
215/// name: String,
216/// email: Option<String>,
217/// }
218///
219/// #[derive(SQLiteSchema)]
220/// struct Schema {
221/// user: User,
222/// }
223///
224/// let builder = QueryBuilder::new::<Schema>();
225/// let Schema { user } = Schema::new();
226///
227/// // Basic SELECT
228/// let query = builder.select(user.name).from(user);
229/// assert_eq!(query.to_sql().sql(), r#"SELECT "users"."name" FROM "users""#);
230///
231/// // SELECT with WHERE clause
232/// use drizzle::core::expr::gt;
233/// let query = builder
234/// .select((user.id, user.name))
235/// .from(user)
236/// .r#where(gt(user.id, 10));
237/// assert_eq!(
238/// query.to_sql().sql(),
239/// r#"SELECT "users"."id", "users"."name" FROM "users" WHERE "users"."id" > ?"#
240/// );
241/// ```
242///
243/// ## Advanced Queries
244///
245/// ```rust,no_run
246/// # mod drizzle {
247/// # pub mod core { pub use drizzle_core::*; }
248/// # pub mod error { pub use drizzle_core::error::*; }
249/// # pub mod types { pub use drizzle_types::*; }
250/// # pub mod migrations { pub use drizzle_migrations::*; }
251/// # pub use drizzle_types::Dialect;
252/// # pub use drizzle_types as ddl;
253/// # pub mod sqlite {
254/// # pub use drizzle_sqlite::{*, attrs::*};
255/// # pub mod prelude {
256/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
257/// # pub use drizzle_sqlite::{*, attrs::*};
258/// # pub use drizzle_core::*;
259/// # }
260/// # }
261/// # }
262/// # use drizzle::sqlite::prelude::*;
263/// # use drizzle::core::expr::eq;
264/// # use drizzle::sqlite::builder::QueryBuilder;
265/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
266/// # #[SQLiteTable(name = "posts")] struct Post { #[column(primary)] id: i32, user_id: i32, title: String }
267/// # #[derive(SQLiteSchema)] struct Schema { user: User, post: Post }
268/// # let builder = QueryBuilder::new::<Schema>();
269/// # let Schema { user, post } = Schema::new();
270/// let query = builder
271/// .select((user.name, post.title))
272/// .from(user)
273/// .join(post, eq(user.id, post.user_id));
274/// ```
275///
276/// ```rust,no_run
277/// # mod drizzle {
278/// # pub mod core { pub use drizzle_core::*; }
279/// # pub mod error { pub use drizzle_core::error::*; }
280/// # pub mod types { pub use drizzle_types::*; }
281/// # pub mod migrations { pub use drizzle_migrations::*; }
282/// # pub use drizzle_types::Dialect;
283/// # pub use drizzle_types as ddl;
284/// # pub mod sqlite {
285/// # pub use drizzle_sqlite::{*, attrs::*};
286/// # pub mod prelude {
287/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
288/// # pub use drizzle_sqlite::{*, attrs::*};
289/// # pub use drizzle_core::*;
290/// # }
291/// # }
292/// # }
293/// # use drizzle::sqlite::prelude::*;
294/// # use drizzle::sqlite::builder::QueryBuilder;
295/// # use drizzle::core::OrderBy;
296/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
297/// # #[derive(SQLiteSchema)] struct Schema { user: User }
298/// # let builder = QueryBuilder::new::<Schema>();
299/// # let Schema { user } = Schema::new();
300/// let query = builder
301/// .select(user.name)
302/// .from(user)
303/// .order_by(OrderBy::asc(user.name))
304/// .limit(10);
305/// ```
306pub type SelectBuilder<'a, Schema, State, Table = ()> =
307 super::QueryBuilder<'a, Schema, State, Table>;
308
309//------------------------------------------------------------------------------
310// Initial State Implementation
311//------------------------------------------------------------------------------
312
313impl<'a, S> SelectBuilder<'a, S, SelectInitial> {
314 /// Specifies the table or subquery to select FROM.
315 ///
316 /// This method transitions the builder from the initial state to the FROM state,
317 /// enabling subsequent WHERE, JOIN, ORDER BY, and other clauses.
318 ///
319 /// # Examples
320 ///
321 /// ```rust
322 /// # mod drizzle {
323 /// # pub mod core { pub use drizzle_core::*; }
324 /// # pub mod error { pub use drizzle_core::error::*; }
325 /// # pub mod types { pub use drizzle_types::*; }
326 /// # pub mod migrations { pub use drizzle_migrations::*; }
327 /// # pub use drizzle_types::Dialect;
328 /// # pub use drizzle_types as ddl;
329 /// # pub mod sqlite {
330 /// # pub use drizzle_sqlite::{*, attrs::*};
331 /// # pub mod prelude {
332 /// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
333 /// # pub use drizzle_sqlite::{*, attrs::*};
334 /// # pub use drizzle_core::*;
335 /// # }
336 /// # }
337 /// # }
338 /// # use drizzle::sqlite::prelude::*;
339 /// # use drizzle::sqlite::builder::QueryBuilder;
340 /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
341 /// # #[derive(SQLiteSchema)] struct Schema { user: User }
342 /// # let builder = QueryBuilder::new::<Schema>();
343 /// # let Schema { user } = Schema::new();
344 /// // Select from a table
345 /// let query = builder.select(user.name).from(user);
346 /// assert_eq!(query.to_sql().sql(), r#"SELECT "users"."name" FROM "users""#);
347 /// ```
348 #[inline]
349 pub fn from<T>(self, query: T) -> SelectBuilder<'a, S, SelectFromSet, T>
350 where
351 T: ToSQL<'a, SQLiteValue<'a>>,
352 {
353 let sql = self.sql.append(helpers::from(query));
354 SelectBuilder {
355 sql,
356 schema: PhantomData,
357 state: PhantomData,
358 table: PhantomData,
359 }
360 }
361}
362
363//------------------------------------------------------------------------------
364// Post-FROM State Implementation
365//------------------------------------------------------------------------------
366
367impl<'a, S, T> SelectBuilder<'a, S, SelectFromSet, T> {
368 /// Adds an INNER JOIN clause to the query.
369 ///
370 /// Joins another table to the current query using the specified condition.
371 /// The joined table must be part of the schema and the condition should
372 /// relate columns from both tables.
373 ///
374 /// ```rust
375 /// # mod drizzle {
376 /// # pub mod core { pub use drizzle_core::*; }
377 /// # pub mod error { pub use drizzle_core::error::*; }
378 /// # pub mod types { pub use drizzle_types::*; }
379 /// # pub mod migrations { pub use drizzle_migrations::*; }
380 /// # pub use drizzle_types::Dialect;
381 /// # pub use drizzle_types as ddl;
382 /// # pub mod sqlite {
383 /// # pub use drizzle_sqlite::{*, attrs::*};
384 /// # pub mod prelude {
385 /// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
386 /// # pub use drizzle_sqlite::{*, attrs::*};
387 /// # pub use drizzle_core::*;
388 /// # }
389 /// # }
390 /// # }
391 /// # use drizzle::sqlite::prelude::*;
392 /// # use drizzle::core::expr::eq;
393 /// # use drizzle::sqlite::builder::QueryBuilder;
394 /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
395 /// # #[SQLiteTable(name = "posts")] struct Post { #[column(primary)] id: i32, user_id: i32, title: String }
396 /// # #[derive(SQLiteSchema)] struct Schema { user: User, post: Post }
397 /// # let builder = QueryBuilder::new::<Schema>();
398 /// # let Schema { user, post } = Schema::new();
399 /// let query = builder
400 /// .select((user.name, post.title))
401 /// .from(user)
402 /// .join(post, eq(user.id, post.user_id));
403 /// assert_eq!(
404 /// query.to_sql().sql(),
405 /// r#"SELECT "users"."name", "posts"."title" FROM "users" JOIN "posts" ON "users"."id" = "posts"."user_id""#
406 /// );
407 /// ```
408 #[inline]
409 pub fn join<U: SQLiteTable<'a>>(
410 self,
411 table: U,
412 condition: impl ToSQL<'a, SQLiteValue<'a>>,
413 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
414 SelectBuilder {
415 sql: self.sql.append(helpers::join(table, condition)),
416 schema: PhantomData,
417 state: PhantomData,
418 table: PhantomData,
419 }
420 }
421
422 join_impl!();
423
424 /// Adds a WHERE clause to filter query results.
425 ///
426 /// This method applies conditions to filter the rows returned by the query.
427 /// You can use various condition functions from `drizzle::core::expr::conditions`.
428 ///
429 /// ```rust
430 /// # mod drizzle {
431 /// # pub mod core { pub use drizzle_core::*; }
432 /// # pub mod error { pub use drizzle_core::error::*; }
433 /// # pub mod types { pub use drizzle_types::*; }
434 /// # pub mod migrations { pub use drizzle_migrations::*; }
435 /// # pub use drizzle_types::Dialect;
436 /// # pub use drizzle_types as ddl;
437 /// # pub mod sqlite {
438 /// # pub use drizzle_sqlite::{*, attrs::*};
439 /// # pub mod prelude {
440 /// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
441 /// # pub use drizzle_sqlite::{*, attrs::*};
442 /// # pub use drizzle_core::*;
443 /// # }
444 /// # }
445 /// # }
446 /// # use drizzle::sqlite::prelude::*;
447 /// # use drizzle::core::expr::{gt, and, eq};
448 /// # use drizzle::sqlite::builder::QueryBuilder;
449 /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
450 /// # #[derive(SQLiteSchema)] struct Schema { user: User }
451 /// # let builder = QueryBuilder::new::<Schema>();
452 /// # let Schema { user } = Schema::new();
453 /// // Single condition
454 /// let query = builder
455 /// .select(user.name)
456 /// .from(user)
457 /// .r#where(gt(user.id, 10));
458 /// assert_eq!(
459 /// query.to_sql().sql(),
460 /// r#"SELECT "users"."name" FROM "users" WHERE "users"."id" > ?"#
461 /// );
462 ///
463 /// // Multiple conditions
464 /// let query = builder
465 /// .select(user.name)
466 /// .from(user)
467 /// .r#where(and([gt(user.id, 10), eq(user.name, "Alice")]));
468 /// ```
469 #[inline]
470 pub fn r#where(
471 self,
472 condition: impl ToSQL<'a, SQLiteValue<'a>>,
473 ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
474 SelectBuilder {
475 sql: self.sql.append(helpers::r#where(condition)),
476 schema: PhantomData,
477 state: PhantomData,
478 table: PhantomData,
479 }
480 }
481
482 /// Adds a GROUP BY clause to the query
483 pub fn group_by(
484 self,
485 expressions: impl IntoIterator<Item = impl ToSQL<'a, SQLiteValue<'a>>>,
486 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
487 SelectBuilder {
488 sql: self.sql.append(helpers::group_by(expressions)),
489 schema: PhantomData,
490 state: PhantomData,
491 table: PhantomData,
492 }
493 }
494
495 /// Limits the number of rows returned
496 #[inline]
497 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
498 SelectBuilder {
499 sql: self.sql.append(helpers::limit(limit)),
500 schema: PhantomData,
501 state: PhantomData,
502 table: PhantomData,
503 }
504 }
505
506 /// Sets the offset for the query results
507 #[inline]
508 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
509 SelectBuilder {
510 sql: self.sql.append(helpers::offset(offset)),
511 schema: PhantomData,
512 state: PhantomData,
513 table: PhantomData,
514 }
515 }
516
517 /// Sorts the query results
518 #[inline]
519 pub fn order_by<TOrderBy>(
520 self,
521 expressions: TOrderBy,
522 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
523 where
524 TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
525 {
526 SelectBuilder {
527 sql: self.sql.append(helpers::order_by(expressions)),
528 schema: PhantomData,
529 state: PhantomData,
530 table: PhantomData,
531 }
532 }
533}
534
535//------------------------------------------------------------------------------
536// Post-JOIN State Implementation
537//------------------------------------------------------------------------------
538
539impl<'a, S, T> SelectBuilder<'a, S, SelectJoinSet, T> {
540 /// Adds a WHERE condition after a JOIN
541 #[inline]
542 pub fn r#where(
543 self,
544 condition: impl ToSQL<'a, SQLiteValue<'a>>,
545 ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
546 SelectBuilder {
547 sql: self.sql.append(crate::helpers::r#where(condition)),
548 schema: PhantomData,
549 state: PhantomData,
550 table: PhantomData,
551 }
552 }
553 /// Sorts the query results
554 #[inline]
555 pub fn order_by<TOrderBy>(
556 self,
557 expressions: TOrderBy,
558 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
559 where
560 TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
561 {
562 SelectBuilder {
563 sql: self.sql.append(helpers::order_by(expressions)),
564 schema: PhantomData,
565 state: PhantomData,
566 table: PhantomData,
567 }
568 }
569 /// Adds a JOIN clause to the query
570 #[inline]
571 pub fn join<U: SQLiteTable<'a>>(
572 self,
573 table: U,
574 condition: impl ToSQL<'a, SQLiteValue<'a>>,
575 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
576 SelectBuilder {
577 sql: self.sql.append(helpers::join(table, condition)),
578 schema: PhantomData,
579 state: PhantomData,
580 table: PhantomData,
581 }
582 }
583 join_impl!();
584}
585
586//------------------------------------------------------------------------------
587// Post-WHERE State Implementation
588//------------------------------------------------------------------------------
589
590impl<'a, S, T> SelectBuilder<'a, S, SelectWhereSet, T> {
591 /// Adds a GROUP BY clause after a WHERE
592 pub fn group_by(
593 self,
594 expressions: impl IntoIterator<Item = impl ToSQL<'a, SQLiteValue<'a>>>,
595 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
596 SelectBuilder {
597 sql: self.sql.append(helpers::group_by(expressions)),
598 schema: PhantomData,
599 state: PhantomData,
600 table: PhantomData,
601 }
602 }
603
604 /// Adds an ORDER BY clause after a WHERE
605 pub fn order_by<TOrderBy>(
606 self,
607 expressions: TOrderBy,
608 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
609 where
610 TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
611 {
612 SelectBuilder {
613 sql: self.sql.append(helpers::order_by(expressions)),
614 schema: PhantomData,
615 state: PhantomData,
616 table: PhantomData,
617 }
618 }
619
620 /// Adds a LIMIT clause after a WHERE
621 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
622 SelectBuilder {
623 sql: self.sql.append(helpers::limit(limit)),
624 schema: PhantomData,
625 state: PhantomData,
626 table: PhantomData,
627 }
628 }
629}
630
631//------------------------------------------------------------------------------
632// Post-GROUP BY State Implementation
633//------------------------------------------------------------------------------
634
635impl<'a, S, T> SelectBuilder<'a, S, SelectGroupSet, T> {
636 /// Adds a HAVING clause after GROUP BY
637 pub fn having(
638 self,
639 condition: impl ToSQL<'a, SQLiteValue<'a>>,
640 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
641 SelectBuilder {
642 sql: self.sql.append(helpers::having(condition)),
643 schema: PhantomData,
644 state: PhantomData,
645 table: PhantomData,
646 }
647 }
648
649 /// Adds an ORDER BY clause after GROUP BY
650 pub fn order_by<TOrderBy>(
651 self,
652 expressions: TOrderBy,
653 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
654 where
655 TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
656 {
657 SelectBuilder {
658 sql: self.sql.append(helpers::order_by(expressions)),
659 schema: PhantomData,
660 state: PhantomData,
661 table: PhantomData,
662 }
663 }
664}
665
666//------------------------------------------------------------------------------
667// Post-ORDER BY State Implementation
668//------------------------------------------------------------------------------
669
670impl<'a, S, T> SelectBuilder<'a, S, SelectOrderSet, T> {
671 /// Adds a LIMIT clause after ORDER BY
672 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
673 let sql = helpers::limit(limit);
674 SelectBuilder {
675 sql: self.sql.append(sql),
676 schema: PhantomData,
677 state: PhantomData,
678 table: PhantomData,
679 }
680 }
681}
682
683//------------------------------------------------------------------------------
684// Post-LIMIT State Implementation
685//------------------------------------------------------------------------------
686
687impl<'a, S, T> SelectBuilder<'a, S, SelectLimitSet, T> {
688 /// Adds an OFFSET clause after LIMIT
689 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
690 SelectBuilder {
691 sql: self.sql.append(helpers::offset(offset)),
692 schema: PhantomData,
693 state: PhantomData,
694 table: PhantomData,
695 }
696 }
697}
698
699impl<'a, S, State, T> SelectBuilder<'a, S, State, T>
700where
701 State: AsCteState,
702 T: SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>,
703{
704 /// Converts this SELECT query into a CTE (Common Table Expression) with the given name.
705 #[inline]
706 pub fn into_cte(
707 self,
708 name: &'static str,
709 ) -> super::CTEView<
710 'a,
711 <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::Aliased,
712 Self,
713 > {
714 super::CTEView::new(
715 <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::alias(name),
716 name,
717 self,
718 )
719 }
720}
721
722//------------------------------------------------------------------------------
723// Set operation support (UNION / INTERSECT / EXCEPT)
724//------------------------------------------------------------------------------
725
726impl<'a, S, State, T> SelectBuilder<'a, S, State, T>
727where
728 State: ExecutableState,
729{
730 /// Combines this query with another using UNION.
731 pub fn union(
732 self,
733 other: impl ToSQL<'a, SQLiteValue<'a>>,
734 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
735 SelectBuilder {
736 sql: helpers::union(self.sql, other),
737 schema: PhantomData,
738 state: PhantomData,
739 table: PhantomData,
740 }
741 }
742
743 /// Combines this query with another using UNION ALL.
744 pub fn union_all(
745 self,
746 other: impl ToSQL<'a, SQLiteValue<'a>>,
747 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
748 SelectBuilder {
749 sql: helpers::union_all(self.sql, other),
750 schema: PhantomData,
751 state: PhantomData,
752 table: PhantomData,
753 }
754 }
755
756 /// Combines this query with another using INTERSECT.
757 pub fn intersect(
758 self,
759 other: impl ToSQL<'a, SQLiteValue<'a>>,
760 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
761 SelectBuilder {
762 sql: helpers::intersect(self.sql, other),
763 schema: PhantomData,
764 state: PhantomData,
765 table: PhantomData,
766 }
767 }
768
769 /// Combines this query with another using INTERSECT ALL.
770 pub fn intersect_all(
771 self,
772 other: impl ToSQL<'a, SQLiteValue<'a>>,
773 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
774 SelectBuilder {
775 sql: helpers::intersect_all(self.sql, other),
776 schema: PhantomData,
777 state: PhantomData,
778 table: PhantomData,
779 }
780 }
781
782 /// Combines this query with another using EXCEPT.
783 pub fn except(
784 self,
785 other: impl ToSQL<'a, SQLiteValue<'a>>,
786 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
787 SelectBuilder {
788 sql: helpers::except(self.sql, other),
789 schema: PhantomData,
790 state: PhantomData,
791 table: PhantomData,
792 }
793 }
794
795 /// Combines this query with another using EXCEPT ALL.
796 pub fn except_all(
797 self,
798 other: impl ToSQL<'a, SQLiteValue<'a>>,
799 ) -> SelectBuilder<'a, S, SelectSetOpSet, T> {
800 SelectBuilder {
801 sql: helpers::except_all(self.sql, other),
802 schema: PhantomData,
803 state: PhantomData,
804 table: PhantomData,
805 }
806 }
807}
808
809impl<'a, S, T> SelectBuilder<'a, S, SelectSetOpSet, T> {
810 /// Sorts the results of a set operation.
811 pub fn order_by<TOrderBy>(
812 self,
813 expressions: TOrderBy,
814 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
815 where
816 TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
817 {
818 SelectBuilder {
819 sql: self.sql.append(helpers::order_by(expressions)),
820 schema: PhantomData,
821 state: PhantomData,
822 table: PhantomData,
823 }
824 }
825
826 /// Limits the results of a set operation.
827 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
828 SelectBuilder {
829 sql: self.sql.append(helpers::limit(limit)),
830 schema: PhantomData,
831 state: PhantomData,
832 table: PhantomData,
833 }
834 }
835
836 /// Offsets the results of a set operation.
837 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
838 SelectBuilder {
839 sql: self.sql.append(helpers::offset(offset)),
840 schema: PhantomData,
841 state: PhantomData,
842 table: PhantomData,
843 }
844 }
845}