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