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 #[inline]
650 #[must_use]
651 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T, M, R, G> {
652 SelectBuilder {
653 sql: append_sql(self.sql, helpers::limit(limit)),
654 schema: PhantomData,
655 state: PhantomData,
656 table: PhantomData,
657 marker: PhantomData,
658 row: PhantomData,
659 grouped: PhantomData,
660 }
661 }
662}
663
664// OFFSET (available from SelectFromSet and SelectLimitSet)
665impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
666where
667 State: drizzle_core::OffsetAllowed,
668{
669 /// Sets the offset for the query results.
670 #[inline]
671 #[must_use]
672 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T, M, R, G> {
673 SelectBuilder {
674 sql: append_sql(self.sql, helpers::offset(offset)),
675 schema: PhantomData,
676 state: PhantomData,
677 table: PhantomData,
678 marker: PhantomData,
679 row: PhantomData,
680 grouped: PhantomData,
681 }
682 }
683}
684
685//------------------------------------------------------------------------------
686// CTE support
687//------------------------------------------------------------------------------
688
689impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
690where
691 State: AsCteState,
692 T: SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>,
693{
694 /// Converts this SELECT query into a typed CTE using alias tag name.
695 #[inline]
696 #[must_use]
697 pub fn into_cte<Tag: drizzle_core::Tag + 'static>(
698 self,
699 ) -> super::CTEView<
700 'a,
701 <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::Aliased<Tag>,
702 Self,
703 > {
704 let name = Tag::NAME;
705 super::CTEView::new(
706 <T as SQLTable<'a, crate::common::SQLiteSchemaType, SQLiteValue<'a>>>::alias::<Tag>(),
707 name,
708 self,
709 )
710 }
711}
712
713//------------------------------------------------------------------------------
714// Set operation support (UNION / INTERSECT / EXCEPT)
715//------------------------------------------------------------------------------
716
717impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
718where
719 State: ExecutableState,
720{
721 /// Combines this query with another using UNION.
722 pub fn union(
723 self,
724 other: impl IntoSelect<'a, S, M, R>,
725 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
726 SelectBuilder {
727 sql: helpers::union(self.sql, other.into_select()),
728 schema: PhantomData,
729 state: PhantomData,
730 table: PhantomData,
731 marker: PhantomData,
732 row: PhantomData,
733 grouped: PhantomData,
734 }
735 }
736
737 /// Combines this query with another using UNION ALL.
738 pub fn union_all(
739 self,
740 other: impl IntoSelect<'a, S, M, R>,
741 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
742 SelectBuilder {
743 sql: helpers::union_all(self.sql, other.into_select()),
744 schema: PhantomData,
745 state: PhantomData,
746 table: PhantomData,
747 marker: PhantomData,
748 row: PhantomData,
749 grouped: PhantomData,
750 }
751 }
752
753 /// Combines this query with another using INTERSECT.
754 pub fn intersect(
755 self,
756 other: impl IntoSelect<'a, S, M, R>,
757 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
758 SelectBuilder {
759 sql: helpers::intersect(self.sql, other.into_select()),
760 schema: PhantomData,
761 state: PhantomData,
762 table: PhantomData,
763 marker: PhantomData,
764 row: PhantomData,
765 grouped: PhantomData,
766 }
767 }
768
769 /// Combines this query with another using INTERSECT ALL.
770 pub fn intersect_all(
771 self,
772 other: impl IntoSelect<'a, S, M, R>,
773 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
774 SelectBuilder {
775 sql: helpers::intersect_all(self.sql, other.into_select()),
776 schema: PhantomData,
777 state: PhantomData,
778 table: PhantomData,
779 marker: PhantomData,
780 row: PhantomData,
781 grouped: PhantomData,
782 }
783 }
784
785 /// Combines this query with another using EXCEPT.
786 pub fn except(
787 self,
788 other: impl IntoSelect<'a, S, M, R>,
789 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
790 SelectBuilder {
791 sql: helpers::except(self.sql, other.into_select()),
792 schema: PhantomData,
793 state: PhantomData,
794 table: PhantomData,
795 marker: PhantomData,
796 row: PhantomData,
797 grouped: PhantomData,
798 }
799 }
800
801 /// Combines this query with another using EXCEPT ALL.
802 pub fn except_all(
803 self,
804 other: impl IntoSelect<'a, S, M, R>,
805 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
806 SelectBuilder {
807 sql: helpers::except_all(self.sql, other.into_select()),
808 schema: PhantomData,
809 state: PhantomData,
810 table: PhantomData,
811 marker: PhantomData,
812 row: PhantomData,
813 grouped: PhantomData,
814 }
815 }
816}
817
818//------------------------------------------------------------------------------
819// Expr impl for subquery usage
820//------------------------------------------------------------------------------
821
822impl<'a, S, State, T, M, R, G> drizzle_core::expr::Expr<'a, SQLiteValue<'a>>
823 for SelectBuilder<'a, S, State, T, M, R, G>
824where
825 State: ExecutableState,
826 M: drizzle_core::expr::SubqueryType<'a, SQLiteValue<'a>>,
827{
828 type SQLType = <M as drizzle_core::expr::SubqueryType<'a, SQLiteValue<'a>>>::SQLType;
829 type Nullable = drizzle_core::expr::Null;
830 type Aggregate = drizzle_core::expr::Scalar;
831}
832
833//------------------------------------------------------------------------------
834// IntoSelect conversion trait
835//------------------------------------------------------------------------------
836
837/// Conversion trait for types that can become a `SelectBuilder`.
838/// Used by set operations to accept both raw `SelectBuilder` and `DrizzleBuilder`.
839pub trait IntoSelect<'a, S, M, R> {
840 type State: ExecutableState;
841 type Table;
842 fn into_select(self) -> SelectBuilder<'a, S, Self::State, Self::Table, M, R>;
843}
844
845impl<'a, S, State: ExecutableState, T, M, R, G> IntoSelect<'a, S, M, R>
846 for SelectBuilder<'a, S, State, T, M, R, G>
847{
848 type State = State;
849 type Table = T;
850 fn into_select(self) -> SelectBuilder<'a, S, State, T, M, R> {
851 SelectBuilder {
852 sql: self.sql,
853 schema: PhantomData,
854 state: PhantomData,
855 table: PhantomData,
856 marker: PhantomData,
857 row: PhantomData,
858 grouped: PhantomData,
859 }
860 }
861}