Skip to main content

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/// #             #[cfg(feature = "rusqlite")]
210/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
211/// #             #[cfg(feature = "libsql")]
212/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
213/// #             #[cfg(feature = "turso")]
214/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
215/// #         pub mod prelude {
216/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
217/// #             pub use drizzle_sqlite::{*, attrs::*};
218/// #             pub use drizzle_core::*;
219/// #         }
220/// #     }
221/// # }
222/// use drizzle::sqlite::prelude::*;
223/// use drizzle::sqlite::builder::QueryBuilder;
224///
225/// #[SQLiteTable(name = "users")]
226/// struct User {
227///     #[column(primary)]
228///     id: i32,
229///     name: String,
230///     email: Option<String>,
231/// }
232///
233/// #[derive(SQLiteSchema)]
234/// struct Schema {
235///     user: User,
236/// }
237///
238/// let builder = QueryBuilder::new::<Schema>();
239/// let Schema { user } = Schema::new();
240///
241/// // Basic SELECT
242/// let query = builder.select(user.name).from(user);
243/// assert_eq!(query.to_sql().sql(), r#"SELECT "users"."name" FROM "users""#);
244///
245/// // SELECT with WHERE clause
246/// use drizzle::core::expr::gt;
247/// let query = builder
248///     .select((user.id, user.name))
249///     .from(user)
250///     .r#where(gt(user.id, 10));
251/// assert_eq!(
252///     query.to_sql().sql(),
253///     r#"SELECT "users"."id", "users"."name" FROM "users" WHERE "users"."id" > ?"#
254/// );
255/// ```
256///
257/// ## Advanced Queries
258///
259/// ```rust
260/// # mod drizzle {
261/// #     pub mod core { pub use drizzle_core::*; }
262/// #     pub mod error { pub use drizzle_core::error::*; }
263/// #     pub mod types { pub use drizzle_types::*; }
264/// #     pub mod migrations { pub use drizzle_migrations::*; }
265/// #     pub use drizzle_types::Dialect;
266/// #     pub use drizzle_types as ddl;
267/// #     pub mod sqlite {
268/// #             pub use drizzle_sqlite::{*, attrs::*};
269/// #             #[cfg(feature = "rusqlite")]
270/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
271/// #             #[cfg(feature = "libsql")]
272/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
273/// #             #[cfg(feature = "turso")]
274/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
275/// #         pub mod prelude {
276/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
277/// #             pub use drizzle_sqlite::{*, attrs::*};
278/// #             pub use drizzle_core::*;
279/// #         }
280/// #     }
281/// # }
282/// # use drizzle::sqlite::prelude::*;
283/// # use drizzle::core::expr::eq;
284/// # use drizzle::sqlite::builder::QueryBuilder;
285/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
286/// # #[SQLiteTable(name = "posts")] struct Post { #[column(primary)] id: i32, user_id: i32, title: String }
287/// # #[derive(SQLiteSchema)] struct Schema { user: User, post: Post }
288/// # let builder = QueryBuilder::new::<Schema>();
289/// # let Schema { user, post } = Schema::new();
290/// let query = builder
291///     .select((user.name, post.title))
292///     .from(user)
293///     .join((post, eq(user.id, post.user_id)));
294/// ```
295///
296/// ```rust
297/// # mod drizzle {
298/// #     pub mod core { pub use drizzle_core::*; }
299/// #     pub mod error { pub use drizzle_core::error::*; }
300/// #     pub mod types { pub use drizzle_types::*; }
301/// #     pub mod migrations { pub use drizzle_migrations::*; }
302/// #     pub use drizzle_types::Dialect;
303/// #     pub use drizzle_types as ddl;
304/// #     pub mod sqlite {
305/// #             pub use drizzle_sqlite::{*, attrs::*};
306/// #             #[cfg(feature = "rusqlite")]
307/// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
308/// #             #[cfg(feature = "libsql")]
309/// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
310/// #             #[cfg(feature = "turso")]
311/// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
312/// #         pub mod prelude {
313/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
314/// #             pub use drizzle_sqlite::{*, attrs::*};
315/// #             pub use drizzle_core::*;
316/// #         }
317/// #     }
318/// # }
319/// # use drizzle::sqlite::prelude::*;
320/// # use drizzle::sqlite::builder::QueryBuilder;
321/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
322/// # #[derive(SQLiteSchema)] struct Schema { user: User }
323/// # let builder = QueryBuilder::new::<Schema>();
324/// # let Schema { user } = Schema::new();
325/// let query = builder
326///     .select(user.name)
327///     .from(user)
328///     .order_by(asc(user.name))
329///     .limit(10);
330/// ```
331pub type SelectBuilder<'a, Schema, State, Table = (), Marker = (), Row = (), Grouped = ()> =
332    super::QueryBuilder<'a, Schema, State, Table, Marker, Row, Grouped>;
333
334//------------------------------------------------------------------------------
335// Initial State: .from()
336//------------------------------------------------------------------------------
337
338impl<'a, S, M> SelectBuilder<'a, S, SelectInitial, (), M> {
339    /// Specifies the table or subquery to select FROM.
340    ///
341    /// This method transitions the builder from the initial state to the FROM state,
342    /// enabling subsequent WHERE, JOIN, ORDER BY, and other clauses.
343    ///
344    /// The row type `R` is resolved from the select marker `M` and the table `T`
345    /// via the `ResolveRow` trait.
346    ///
347    /// # Examples
348    ///
349    /// ```rust
350    /// # mod drizzle {
351    /// #     pub mod core { pub use drizzle_core::*; }
352    /// #     pub mod error { pub use drizzle_core::error::*; }
353    /// #     pub mod types { pub use drizzle_types::*; }
354    /// #     pub mod migrations { pub use drizzle_migrations::*; }
355    /// #     pub use drizzle_types::Dialect;
356    /// #     pub use drizzle_types as ddl;
357    /// #     pub mod sqlite {
358    /// #             pub use drizzle_sqlite::{*, attrs::*};
359    /// #             #[cfg(feature = "rusqlite")]
360    /// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
361    /// #             #[cfg(feature = "libsql")]
362    /// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
363    /// #             #[cfg(feature = "turso")]
364    /// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
365    /// #         pub mod prelude {
366    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
367    /// #             pub use drizzle_sqlite::{*, attrs::*};
368    /// #             pub use drizzle_core::*;
369    /// #         }
370    /// #     }
371    /// # }
372    /// # use drizzle::sqlite::prelude::*;
373    /// # use drizzle::sqlite::builder::QueryBuilder;
374    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
375    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
376    /// # let builder = QueryBuilder::new::<Schema>();
377    /// # let Schema { user } = Schema::new();
378    /// // Select from a table
379    /// let query = builder.select(user.name).from(user);
380    /// assert_eq!(query.to_sql().sql(), r#"SELECT "users"."name" FROM "users""#);
381    /// ```
382    #[inline]
383    #[allow(clippy::type_complexity)]
384    pub fn from<T>(
385        self,
386        query: T,
387    ) -> SelectBuilder<
388        'a,
389        S,
390        SelectFromSet,
391        T,
392        drizzle_core::Scoped<M, drizzle_core::Cons<T, drizzle_core::Nil>>,
393        <M as drizzle_core::ResolveRow<T>>::Row,
394    >
395    where
396        T: ToSQL<'a, SQLiteValue<'a>>,
397        M: drizzle_core::ResolveRow<T>,
398    {
399        let sql = append_sql(self.sql, helpers::from(query));
400        SelectBuilder {
401            sql,
402            schema: PhantomData,
403            state: PhantomData,
404            table: PhantomData,
405            marker: PhantomData,
406            row: PhantomData,
407            grouped: PhantomData,
408        }
409    }
410}
411
412//------------------------------------------------------------------------------
413// Capability-gated methods (generic over State)
414//------------------------------------------------------------------------------
415
416// JOIN (available from SelectFromSet and SelectJoinSet)
417impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
418where
419    State: drizzle_core::JoinAllowed,
420{
421    /// Adds an INNER JOIN clause to the query.
422    ///
423    /// Joins another table to the current query using the specified condition.
424    /// The joined table must be part of the schema and the condition should
425    /// relate columns from both tables.
426    ///
427    /// ```rust
428    /// # mod drizzle {
429    /// #     pub mod core { pub use drizzle_core::*; }
430    /// #     pub mod error { pub use drizzle_core::error::*; }
431    /// #     pub mod types { pub use drizzle_types::*; }
432    /// #     pub mod migrations { pub use drizzle_migrations::*; }
433    /// #     pub use drizzle_types::Dialect;
434    /// #     pub use drizzle_types as ddl;
435    /// #     pub mod sqlite {
436    /// #             pub use drizzle_sqlite::{*, attrs::*};
437    /// #             #[cfg(feature = "rusqlite")]
438    /// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
439    /// #             #[cfg(feature = "libsql")]
440    /// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
441    /// #             #[cfg(feature = "turso")]
442    /// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
443    /// #         pub mod prelude {
444    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
445    /// #             pub use drizzle_sqlite::{*, attrs::*};
446    /// #             pub use drizzle_core::*;
447    /// #         }
448    /// #     }
449    /// # }
450    /// # use drizzle::sqlite::prelude::*;
451    /// # use drizzle::core::expr::eq;
452    /// # use drizzle::sqlite::builder::QueryBuilder;
453    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
454    /// # #[SQLiteTable(name = "posts")] struct Post { #[column(primary)] id: i32, user_id: i32, title: String }
455    /// # #[derive(SQLiteSchema)] struct Schema { user: User, post: Post }
456    /// # let builder = QueryBuilder::new::<Schema>();
457    /// # let Schema { user, post } = Schema::new();
458    /// let query = builder
459    ///     .select((user.name, post.title))
460    ///     .from(user)
461    ///     .join((post, eq(user.id, post.user_id)));
462    /// assert_eq!(
463    ///     query.to_sql().sql(),
464    ///     r#"SELECT "users"."name", "posts"."title" FROM "users" JOIN "posts" ON "users"."id" = "posts"."user_id""#
465    /// );
466    /// ```
467    #[inline]
468    #[allow(clippy::type_complexity)]
469    pub fn join<J: JoinArg<'a, T>>(
470        self,
471        arg: J,
472    ) -> SelectBuilder<
473        'a,
474        S,
475        SelectJoinSet,
476        J::JoinedTable,
477        <M as drizzle_core::ScopePush<J::JoinedTable>>::Out,
478        <M as drizzle_core::AfterJoin<R, J::JoinedTable>>::NewRow,
479        G,
480    >
481    where
482        M: drizzle_core::AfterJoin<R, J::JoinedTable> + drizzle_core::ScopePush<J::JoinedTable>,
483    {
484        SelectBuilder {
485            sql: append_sql(self.sql, arg.into_join_sql(drizzle_core::Join::new())),
486            schema: PhantomData,
487            state: PhantomData,
488            table: PhantomData,
489            marker: PhantomData,
490            row: PhantomData,
491            grouped: PhantomData,
492        }
493    }
494
495    join_impl!();
496}
497
498// WHERE (available from SelectFromSet and SelectJoinSet)
499impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
500where
501    State: drizzle_core::WhereAllowed,
502{
503    /// Adds a WHERE clause to filter query results.
504    ///
505    /// ```rust
506    /// # mod drizzle {
507    /// #     pub mod core { pub use drizzle_core::*; }
508    /// #     pub mod error { pub use drizzle_core::error::*; }
509    /// #     pub mod types { pub use drizzle_types::*; }
510    /// #     pub mod migrations { pub use drizzle_migrations::*; }
511    /// #     pub use drizzle_types::Dialect;
512    /// #     pub use drizzle_types as ddl;
513    /// #     pub mod sqlite {
514    /// #             pub use drizzle_sqlite::{*, attrs::*};
515    /// #             #[cfg(feature = "rusqlite")]
516    /// #             pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
517    /// #             #[cfg(feature = "libsql")]
518    /// #             pub mod libsql { pub use ::libsql::{Row, Value}; }
519    /// #             #[cfg(feature = "turso")]
520    /// #             pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
521    /// #         pub mod prelude {
522    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
523    /// #             pub use drizzle_sqlite::{*, attrs::*};
524    /// #             pub use drizzle_core::*;
525    /// #         }
526    /// #     }
527    /// # }
528    /// # use drizzle::sqlite::prelude::*;
529    /// # use drizzle::core::expr::{gt, and, eq};
530    /// # use drizzle::sqlite::builder::QueryBuilder;
531    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
532    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
533    /// # let builder = QueryBuilder::new::<Schema>();
534    /// # let Schema { user } = Schema::new();
535    /// // Single condition
536    /// let query = builder
537    ///     .select(user.name)
538    ///     .from(user)
539    ///     .r#where(gt(user.id, 10));
540    /// assert_eq!(
541    ///     query.to_sql().sql(),
542    ///     r#"SELECT "users"."name" FROM "users" WHERE "users"."id" > ?"#
543    /// );
544    ///
545    /// // Multiple conditions
546    /// let query = builder
547    ///     .select(user.name)
548    ///     .from(user)
549    ///     .r#where(and(gt(user.id, 10), eq(user.name, "Alice")));
550    /// ```
551    #[inline]
552    pub fn r#where<E>(self, condition: E) -> SelectBuilder<'a, S, SelectWhereSet, T, M, R, G>
553    where
554        E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
555        E::SQLType: drizzle_core::types::BooleanLike,
556    {
557        SelectBuilder {
558            sql: append_sql(self.sql, helpers::r#where(condition)),
559            schema: PhantomData,
560            state: PhantomData,
561            table: PhantomData,
562            marker: PhantomData,
563            row: PhantomData,
564            grouped: PhantomData,
565        }
566    }
567}
568
569// GROUP BY (available from SelectFromSet, SelectJoinSet, SelectWhereSet)
570impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
571where
572    State: drizzle_core::GroupByAllowed,
573{
574    /// Adds a GROUP BY clause to the query.
575    pub fn group_by<Gr>(
576        self,
577        columns: Gr,
578    ) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, Gr::Columns>
579    where
580        Gr: drizzle_core::IntoGroupBy<'a, SQLiteValue<'a>>,
581    {
582        SelectBuilder {
583            sql: append_sql(self.sql, helpers::group_by_expr(columns)),
584            schema: PhantomData,
585            state: PhantomData,
586            table: PhantomData,
587            marker: PhantomData,
588            row: PhantomData,
589            grouped: PhantomData,
590        }
591    }
592}
593
594// HAVING (available only from SelectGroupSet)
595impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
596where
597    State: drizzle_core::HavingAllowed,
598{
599    /// Adds a HAVING clause after GROUP BY.
600    pub fn having<E>(self, condition: E) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, G>
601    where
602        E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
603        E::SQLType: drizzle_core::types::BooleanLike,
604    {
605        SelectBuilder {
606            sql: append_sql(self.sql, helpers::having(condition)),
607            schema: PhantomData,
608            state: PhantomData,
609            table: PhantomData,
610            marker: PhantomData,
611            row: PhantomData,
612            grouped: PhantomData,
613        }
614    }
615}
616
617// ORDER BY (available from many states)
618impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
619where
620    State: drizzle_core::OrderByAllowed,
621{
622    /// Sorts the query results.
623    #[inline]
624    pub fn order_by<TOrderBy>(
625        self,
626        expressions: TOrderBy,
627    ) -> SelectBuilder<'a, S, SelectOrderSet, T, M, R, G>
628    where
629        TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
630    {
631        SelectBuilder {
632            sql: append_sql(self.sql, helpers::order_by(expressions)),
633            schema: PhantomData,
634            state: PhantomData,
635            table: PhantomData,
636            marker: PhantomData,
637            row: PhantomData,
638            grouped: PhantomData,
639        }
640    }
641}
642
643// LIMIT (available from many states)
644impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
645where
646    State: drizzle_core::LimitAllowed,
647{
648    /// Limits the number of rows returned.
649    ///
650    /// # Panics
651    ///
652    /// Panics when a signed numeric argument is negative or a numeric value
653    /// does not fit in `usize`.
654    #[inline]
655    #[must_use]
656    #[track_caller]
657    pub fn limit<P>(self, limit: P) -> SelectBuilder<'a, S, SelectLimitSet, T, M, R, G>
658    where
659        P: drizzle_core::PaginationArg<'a, SQLiteValue<'a>>,
660    {
661        SelectBuilder {
662            sql: append_sql(self.sql, helpers::limit(limit)),
663            schema: PhantomData,
664            state: PhantomData,
665            table: PhantomData,
666            marker: PhantomData,
667            row: PhantomData,
668            grouped: PhantomData,
669        }
670    }
671}
672
673// OFFSET (available from SelectFromSet and SelectLimitSet)
674impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
675where
676    State: drizzle_core::OffsetAllowed,
677{
678    /// Sets the offset for the query results.
679    ///
680    /// # Panics
681    ///
682    /// Panics when a signed numeric argument is negative or a numeric value
683    /// does not fit in `usize`.
684    #[inline]
685    #[must_use]
686    #[track_caller]
687    pub fn offset<P>(self, offset: P) -> SelectBuilder<'a, S, SelectOffsetSet, T, M, R, G>
688    where
689        P: drizzle_core::PaginationArg<'a, SQLiteValue<'a>>,
690    {
691        SelectBuilder {
692            sql: append_sql(self.sql, helpers::offset(offset)),
693            schema: PhantomData,
694            state: PhantomData,
695            table: PhantomData,
696            marker: PhantomData,
697            row: PhantomData,
698            grouped: PhantomData,
699        }
700    }
701}
702
703//------------------------------------------------------------------------------
704// CTE support
705//------------------------------------------------------------------------------
706
707impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
708where
709    State: AsCteState,
710    T: SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>,
711{
712    /// Converts this SELECT query into a typed CTE using alias tag name.
713    #[inline]
714    #[must_use]
715    pub fn into_cte<Tag: drizzle_core::Tag + 'static>(
716        self,
717    ) -> super::CTEView<
718        'a,
719        <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::Aliased<Tag>,
720        Self,
721    > {
722        let name = Tag::NAME;
723        super::CTEView::new(
724            <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::alias::<Tag>(),
725            name,
726            self,
727        )
728    }
729}
730
731//------------------------------------------------------------------------------
732// Set operation support (UNION / INTERSECT / EXCEPT)
733//------------------------------------------------------------------------------
734
735impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
736where
737    State: ExecutableState,
738{
739    /// Combines this query with another using UNION.
740    pub fn union(
741        self,
742        other: impl IntoSelect<'a, S, M, R>,
743    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
744        SelectBuilder {
745            sql: helpers::union(self.sql, other.into_select()),
746            schema: PhantomData,
747            state: PhantomData,
748            table: PhantomData,
749            marker: PhantomData,
750            row: PhantomData,
751            grouped: PhantomData,
752        }
753    }
754
755    /// Combines this query with another using UNION ALL.
756    pub fn union_all(
757        self,
758        other: impl IntoSelect<'a, S, M, R>,
759    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
760        SelectBuilder {
761            sql: helpers::union_all(self.sql, other.into_select()),
762            schema: PhantomData,
763            state: PhantomData,
764            table: PhantomData,
765            marker: PhantomData,
766            row: PhantomData,
767            grouped: PhantomData,
768        }
769    }
770
771    /// Combines this query with another using INTERSECT.
772    pub fn intersect(
773        self,
774        other: impl IntoSelect<'a, S, M, R>,
775    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
776        SelectBuilder {
777            sql: helpers::intersect(self.sql, other.into_select()),
778            schema: PhantomData,
779            state: PhantomData,
780            table: PhantomData,
781            marker: PhantomData,
782            row: PhantomData,
783            grouped: PhantomData,
784        }
785    }
786
787    /// Combines this query with another using INTERSECT ALL.
788    pub fn intersect_all(
789        self,
790        other: impl IntoSelect<'a, S, M, R>,
791    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
792        SelectBuilder {
793            sql: helpers::intersect_all(self.sql, other.into_select()),
794            schema: PhantomData,
795            state: PhantomData,
796            table: PhantomData,
797            marker: PhantomData,
798            row: PhantomData,
799            grouped: PhantomData,
800        }
801    }
802
803    /// Combines this query with another using EXCEPT.
804    pub fn except(
805        self,
806        other: impl IntoSelect<'a, S, M, R>,
807    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
808        SelectBuilder {
809            sql: helpers::except(self.sql, other.into_select()),
810            schema: PhantomData,
811            state: PhantomData,
812            table: PhantomData,
813            marker: PhantomData,
814            row: PhantomData,
815            grouped: PhantomData,
816        }
817    }
818
819    /// Combines this query with another using EXCEPT ALL.
820    pub fn except_all(
821        self,
822        other: impl IntoSelect<'a, S, M, R>,
823    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
824        SelectBuilder {
825            sql: helpers::except_all(self.sql, other.into_select()),
826            schema: PhantomData,
827            state: PhantomData,
828            table: PhantomData,
829            marker: PhantomData,
830            row: PhantomData,
831            grouped: PhantomData,
832        }
833    }
834}
835
836//------------------------------------------------------------------------------
837// Expr impl for subquery usage
838//------------------------------------------------------------------------------
839
840impl<'a, S, State, T, M, R, G> drizzle_core::expr::Expr<'a, SQLiteValue<'a>>
841    for SelectBuilder<'a, S, State, T, M, R, G>
842where
843    State: ExecutableState,
844    M: drizzle_core::expr::SubqueryType<'a, SQLiteValue<'a>>,
845{
846    type SQLType = <M as drizzle_core::expr::SubqueryType<'a, SQLiteValue<'a>>>::SQLType;
847    type Nullable = drizzle_core::expr::Null;
848    type Aggregate = drizzle_core::expr::Scalar;
849}
850
851//------------------------------------------------------------------------------
852// IntoSelect conversion trait
853//------------------------------------------------------------------------------
854
855/// Conversion trait for types that can become a `SelectBuilder`.
856/// Used by set operations to accept both raw `SelectBuilder` and `DrizzleBuilder`.
857pub trait IntoSelect<'a, S, M, R> {
858    type State: ExecutableState;
859    type Table;
860    fn into_select(self) -> SelectBuilder<'a, S, Self::State, Self::Table, M, R>;
861}
862
863impl<'a, S, State: ExecutableState, T, M, R, G> IntoSelect<'a, S, M, R>
864    for SelectBuilder<'a, S, State, T, M, R, G>
865{
866    type State = State;
867    type Table = T;
868    fn into_select(self) -> SelectBuilder<'a, S, State, T, M, R> {
869        SelectBuilder {
870            sql: self.sql,
871            schema: PhantomData,
872            state: PhantomData,
873            table: PhantomData,
874            marker: PhantomData,
875            row: PhantomData,
876            grouped: PhantomData,
877        }
878    }
879}