1use crate::common::PostgresSchemaType;
2use crate::traits::PostgresTable;
3use crate::values::PostgresValue;
4use crate::{ToPostgresSQL, helpers};
5use drizzle_core::SQL;
6use drizzle_core::traits::SQLTable;
7use paste::paste;
8use std::fmt::Debug;
9use std::marker::PhantomData;
10
11use super::ExecutableState;
13
14#[derive(Debug, Clone, Copy, Default)]
20pub struct SelectInitial;
21
22impl SelectInitial {
23 #[inline]
25 pub const fn new() -> Self {
26 Self
27 }
28}
29
30#[derive(Debug, Clone, Copy, Default)]
32pub struct SelectFromSet;
33
34#[derive(Debug, Clone, Copy, Default)]
36pub struct SelectJoinSet;
37
38#[derive(Debug, Clone, Copy, Default)]
40pub struct SelectWhereSet;
41
42#[derive(Debug, Clone, Copy, Default)]
44pub struct SelectGroupSet;
45
46#[derive(Debug, Clone, Copy, Default)]
48pub struct SelectOrderSet;
49
50#[derive(Debug, Clone, Copy, Default)]
52pub struct SelectLimitSet;
53
54#[derive(Debug, Clone, Copy, Default)]
56pub struct SelectOffsetSet;
57
58impl SelectFromSet {
60 #[inline]
61 pub const fn new() -> Self {
62 Self
63 }
64}
65impl SelectJoinSet {
66 #[inline]
67 pub const fn new() -> Self {
68 Self
69 }
70}
71impl SelectWhereSet {
72 #[inline]
73 pub const fn new() -> Self {
74 Self
75 }
76}
77impl SelectGroupSet {
78 #[inline]
79 pub const fn new() -> Self {
80 Self
81 }
82}
83impl SelectOrderSet {
84 #[inline]
85 pub const fn new() -> Self {
86 Self
87 }
88}
89impl SelectLimitSet {
90 #[inline]
91 pub const fn new() -> Self {
92 Self
93 }
94}
95impl SelectOffsetSet {
96 #[inline]
97 pub const fn new() -> Self {
98 Self
99 }
100}
101
102#[doc(hidden)]
103macro_rules! join_impl {
104 () => {
105 join_impl!(natural);
106 join_impl!(natural_left);
107 join_impl!(left);
108 join_impl!(left_outer);
109 join_impl!(natural_left_outer);
110 join_impl!(natural_right);
111 join_impl!(right);
112 join_impl!(right_outer);
113 join_impl!(natural_right_outer);
114 join_impl!(natural_full);
115 join_impl!(full);
116 join_impl!(full_outer);
117 join_impl!(natural_full_outer);
118 join_impl!(inner);
119 join_impl!(cross);
120
121 join_using_impl!(left);
123 join_using_impl!(left_outer);
124 join_using_impl!(right);
125 join_using_impl!(right_outer);
126 join_using_impl!(full);
127 join_using_impl!(full_outer);
128 join_using_impl!(inner);
129 join_using_impl!(); };
131 ($type:ident) => {
132 paste! {
133 pub fn [<$type _join>]<U: PostgresTable<'a>>(
135 self,
136 table: U,
137 condition: impl ToPostgresSQL<'a>,
138 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
139 SelectBuilder {
140 sql: self.sql.append(helpers::[<$type _join>](table, condition)),
141 schema: PhantomData,
142 state: PhantomData,
143 table: PhantomData,
144 }
145 }
146 }
147 };
148}
149
150macro_rules! join_using_impl {
151 () => {
152 pub fn join_using<U: PostgresTable<'a>>(
154 self,
155 table: U,
156 columns: impl ToPostgresSQL<'a>,
157 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
158 SelectBuilder {
159 sql: self.sql.append(helpers::join_using(table, columns)),
160 schema: PhantomData,
161 state: PhantomData,
162 table: PhantomData,
163 }
164 }
165 };
166 ($type:ident) => {
167 paste! {
168 pub fn [<$type _join_using>]<U: PostgresTable<'a>>(
170 self,
171 table: U,
172 columns: impl ToPostgresSQL<'a>,
173 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
174 SelectBuilder {
175 sql: self.sql.append(helpers::[<$type _join_using>](table, columns)),
176 schema: PhantomData,
177 state: PhantomData,
178 table: PhantomData,
179 }
180 }
181 }
182 };
183}
184
185impl ExecutableState for SelectFromSet {}
187impl ExecutableState for SelectWhereSet {}
188impl ExecutableState for SelectLimitSet {}
189impl ExecutableState for SelectOffsetSet {}
190impl ExecutableState for SelectOrderSet {}
191impl ExecutableState for SelectGroupSet {}
192impl ExecutableState for SelectJoinSet {}
193
194pub type SelectBuilder<'a, Schema, State, Table = ()> =
200 super::QueryBuilder<'a, Schema, State, Table>;
201
202impl<'a, S> SelectBuilder<'a, S, SelectInitial> {
207 #[inline]
209 pub fn from<T>(self, query: T) -> SelectBuilder<'a, S, SelectFromSet, T>
210 where
211 T: ToPostgresSQL<'a>,
212 {
213 SelectBuilder {
214 sql: self.sql.append(helpers::from(query)),
215 schema: PhantomData,
216 state: PhantomData,
217 table: PhantomData,
218 }
219 }
220}
221
222impl<'a, S, T> SelectBuilder<'a, S, SelectFromSet, T>
227where
228 T: SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>,
229{
230 #[inline]
232 pub fn join<U: PostgresTable<'a>>(
233 self,
234 table: U,
235 condition: SQL<'a, PostgresValue<'a>>,
236 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
237 SelectBuilder {
238 sql: self.sql.append(helpers::join(table, condition)),
239 schema: PhantomData,
240 state: PhantomData,
241 table: PhantomData,
242 }
243 }
244
245 join_impl!();
246
247 #[inline]
248 pub fn r#where(
249 self,
250 condition: SQL<'a, PostgresValue<'a>>,
251 ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
252 SelectBuilder {
253 sql: self.sql.append(helpers::r#where(condition)),
254 schema: PhantomData,
255 state: PhantomData,
256 table: PhantomData,
257 }
258 }
259
260 pub fn group_by(
262 self,
263 expressions: Vec<SQL<'a, PostgresValue<'a>>>,
264 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
265 SelectBuilder {
266 sql: self.sql.append(helpers::group_by(expressions)),
267 schema: PhantomData,
268 state: PhantomData,
269 table: PhantomData,
270 }
271 }
272
273 #[inline]
275 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
276 SelectBuilder {
277 sql: self.sql.append(helpers::limit(limit)),
278 schema: PhantomData,
279 state: PhantomData,
280 table: PhantomData,
281 }
282 }
283
284 #[inline]
286 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
287 SelectBuilder {
288 sql: self.sql.append(helpers::offset(offset)),
289 schema: PhantomData,
290 state: PhantomData,
291 table: PhantomData,
292 }
293 }
294
295 #[inline]
297 pub fn order_by<TOrderBy>(
298 self,
299 expressions: TOrderBy,
300 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
301 where
302 TOrderBy: ToPostgresSQL<'a>,
303 {
304 SelectBuilder {
305 sql: self.sql.append(helpers::order_by(expressions)),
306 schema: PhantomData,
307 state: PhantomData,
308 table: PhantomData,
309 }
310 }
311}
312
313impl<'a, S, T> SelectBuilder<'a, S, SelectJoinSet, T> {
318 #[inline]
320 pub fn r#where(
321 self,
322 condition: SQL<'a, PostgresValue<'a>>,
323 ) -> SelectBuilder<'a, S, SelectWhereSet, T> {
324 SelectBuilder {
325 sql: self.sql.append(crate::helpers::r#where(condition)),
326 schema: PhantomData,
327 state: PhantomData,
328 table: PhantomData,
329 }
330 }
331 #[inline]
333 pub fn order_by<TOrderBy>(
334 self,
335 expressions: TOrderBy,
336 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
337 where
338 TOrderBy: ToPostgresSQL<'a>,
339 {
340 SelectBuilder {
341 sql: self.sql.append(helpers::order_by(expressions)),
342 schema: PhantomData,
343 state: PhantomData,
344 table: PhantomData,
345 }
346 }
347 #[inline]
349 pub fn join<U: PostgresTable<'a>>(
350 self,
351 table: U,
352 condition: SQL<'a, PostgresValue<'a>>,
353 ) -> SelectBuilder<'a, S, SelectJoinSet, T> {
354 SelectBuilder {
355 sql: self.sql.append(helpers::join(table, condition)),
356 schema: PhantomData,
357 state: PhantomData,
358 table: PhantomData,
359 }
360 }
361 join_impl!();
362}
363
364impl<'a, S, T> SelectBuilder<'a, S, SelectWhereSet, T> {
369 pub fn group_by(
371 self,
372 expressions: Vec<SQL<'a, PostgresValue<'a>>>,
373 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
374 SelectBuilder {
375 sql: self.sql.append(helpers::group_by(expressions)),
376 schema: PhantomData,
377 state: PhantomData,
378 table: PhantomData,
379 }
380 }
381
382 pub fn order_by<TOrderBy>(
384 self,
385 expressions: TOrderBy,
386 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
387 where
388 TOrderBy: ToPostgresSQL<'a>,
389 {
390 SelectBuilder {
391 sql: self.sql.append(helpers::order_by(expressions)),
392 schema: PhantomData,
393 state: PhantomData,
394 table: PhantomData,
395 }
396 }
397
398 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
400 SelectBuilder {
401 sql: self.sql.append(helpers::limit(limit)),
402 schema: PhantomData,
403 state: PhantomData,
404 table: PhantomData,
405 }
406 }
407}
408
409impl<'a, S, T> SelectBuilder<'a, S, SelectGroupSet, T> {
414 pub fn having(
416 self,
417 condition: SQL<'a, PostgresValue<'a>>,
418 ) -> SelectBuilder<'a, S, SelectGroupSet, T> {
419 SelectBuilder {
420 sql: self.sql.append(helpers::having(condition)),
421 schema: PhantomData,
422 state: PhantomData,
423 table: PhantomData,
424 }
425 }
426
427 pub fn order_by<TOrderBy>(
429 self,
430 expressions: TOrderBy,
431 ) -> SelectBuilder<'a, S, SelectOrderSet, T>
432 where
433 TOrderBy: ToPostgresSQL<'a>,
434 {
435 SelectBuilder {
436 sql: self.sql.append(helpers::order_by(expressions)),
437 schema: PhantomData,
438 state: PhantomData,
439 table: PhantomData,
440 }
441 }
442}
443
444impl<'a, S, T> SelectBuilder<'a, S, SelectOrderSet, T> {
449 pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T> {
451 SelectBuilder {
452 sql: self.sql.append(helpers::limit(limit)),
453 schema: PhantomData,
454 state: PhantomData,
455 table: PhantomData,
456 }
457 }
458}
459
460impl<'a, S, T> SelectBuilder<'a, S, SelectLimitSet, T> {
465 pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T> {
467 SelectBuilder {
468 sql: self.sql.append(helpers::offset(offset)),
469 schema: PhantomData,
470 state: PhantomData,
471 table: PhantomData,
472 }
473 }
474}
475
476#[cfg(test)]
477mod tests {
478 use super::*;
479 use drizzle_core::{SQL, ToSQL};
480
481 #[test]
482 fn test_select_builder_creation() {
483 let builder = SelectBuilder::<(), SelectInitial> {
484 sql: SQL::raw("SELECT *"),
485 schema: PhantomData,
486 state: PhantomData,
487 table: PhantomData,
488 };
489
490 assert_eq!(builder.to_sql().sql(), "SELECT *");
491 }
492}