1use crate::common::PostgresSchemaType;
2use crate::helpers;
3use crate::traits::PostgresTable;
4use crate::values::PostgresValue;
5use core::marker::PhantomData;
6use drizzle_core::ToSQL;
7use drizzle_core::traits::SQLTable;
8use paste::paste;
9
10use super::ExecutableState;
12
13pub use drizzle_core::builder::{
18 AsCteState, SelectFromSet, SelectGroupSet, SelectInitial, SelectJoinSet, SelectLimitSet,
19 SelectOffsetSet, SelectOrderSet, SelectSetOpSet, SelectWhereSet,
20};
21
22#[doc(hidden)]
23pub trait SelectWhereAllowed: drizzle_core::WhereAllowed {}
24
25impl SelectWhereAllowed for SelectFromSet {}
26impl SelectWhereAllowed for SelectJoinSet {}
27
28#[derive(Debug, Clone, Copy, Default)]
30pub struct SelectForSet;
31
32#[doc(hidden)]
37macro_rules! join_impl {
38 () => {
39 join_impl!(natural, Join::new().natural(), drizzle_core::AfterJoin);
40 join_impl!(natural_left, Join::new().natural().left(), drizzle_core::AfterLeftJoin);
41 join_impl!(left, Join::new().left(), drizzle_core::AfterLeftJoin);
42 join_impl!(left_outer, Join::new().left().outer(), drizzle_core::AfterLeftJoin);
43 join_impl!(natural_left_outer, Join::new().natural().left().outer(), drizzle_core::AfterLeftJoin);
44 join_impl!(natural_right, Join::new().natural().right(), drizzle_core::AfterRightJoin);
45 join_impl!(right, Join::new().right(), drizzle_core::AfterRightJoin);
46 join_impl!(right_outer, Join::new().right().outer(), drizzle_core::AfterRightJoin);
47 join_impl!(natural_right_outer, Join::new().natural().right().outer(), drizzle_core::AfterRightJoin);
48 join_impl!(natural_full, Join::new().natural().full(), drizzle_core::AfterFullJoin);
49 join_impl!(full, Join::new().full(), drizzle_core::AfterFullJoin);
50 join_impl!(full_outer, Join::new().full().outer(), drizzle_core::AfterFullJoin);
51 join_impl!(natural_full_outer, Join::new().natural().full().outer(), drizzle_core::AfterFullJoin);
52 join_impl!(inner, Join::new().inner(), drizzle_core::AfterJoin);
53 join_impl!(cross, Join::new().cross(), drizzle_core::AfterJoin);
54
55 join_using_impl!(left, drizzle_core::AfterLeftJoin);
57 join_using_impl!(left_outer, drizzle_core::AfterLeftJoin);
58 join_using_impl!(right, drizzle_core::AfterRightJoin);
59 join_using_impl!(right_outer, drizzle_core::AfterRightJoin);
60 join_using_impl!(full, drizzle_core::AfterFullJoin);
61 join_using_impl!(full_outer, drizzle_core::AfterFullJoin);
62 join_using_impl!(inner, drizzle_core::AfterJoin);
63 join_using_impl!(); };
65 ($type:ident, $join_expr:expr, $join_trait:path) => {
66 paste! {
67 pub fn [<$type _join>]<J: crate::helpers::JoinArg<'a, T>>(
69 self,
70 arg: J,
71 ) -> SelectBuilder<'a, S, SelectJoinSet, J::JoinedTable, <M as drizzle_core::ScopePush<J::JoinedTable>>::Out, <M as $join_trait<R, J::JoinedTable>>::NewRow, G>
72 where
73 M: $join_trait<R, J::JoinedTable> + drizzle_core::ScopePush<J::JoinedTable>,
74 {
75 use drizzle_core::Join;
76 SelectBuilder {
77 sql: self.sql.append(arg.into_join_sql($join_expr)),
78 schema: PhantomData,
79 state: PhantomData,
80 table: PhantomData,
81 marker: PhantomData,
82 row: PhantomData,
83 grouped: PhantomData,
84 }
85 }
86 }
87 };
88}
89
90macro_rules! join_using_impl {
91 () => {
92 pub fn join_using<U: PostgresTable<'a>>(
94 self,
95 table: U,
96 columns: impl ToSQL<'a, PostgresValue<'a>>,
97 ) -> SelectBuilder<
98 'a,
99 S,
100 SelectJoinSet,
101 U,
102 <M as drizzle_core::ScopePush<U>>::Out,
103 <M as drizzle_core::AfterJoin<R, U>>::NewRow,
104 G,
105 >
106 where
107 M: drizzle_core::AfterJoin<R, U> + drizzle_core::ScopePush<U>,
108 {
109 SelectBuilder {
110 sql: self.sql.append(helpers::join_using(table, columns)),
111 schema: PhantomData,
112 state: PhantomData,
113 table: PhantomData,
114 marker: PhantomData,
115 row: PhantomData,
116 grouped: PhantomData,
117 }
118 }
119 };
120 ($type:ident, $join_trait:path) => {
121 paste! {
122 pub fn [<$type _join_using>]<U: PostgresTable<'a>>(
124 self,
125 table: U,
126 columns: impl ToSQL<'a, PostgresValue<'a>>,
127 ) -> SelectBuilder<
128 'a,
129 S,
130 SelectJoinSet,
131 U,
132 <M as drizzle_core::ScopePush<U>>::Out,
133 <M as $join_trait<R, U>>::NewRow,
134 G,
135 >
136 where
137 M: $join_trait<R, U> + drizzle_core::ScopePush<U>,
138 {
139 SelectBuilder {
140 sql: self.sql.append(helpers::[<$type _join_using>](table, columns)),
141 schema: PhantomData,
142 state: PhantomData,
143 table: PhantomData,
144 marker: PhantomData,
145 row: PhantomData,
146 grouped: PhantomData,
147 }
148 }
149 }
150 };
151}
152
153impl ExecutableState for SelectForSet {}
158
159pub type SelectBuilder<'a, Schema, State, Table = (), Marker = (), Row = (), Grouped = ()> =
165 super::QueryBuilder<'a, Schema, State, Table, Marker, Row, Grouped>;
166
167impl<'a, S, M> SelectBuilder<'a, S, SelectInitial, (), M> {
172 #[inline]
174 #[allow(clippy::type_complexity)]
175 pub fn from<T>(
176 self,
177 query: T,
178 ) -> SelectBuilder<
179 'a,
180 S,
181 SelectFromSet,
182 T,
183 drizzle_core::Scoped<M, drizzle_core::Cons<T, drizzle_core::Nil>>,
184 <M as drizzle_core::ResolveRow<T>>::Row,
185 >
186 where
187 T: ToSQL<'a, PostgresValue<'a>>,
188 M: drizzle_core::ResolveRow<T>,
189 {
190 SelectBuilder {
191 sql: self.sql.append(helpers::from(query)),
192 schema: PhantomData,
193 state: PhantomData,
194 table: PhantomData,
195 marker: PhantomData,
196 row: PhantomData,
197 grouped: PhantomData,
198 }
199 }
200}
201
202impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
208where
209 State: drizzle_core::JoinAllowed,
210{
211 #[inline]
213 #[allow(clippy::type_complexity)]
214 pub fn join<J: crate::helpers::JoinArg<'a, T>>(
215 self,
216 arg: J,
217 ) -> SelectBuilder<
218 'a,
219 S,
220 SelectJoinSet,
221 J::JoinedTable,
222 <M as drizzle_core::ScopePush<J::JoinedTable>>::Out,
223 <M as drizzle_core::AfterJoin<R, J::JoinedTable>>::NewRow,
224 G,
225 >
226 where
227 M: drizzle_core::AfterJoin<R, J::JoinedTable> + drizzle_core::ScopePush<J::JoinedTable>,
228 {
229 use drizzle_core::Join;
230 SelectBuilder {
231 sql: self.sql.append(arg.into_join_sql(Join::new())),
232 schema: PhantomData,
233 state: PhantomData,
234 table: PhantomData,
235 marker: PhantomData,
236 row: PhantomData,
237 grouped: PhantomData,
238 }
239 }
240
241 join_impl!();
242}
243
244impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
246where
247 State: SelectWhereAllowed,
248{
249 #[inline]
251 pub fn r#where<E>(self, condition: E) -> SelectBuilder<'a, S, SelectWhereSet, T, M, R, G>
252 where
253 E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
254 E::SQLType: drizzle_core::types::BooleanLike,
255 {
256 SelectBuilder {
257 sql: self.sql.append(helpers::r#where(condition)),
258 schema: PhantomData,
259 state: PhantomData,
260 table: PhantomData,
261 marker: PhantomData,
262 row: PhantomData,
263 grouped: PhantomData,
264 }
265 }
266}
267
268impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
270where
271 State: drizzle_core::GroupByAllowed,
272{
273 pub fn group_by<Gr>(
275 self,
276 columns: Gr,
277 ) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, Gr::Columns>
278 where
279 Gr: drizzle_core::IntoGroupBy<'a, PostgresValue<'a>>,
280 {
281 SelectBuilder {
282 sql: self.sql.append(helpers::group_by_expr(columns)),
283 schema: PhantomData,
284 state: PhantomData,
285 table: PhantomData,
286 marker: PhantomData,
287 row: PhantomData,
288 grouped: PhantomData,
289 }
290 }
291}
292
293impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
295where
296 State: drizzle_core::HavingAllowed,
297{
298 pub fn having<E>(self, condition: E) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, G>
300 where
301 E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
302 E::SQLType: drizzle_core::types::BooleanLike,
303 {
304 SelectBuilder {
305 sql: self.sql.append(helpers::having(condition)),
306 schema: PhantomData,
307 state: PhantomData,
308 table: PhantomData,
309 marker: PhantomData,
310 row: PhantomData,
311 grouped: PhantomData,
312 }
313 }
314}
315
316impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
318where
319 State: drizzle_core::OrderByAllowed,
320{
321 #[inline]
323 pub fn order_by<TOrderBy>(
324 self,
325 expressions: TOrderBy,
326 ) -> SelectBuilder<'a, S, SelectOrderSet, T, M, R, G>
327 where
328 TOrderBy: ToSQL<'a, PostgresValue<'a>>,
329 {
330 SelectBuilder {
331 sql: self.sql.append(helpers::order_by(expressions)),
332 schema: PhantomData,
333 state: PhantomData,
334 table: PhantomData,
335 marker: PhantomData,
336 row: PhantomData,
337 grouped: PhantomData,
338 }
339 }
340}
341
342impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
344where
345 State: drizzle_core::LimitAllowed,
346{
347 #[inline]
354 #[must_use]
355 #[track_caller]
356 pub fn limit<P>(self, limit: P) -> SelectBuilder<'a, S, SelectLimitSet, T, M, R, G>
357 where
358 P: drizzle_core::PaginationArg<'a, PostgresValue<'a>>,
359 {
360 SelectBuilder {
361 sql: self.sql.append(helpers::limit(limit)),
362 schema: PhantomData,
363 state: PhantomData,
364 table: PhantomData,
365 marker: PhantomData,
366 row: PhantomData,
367 grouped: PhantomData,
368 }
369 }
370}
371
372impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
374where
375 State: drizzle_core::OffsetAllowed,
376{
377 #[inline]
384 #[must_use]
385 #[track_caller]
386 pub fn offset<P>(self, offset: P) -> SelectBuilder<'a, S, SelectOffsetSet, T, M, R, G>
387 where
388 P: drizzle_core::PaginationArg<'a, PostgresValue<'a>>,
389 {
390 SelectBuilder {
391 sql: self.sql.append(helpers::offset(offset)),
392 schema: PhantomData,
393 state: PhantomData,
394 table: PhantomData,
395 marker: PhantomData,
396 row: PhantomData,
397 grouped: PhantomData,
398 }
399 }
400}
401
402impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
407where
408 State: AsCteState,
409 T: SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>,
410{
411 #[inline]
413 #[must_use]
414 pub fn into_cte<Tag: drizzle_core::Tag + 'static>(
415 self,
416 ) -> super::CTEView<
417 'a,
418 <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::Aliased<Tag>,
419 Self,
420 > {
421 let name = Tag::NAME;
422 super::CTEView::new(
423 <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::alias::<Tag>(),
424 name,
425 self,
426 )
427 }
428}
429
430impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
435where
436 State: ExecutableState,
437{
438 pub fn union(
440 self,
441 other: impl IntoSelect<'a, S, M, R>,
442 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
443 SelectBuilder {
444 sql: helpers::union(self.sql, other.into_select()),
445 schema: PhantomData,
446 state: PhantomData,
447 table: PhantomData,
448 marker: PhantomData,
449 row: PhantomData,
450 grouped: PhantomData,
451 }
452 }
453
454 pub fn union_all(
456 self,
457 other: impl IntoSelect<'a, S, M, R>,
458 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
459 SelectBuilder {
460 sql: helpers::union_all(self.sql, other.into_select()),
461 schema: PhantomData,
462 state: PhantomData,
463 table: PhantomData,
464 marker: PhantomData,
465 row: PhantomData,
466 grouped: PhantomData,
467 }
468 }
469
470 pub fn intersect(
472 self,
473 other: impl IntoSelect<'a, S, M, R>,
474 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
475 SelectBuilder {
476 sql: helpers::intersect(self.sql, other.into_select()),
477 schema: PhantomData,
478 state: PhantomData,
479 table: PhantomData,
480 marker: PhantomData,
481 row: PhantomData,
482 grouped: PhantomData,
483 }
484 }
485
486 pub fn intersect_all(
488 self,
489 other: impl IntoSelect<'a, S, M, R>,
490 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
491 SelectBuilder {
492 sql: helpers::intersect_all(self.sql, other.into_select()),
493 schema: PhantomData,
494 state: PhantomData,
495 table: PhantomData,
496 marker: PhantomData,
497 row: PhantomData,
498 grouped: PhantomData,
499 }
500 }
501
502 pub fn except(
504 self,
505 other: impl IntoSelect<'a, S, M, R>,
506 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
507 SelectBuilder {
508 sql: helpers::except(self.sql, other.into_select()),
509 schema: PhantomData,
510 state: PhantomData,
511 table: PhantomData,
512 marker: PhantomData,
513 row: PhantomData,
514 grouped: PhantomData,
515 }
516 }
517
518 pub fn except_all(
520 self,
521 other: impl IntoSelect<'a, S, M, R>,
522 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
523 SelectBuilder {
524 sql: helpers::except_all(self.sql, other.into_select()),
525 schema: PhantomData,
526 state: PhantomData,
527 table: PhantomData,
528 marker: PhantomData,
529 row: PhantomData,
530 grouped: PhantomData,
531 }
532 }
533}
534
535impl<'a, S, State, T, M, R, G> drizzle_core::expr::Expr<'a, PostgresValue<'a>>
540 for SelectBuilder<'a, S, State, T, M, R, G>
541where
542 State: ExecutableState,
543 M: drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>,
544{
545 type SQLType = <M as drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>>::SQLType;
546 type Nullable = drizzle_core::expr::Null;
547 type Aggregate = drizzle_core::expr::Scalar;
548}
549
550pub trait IntoSelect<'a, S, M, R> {
557 type State: ExecutableState;
558 type Table;
559 fn into_select(self) -> SelectBuilder<'a, S, Self::State, Self::Table, M, R>;
560}
561
562impl<'a, S, State: ExecutableState, T, M, R, G> IntoSelect<'a, S, M, R>
563 for SelectBuilder<'a, S, State, T, M, R, G>
564{
565 type State = State;
566 type Table = T;
567 fn into_select(self) -> SelectBuilder<'a, S, State, T, M, R> {
568 SelectBuilder {
569 sql: self.sql,
570 schema: PhantomData,
571 state: PhantomData,
572 table: PhantomData,
573 marker: PhantomData,
574 row: PhantomData,
575 grouped: PhantomData,
576 }
577 }
578}
579
580pub trait ForLockableState {}
586
587impl ForLockableState for SelectFromSet {}
588impl ForLockableState for SelectWhereSet {}
589impl ForLockableState for SelectOrderSet {}
590impl ForLockableState for SelectLimitSet {}
591impl ForLockableState for SelectOffsetSet {}
592impl ForLockableState for SelectJoinSet {}
593impl ForLockableState for SelectGroupSet {}
594
595impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
596where
597 State: ForLockableState,
598{
599 #[must_use]
601 pub fn for_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
602 SelectBuilder {
603 sql: self.sql.append(helpers::for_update()),
604 schema: PhantomData,
605 state: PhantomData,
606 table: PhantomData,
607 marker: PhantomData,
608 row: PhantomData,
609 grouped: PhantomData,
610 }
611 }
612
613 #[must_use]
615 pub fn for_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
616 SelectBuilder {
617 sql: self.sql.append(helpers::for_share()),
618 schema: PhantomData,
619 state: PhantomData,
620 table: PhantomData,
621 marker: PhantomData,
622 row: PhantomData,
623 grouped: PhantomData,
624 }
625 }
626
627 #[must_use]
629 pub fn for_no_key_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
630 SelectBuilder {
631 sql: self.sql.append(helpers::for_no_key_update()),
632 schema: PhantomData,
633 state: PhantomData,
634 table: PhantomData,
635 marker: PhantomData,
636 row: PhantomData,
637 grouped: PhantomData,
638 }
639 }
640
641 #[must_use]
643 pub fn for_key_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
644 SelectBuilder {
645 sql: self.sql.append(helpers::for_key_share()),
646 schema: PhantomData,
647 state: PhantomData,
648 table: PhantomData,
649 marker: PhantomData,
650 row: PhantomData,
651 grouped: PhantomData,
652 }
653 }
654
655 pub fn for_update_of<U: PostgresTable<'a>>(
657 self,
658 table: U,
659 ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
660 SelectBuilder {
661 sql: self.sql.append(helpers::for_update_of(table.name())),
662 schema: PhantomData,
663 state: PhantomData,
664 table: PhantomData,
665 marker: PhantomData,
666 row: PhantomData,
667 grouped: PhantomData,
668 }
669 }
670
671 pub fn for_share_of<U: PostgresTable<'a>>(
673 self,
674 table: U,
675 ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
676 SelectBuilder {
677 sql: self.sql.append(helpers::for_share_of(table.name())),
678 schema: PhantomData,
679 state: PhantomData,
680 table: PhantomData,
681 marker: PhantomData,
682 row: PhantomData,
683 grouped: PhantomData,
684 }
685 }
686}
687
688impl<S, T, M, R, G> SelectBuilder<'_, S, SelectForSet, T, M, R, G> {
693 #[must_use]
695 pub fn nowait(self) -> Self {
696 SelectBuilder {
697 sql: self.sql.append(helpers::nowait()),
698 schema: PhantomData,
699 state: PhantomData,
700 table: PhantomData,
701 marker: PhantomData,
702 row: PhantomData,
703 grouped: PhantomData,
704 }
705 }
706
707 #[must_use]
709 pub fn skip_locked(self) -> Self {
710 SelectBuilder {
711 sql: self.sql.append(helpers::skip_locked()),
712 schema: PhantomData,
713 state: PhantomData,
714 table: PhantomData,
715 marker: PhantomData,
716 row: PhantomData,
717 grouped: PhantomData,
718 }
719 }
720}
721
722#[cfg(test)]
723mod tests {
724 use super::*;
725 use drizzle_core::{SQL, ToSQL};
726
727 #[test]
728 fn test_select_builder_creation() {
729 let builder = SelectBuilder::<(), SelectInitial> {
730 sql: SQL::raw("SELECT *"),
731 schema: PhantomData,
732 state: PhantomData,
733 table: PhantomData,
734 marker: PhantomData,
735 row: PhantomData,
736 grouped: PhantomData,
737 };
738
739 assert_eq!(builder.to_sql().sql(), "SELECT *");
740 }
741}