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}