drizzle_sqlite/builder/
select.rs

1use crate::helpers;
2use crate::values::SQLiteValue;
3use drizzle_core::traits::{IsInSchema, SQLTable};
4use drizzle_core::{SQL, ToSQL};
5use paste::paste;
6use std::fmt::Debug;
7use std::marker::PhantomData;
8
9// Import the ExecutableState trait
10use super::ExecutableState;
11
12//------------------------------------------------------------------------------
13// Type State Markers
14//------------------------------------------------------------------------------
15
16/// Marker for the initial state of SelectBuilder.
17#[derive(Debug, Clone, Copy, Default)]
18pub struct SelectInitial;
19
20impl SelectInitial {
21    /// Creates a new SelectInitial marker
22    #[inline]
23    pub const fn new() -> Self {
24        Self
25    }
26}
27
28/// Marker for the state after FROM clause
29#[derive(Debug, Clone, Copy, Default)]
30pub struct SelectFromSet;
31
32/// Marker for the state after JOIN clause
33#[derive(Debug, Clone, Copy, Default)]
34pub struct SelectJoinSet;
35
36/// Marker for the state after WHERE clause
37#[derive(Debug, Clone, Copy, Default)]
38pub struct SelectWhereSet;
39
40/// Marker for the state after GROUP BY clause
41#[derive(Debug, Clone, Copy, Default)]
42pub struct SelectGroupSet;
43
44/// Marker for the state after ORDER BY clause
45#[derive(Debug, Clone, Copy, Default)]
46pub struct SelectOrderSet;
47
48/// Marker for the state after LIMIT clause
49#[derive(Debug, Clone, Copy, Default)]
50pub struct SelectLimitSet;
51
52/// Marker for the state after OFFSET clause
53#[derive(Debug, Clone, Copy, Default)]
54pub struct SelectOffsetSet;
55
56// Const constructors for all marker types
57impl SelectFromSet {
58    #[inline]
59    pub const fn new() -> Self {
60        Self
61    }
62}
63impl SelectJoinSet {
64    #[inline]
65    pub const fn new() -> Self {
66        Self
67    }
68}
69impl SelectWhereSet {
70    #[inline]
71    pub const fn new() -> Self {
72        Self
73    }
74}
75impl SelectGroupSet {
76    #[inline]
77    pub const fn new() -> Self {
78        Self
79    }
80}
81impl SelectOrderSet {
82    #[inline]
83    pub const fn new() -> Self {
84        Self
85    }
86}
87impl SelectLimitSet {
88    #[inline]
89    pub const fn new() -> Self {
90        Self
91    }
92}
93impl SelectOffsetSet {
94    #[inline]
95    pub const fn new() -> Self {
96        Self
97    }
98}
99
100macro_rules! join_impl {
101    () => {
102        join_impl!(natural);
103        join_impl!(natural_left);
104        join_impl!(left);
105        join_impl!(left_outer);
106        join_impl!(natural_left_outer);
107        join_impl!(natural_right);
108        join_impl!(right);
109        join_impl!(right_outer);
110        join_impl!(natural_right_outer);
111        join_impl!(natural_full);
112        join_impl!(full);
113        join_impl!(full_outer);
114        join_impl!(natural_full_outer);
115        join_impl!(inner);
116        join_impl!(cross);
117    };
118    ($type:ident) => {
119        paste! {
120            pub fn [<$type _join>]<U: IsInSchema<S> + SQLTable<'a, SQLiteValue<'a>>>(
121                self,
122                table: U,
123                condition: SQL<'a, SQLiteValue<'a>>,
124            ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
125                SelectBuilder {
126                    sql: self.sql.append(helpers::[<$type _join>](table, condition)),
127                    schema: PhantomData,
128                    state: PhantomData,
129                    table: PhantomData,
130                }
131            }
132        }
133    };
134}
135
136// Mark states that can execute queries as implementing the ExecutableState trait
137impl ExecutableState for SelectFromSet {}
138impl ExecutableState for SelectWhereSet {}
139impl ExecutableState for SelectLimitSet {}
140impl ExecutableState for SelectOffsetSet {}
141impl ExecutableState for SelectOrderSet {}
142impl ExecutableState for SelectGroupSet {}
143impl ExecutableState for SelectJoinSet {}
144
145//------------------------------------------------------------------------------
146// SelectBuilder Definition
147//------------------------------------------------------------------------------
148
149/// Builds a SELECT query specifically for SQLite
150pub type SelectBuilder<'a, Schema, State, Table = ()> =
151    super::QueryBuilder<'a, Schema, State, Table>;
152
153//------------------------------------------------------------------------------
154// Initial State Implementation
155//------------------------------------------------------------------------------
156
157impl<'a, S> SelectBuilder<'a, S, SelectInitial> {
158    /// Specifies the table to select FROM and transitions state
159    #[inline]
160    pub fn from<T>(self, query: T) -> SelectBuilder<'a, S, SelectFromSet, T>
161    where
162        T: ToSQL<'a, SQLiteValue<'a>>,
163    {
164        SelectBuilder {
165            sql: self.sql.append(helpers::from(query)),
166            schema: PhantomData,
167            state: PhantomData,
168            table: PhantomData,
169        }
170    }
171}
172
173//------------------------------------------------------------------------------
174// Post-FROM State Implementation
175//------------------------------------------------------------------------------
176
177impl<'a, S, T> SelectBuilder<'a, S, SelectFromSet, T>
178where
179    T: SQLTable<'a, SQLiteValue<'a>>,
180{
181    /// Adds a JOIN clause to the query
182    #[inline]
183    pub fn join<U: IsInSchema<S> + SQLTable<'a, SQLiteValue<'a>>>(
184        self,
185        table: U,
186        condition: SQL<'a, SQLiteValue<'a>>,
187    ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
188        SelectBuilder {
189            sql: self.sql.append(helpers::join(table, condition)),
190            schema: PhantomData,
191            state: PhantomData,
192            table: PhantomData,
193        }
194    }
195
196    join_impl!();
197
198    #[inline]
199    pub fn r#where(
200        self,
201        condition: SQL<'a, SQLiteValue<'a>>,
202    ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
203        SelectBuilder {
204            sql: self.sql.append(helpers::r#where(condition)),
205            schema: PhantomData,
206            state: PhantomData,
207            table: PhantomData,
208        }
209    }
210
211    /// Adds a GROUP BY clause to the query
212    pub fn group_by(
213        self,
214        expressions: Vec<SQL<'a, SQLiteValue<'a>>>,
215    ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
216        SelectBuilder {
217            sql: self.sql.append(helpers::group_by(expressions)),
218            schema: PhantomData,
219            state: PhantomData,
220            table: PhantomData,
221        }
222    }
223
224    /// Limits the number of rows returned
225    #[inline]
226    pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
227        SelectBuilder {
228            sql: self.sql.append(helpers::limit(limit)),
229            schema: PhantomData,
230            state: PhantomData,
231            table: PhantomData,
232        }
233    }
234
235    /// Sets the offset for the query results
236    #[inline]
237    pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
238        SelectBuilder {
239            sql: self.sql.append(helpers::offset(offset)),
240            schema: PhantomData,
241            state: PhantomData,
242            table: PhantomData,
243        }
244    }
245
246    /// Sorts the query results
247    #[inline]
248    pub fn order_by<TOrderBy>(
249        self,
250        expressions: TOrderBy,
251    ) -> SelectBuilder<'a, S, SelectOrderSet, T>
252    where
253        TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
254    {
255        SelectBuilder {
256            sql: self.sql.append(helpers::order_by(expressions)),
257            schema: PhantomData,
258            state: PhantomData,
259            table: PhantomData,
260        }
261    }
262}
263
264//------------------------------------------------------------------------------
265// Post-JOIN State Implementation
266//------------------------------------------------------------------------------
267
268impl<'a, S, T> SelectBuilder<'a, S, SelectJoinSet, T> {
269    /// Adds a WHERE condition after a JOIN
270    #[inline]
271    pub fn r#where(
272        self,
273        condition: SQL<'a, SQLiteValue<'a>>,
274    ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
275        SelectBuilder {
276            sql: self.sql.append(crate::helpers::r#where(condition)),
277            schema: PhantomData,
278            state: PhantomData,
279            table: PhantomData,
280        }
281    }
282    /// Sorts the query results
283    #[inline]
284    pub fn order_by<TOrderBy>(
285        self,
286        expressions: TOrderBy,
287    ) -> SelectBuilder<'a, S, SelectOrderSet, T>
288    where
289        TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
290    {
291        SelectBuilder {
292            sql: self.sql.append(helpers::order_by(expressions)),
293            schema: PhantomData,
294            state: PhantomData,
295            table: PhantomData,
296        }
297    }
298    /// Adds a JOIN clause to the query
299    #[inline]
300    pub fn join<U: IsInSchema<S> + SQLTable<'a, SQLiteValue<'a>>>(
301        self,
302        table: U,
303        condition: SQL<'a, SQLiteValue<'a>>,
304    ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
305        SelectBuilder {
306            sql: self.sql.append(helpers::join(table, condition)),
307            schema: PhantomData,
308            state: PhantomData,
309            table: PhantomData,
310        }
311    }
312    join_impl!();
313}
314
315//------------------------------------------------------------------------------
316// Post-WHERE State Implementation
317//------------------------------------------------------------------------------
318
319impl<'a, S, T> SelectBuilder<'a, S, SelectWhereSet, T> {
320    /// Adds a GROUP BY clause after a WHERE
321    pub fn group_by(
322        self,
323        expressions: Vec<SQL<'a, SQLiteValue<'a>>>,
324    ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
325        SelectBuilder {
326            sql: self.sql.append(helpers::group_by(expressions)),
327            schema: PhantomData,
328            state: PhantomData,
329            table: PhantomData,
330        }
331    }
332
333    /// Adds an ORDER BY clause after a WHERE
334    pub fn order_by<TOrderBy>(
335        self,
336        expressions: TOrderBy,
337    ) -> SelectBuilder<'a, S, SelectOrderSet, T>
338    where
339        TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
340    {
341        SelectBuilder {
342            sql: self.sql.append(helpers::order_by(expressions)),
343            schema: PhantomData,
344            state: PhantomData,
345            table: PhantomData,
346        }
347    }
348
349    /// Adds a LIMIT clause after a WHERE
350    pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
351        SelectBuilder {
352            sql: self.sql.append(helpers::limit(limit)),
353            schema: PhantomData,
354            state: PhantomData,
355            table: PhantomData,
356        }
357    }
358}
359
360//------------------------------------------------------------------------------
361// Post-GROUP BY State Implementation
362//------------------------------------------------------------------------------
363
364impl<'a, S, T> SelectBuilder<'a, S, SelectGroupSet, T> {
365    /// Adds a HAVING clause after GROUP BY
366    pub fn having(
367        self,
368        condition: SQL<'a, SQLiteValue<'a>>,
369    ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
370        SelectBuilder {
371            sql: self.sql.append(helpers::having(condition)),
372            schema: PhantomData,
373            state: PhantomData,
374            table: PhantomData,
375        }
376    }
377
378    /// Adds an ORDER BY clause after GROUP BY
379    pub fn order_by<TOrderBy>(
380        self,
381        expressions: TOrderBy,
382    ) -> SelectBuilder<'a, S, SelectOrderSet, T>
383    where
384        TOrderBy: drizzle_core::ToSQL<'a, SQLiteValue<'a>>,
385    {
386        SelectBuilder {
387            sql: self.sql.append(helpers::order_by(expressions)),
388            schema: PhantomData,
389            state: PhantomData,
390            table: PhantomData,
391        }
392    }
393}
394
395//------------------------------------------------------------------------------
396// Post-ORDER BY State Implementation
397//------------------------------------------------------------------------------
398
399impl<'a, S, T> SelectBuilder<'a, S, SelectOrderSet, T> {
400    /// Adds a LIMIT clause after ORDER BY
401    pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
402        SelectBuilder {
403            sql: self.sql.append(helpers::limit(limit)),
404            schema: PhantomData,
405            state: PhantomData,
406            table: PhantomData,
407        }
408    }
409}
410
411//------------------------------------------------------------------------------
412// Post-LIMIT State Implementation
413//------------------------------------------------------------------------------
414
415impl<'a, S, T> SelectBuilder<'a, S, SelectLimitSet, T> {
416    /// Adds an OFFSET clause after LIMIT
417    pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
418        SelectBuilder {
419            sql: self.sql.append(helpers::offset(offset)),
420            schema: PhantomData,
421            state: PhantomData,
422            table: PhantomData,
423        }
424    }
425}