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>(
281 self,
282 columns: Gr,
283 ) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, Gr::Columns>
284 where
285 Gr: drizzle_core::IntoGroupBy<'a, PostgresValue<'a>>,
286 {
287 SelectBuilder {
288 sql: self.sql.append(helpers::group_by_expr(columns)),
289 schema: PhantomData,
290 state: PhantomData,
291 table: PhantomData,
292 marker: PhantomData,
293 row: PhantomData,
294 grouped: PhantomData,
295 }
296 }
297}
298
299impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
301where
302 State: drizzle_core::HavingAllowed,
303{
304 pub fn having<E>(self, condition: E) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, G>
306 where
307 E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
308 E::SQLType: drizzle_core::types::BooleanLike,
309 {
310 SelectBuilder {
311 sql: self.sql.append(helpers::having(condition)),
312 schema: PhantomData,
313 state: PhantomData,
314 table: PhantomData,
315 marker: PhantomData,
316 row: PhantomData,
317 grouped: PhantomData,
318 }
319 }
320}
321
322impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
324where
325 State: drizzle_core::OrderByAllowed,
326{
327 #[inline]
329 pub fn order_by<TOrderBy>(
330 self,
331 expressions: TOrderBy,
332 ) -> SelectBuilder<'a, S, SelectOrderSet, T, M, R, G>
333 where
334 TOrderBy: ToSQL<'a, PostgresValue<'a>>,
335 {
336 SelectBuilder {
337 sql: self.sql.append(helpers::order_by(expressions)),
338 schema: PhantomData,
339 state: PhantomData,
340 table: PhantomData,
341 marker: PhantomData,
342 row: PhantomData,
343 grouped: PhantomData,
344 }
345 }
346}
347
348impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
350where
351 State: drizzle_core::LimitAllowed,
352{
353 #[inline]
360 #[must_use]
361 #[track_caller]
362 pub fn limit<P>(self, limit: P) -> SelectBuilder<'a, S, SelectLimitSet, T, M, R, G>
363 where
364 P: drizzle_core::PaginationArg<'a, PostgresValue<'a>>,
365 {
366 SelectBuilder {
367 sql: self.sql.append(helpers::limit(limit)),
368 schema: PhantomData,
369 state: PhantomData,
370 table: PhantomData,
371 marker: PhantomData,
372 row: PhantomData,
373 grouped: PhantomData,
374 }
375 }
376}
377
378impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
380where
381 State: drizzle_core::OffsetAllowed,
382{
383 #[inline]
390 #[must_use]
391 #[track_caller]
392 pub fn offset<P>(self, offset: P) -> SelectBuilder<'a, S, SelectOffsetSet, T, M, R, G>
393 where
394 P: drizzle_core::PaginationArg<'a, PostgresValue<'a>>,
395 {
396 SelectBuilder {
397 sql: self.sql.append(helpers::offset(offset)),
398 schema: PhantomData,
399 state: PhantomData,
400 table: PhantomData,
401 marker: PhantomData,
402 row: PhantomData,
403 grouped: PhantomData,
404 }
405 }
406}
407
408impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
413where
414 State: AsCteState,
415 T: SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>,
416{
417 #[inline]
419 #[must_use]
420 pub fn into_cte<Tag: drizzle_core::Tag + 'static>(
421 self,
422 ) -> super::CTEView<
423 'a,
424 <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::Aliased<Tag>,
425 Self,
426 > {
427 let name = Tag::NAME;
428 super::CTEView::new(
429 <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::alias::<Tag>(),
430 name,
431 self,
432 )
433 }
434}
435
436impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
441where
442 State: ExecutableState,
443{
444 pub fn union(
446 self,
447 other: impl IntoSelect<'a, S, M, R>,
448 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
449 SelectBuilder {
450 sql: helpers::union(self.sql, other.into_select()),
451 schema: PhantomData,
452 state: PhantomData,
453 table: PhantomData,
454 marker: PhantomData,
455 row: PhantomData,
456 grouped: PhantomData,
457 }
458 }
459
460 pub fn union_all(
462 self,
463 other: impl IntoSelect<'a, S, M, R>,
464 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
465 SelectBuilder {
466 sql: helpers::union_all(self.sql, other.into_select()),
467 schema: PhantomData,
468 state: PhantomData,
469 table: PhantomData,
470 marker: PhantomData,
471 row: PhantomData,
472 grouped: PhantomData,
473 }
474 }
475
476 pub fn intersect(
478 self,
479 other: impl IntoSelect<'a, S, M, R>,
480 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
481 SelectBuilder {
482 sql: helpers::intersect(self.sql, other.into_select()),
483 schema: PhantomData,
484 state: PhantomData,
485 table: PhantomData,
486 marker: PhantomData,
487 row: PhantomData,
488 grouped: PhantomData,
489 }
490 }
491
492 pub fn intersect_all(
494 self,
495 other: impl IntoSelect<'a, S, M, R>,
496 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
497 SelectBuilder {
498 sql: helpers::intersect_all(self.sql, other.into_select()),
499 schema: PhantomData,
500 state: PhantomData,
501 table: PhantomData,
502 marker: PhantomData,
503 row: PhantomData,
504 grouped: PhantomData,
505 }
506 }
507
508 pub fn except(
510 self,
511 other: impl IntoSelect<'a, S, M, R>,
512 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
513 SelectBuilder {
514 sql: helpers::except(self.sql, other.into_select()),
515 schema: PhantomData,
516 state: PhantomData,
517 table: PhantomData,
518 marker: PhantomData,
519 row: PhantomData,
520 grouped: PhantomData,
521 }
522 }
523
524 pub fn except_all(
526 self,
527 other: impl IntoSelect<'a, S, M, R>,
528 ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
529 SelectBuilder {
530 sql: helpers::except_all(self.sql, other.into_select()),
531 schema: PhantomData,
532 state: PhantomData,
533 table: PhantomData,
534 marker: PhantomData,
535 row: PhantomData,
536 grouped: PhantomData,
537 }
538 }
539}
540
541impl<'a, S, State, T, M, R, G> drizzle_core::expr::Expr<'a, PostgresValue<'a>>
546 for SelectBuilder<'a, S, State, T, M, R, G>
547where
548 State: ExecutableState,
549 M: drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>,
550{
551 type SQLType = <M as drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>>::SQLType;
552 type Nullable = drizzle_core::expr::Null;
553 type Aggregate = drizzle_core::expr::Scalar;
554}
555
556pub trait IntoSelect<'a, S, M, R> {
563 type State: ExecutableState;
564 type Table;
565 fn into_select(self) -> SelectBuilder<'a, S, Self::State, Self::Table, M, R>;
566}
567
568impl<'a, S, State: ExecutableState, T, M, R, G> IntoSelect<'a, S, M, R>
569 for SelectBuilder<'a, S, State, T, M, R, G>
570{
571 type State = State;
572 type Table = T;
573 fn into_select(self) -> SelectBuilder<'a, S, State, T, M, R> {
574 SelectBuilder {
575 sql: self.sql,
576 schema: PhantomData,
577 state: PhantomData,
578 table: PhantomData,
579 marker: PhantomData,
580 row: PhantomData,
581 grouped: PhantomData,
582 }
583 }
584}
585
586pub trait ForLockableState {}
592
593impl ForLockableState for SelectFromSet {}
594impl ForLockableState for SelectWhereSet {}
595impl ForLockableState for SelectOrderSet {}
596impl ForLockableState for SelectLimitSet {}
597impl ForLockableState for SelectOffsetSet {}
598impl ForLockableState for SelectJoinSet {}
599impl ForLockableState for SelectGroupSet {}
600
601impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
602where
603 State: ForLockableState,
604{
605 #[must_use]
607 pub fn for_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
608 SelectBuilder {
609 sql: self.sql.append(helpers::for_update()),
610 schema: PhantomData,
611 state: PhantomData,
612 table: PhantomData,
613 marker: PhantomData,
614 row: PhantomData,
615 grouped: PhantomData,
616 }
617 }
618
619 #[must_use]
621 pub fn for_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
622 SelectBuilder {
623 sql: self.sql.append(helpers::for_share()),
624 schema: PhantomData,
625 state: PhantomData,
626 table: PhantomData,
627 marker: PhantomData,
628 row: PhantomData,
629 grouped: PhantomData,
630 }
631 }
632
633 #[must_use]
635 pub fn for_no_key_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
636 SelectBuilder {
637 sql: self.sql.append(helpers::for_no_key_update()),
638 schema: PhantomData,
639 state: PhantomData,
640 table: PhantomData,
641 marker: PhantomData,
642 row: PhantomData,
643 grouped: PhantomData,
644 }
645 }
646
647 #[must_use]
649 pub fn for_key_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
650 SelectBuilder {
651 sql: self.sql.append(helpers::for_key_share()),
652 schema: PhantomData,
653 state: PhantomData,
654 table: PhantomData,
655 marker: PhantomData,
656 row: PhantomData,
657 grouped: PhantomData,
658 }
659 }
660
661 pub fn for_update_of<U: PostgresTable<'a>>(
663 self,
664 table: U,
665 ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
666 SelectBuilder {
667 sql: self.sql.append(helpers::for_update_of(table.name())),
668 schema: PhantomData,
669 state: PhantomData,
670 table: PhantomData,
671 marker: PhantomData,
672 row: PhantomData,
673 grouped: PhantomData,
674 }
675 }
676
677 pub fn for_share_of<U: PostgresTable<'a>>(
679 self,
680 table: U,
681 ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
682 SelectBuilder {
683 sql: self.sql.append(helpers::for_share_of(table.name())),
684 schema: PhantomData,
685 state: PhantomData,
686 table: PhantomData,
687 marker: PhantomData,
688 row: PhantomData,
689 grouped: PhantomData,
690 }
691 }
692}
693
694impl<S, T, M, R, G> SelectBuilder<'_, S, SelectForSet, T, M, R, G> {
699 #[must_use]
701 pub fn nowait(self) -> Self {
702 SelectBuilder {
703 sql: self.sql.append(helpers::nowait()),
704 schema: PhantomData,
705 state: PhantomData,
706 table: PhantomData,
707 marker: PhantomData,
708 row: PhantomData,
709 grouped: PhantomData,
710 }
711 }
712
713 #[must_use]
715 pub fn skip_locked(self) -> Self {
716 SelectBuilder {
717 sql: self.sql.append(helpers::skip_locked()),
718 schema: PhantomData,
719 state: PhantomData,
720 table: PhantomData,
721 marker: PhantomData,
722 row: PhantomData,
723 grouped: PhantomData,
724 }
725 }
726}
727
728#[cfg(test)]
729mod tests {
730 use super::*;
731 use drizzle_core::{SQL, ToSQL};
732
733 #[test]
734 fn test_select_builder_creation() {
735 let builder = SelectBuilder::<(), SelectInitial> {
736 sql: SQL::raw("SELECT *"),
737 schema: PhantomData,
738 state: PhantomData,
739 table: PhantomData,
740 marker: PhantomData,
741 row: PhantomData,
742 grouped: PhantomData,
743 };
744
745 assert_eq!(builder.to_sql().sql(), "SELECT *");
746 }
747}