diesel/pg/query_builder/
distinct_on.rs

1use crate::expression::{SelectableExpression, ValidGrouping};
2use crate::pg::Pg;
3use crate::query_builder::group_by_clause::ValidGroupByClause;
4use crate::query_builder::order_clause::NoOrderClause;
5use crate::query_builder::{
6    AstPass, FromClause, QueryFragment, QueryId, SelectClauseExpression, SelectQuery,
7    SelectStatement,
8};
9use crate::query_dsl::group_by_dsl::ValidDistinctForGroupBy;
10use crate::query_dsl::methods::DistinctOnDsl;
11use crate::query_dsl::order_dsl::ValidOrderingForDistinct;
12use crate::result::QueryResult;
13use crate::sql_types::SingleValue;
14use crate::QuerySource;
15use diesel::query_builder::order_clause::OrderClause;
16
17/// Represents `DISTINCT ON (...)`
18#[derive(Debug, Clone, Copy, QueryId)]
19#[cfg(feature = "postgres_backend")]
20pub struct DistinctOnClause<T>(pub(crate) T);
21
22impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for NoOrderClause {}
23impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<(T,)> {}
24impl<T> ValidOrderingForDistinct<DistinctOnClause<T>> for OrderClause<T> where T: crate::Expression {}
25
26impl<S, G, D> ValidDistinctForGroupBy<S, G> for DistinctOnClause<D> where (D, S): ValidGrouping<G> {}
27
28impl<T> ValidOrderingForDistinct<DistinctOnClause<T>>
29    for OrderClause<crate::expression::operators::Asc<T>>
30where
31    T: crate::Expression,
32    T::SqlType: SingleValue,
33{
34}
35
36impl<T> ValidOrderingForDistinct<DistinctOnClause<T>>
37    for OrderClause<crate::expression::operators::Desc<T>>
38where
39    T: crate::Expression,
40    T::SqlType: SingleValue,
41{
42}
43
44macro_rules! valid_ordering {
45    // Special-case: for single tuple elements
46    // generate plain impls as well:
47    (
48        @optional_untuple:
49        [generics: $($T: ident)*]
50        [distinct: $D:ident]
51        [order: $O: ty,]
52    ) => {
53        // nothing if both a single tuple elements
54    };
55    (
56        @optional_untuple:
57        [generics: $($T: ident)*]
58        [distinct: $D:ident]
59        [order: $($O: ty,)*]
60    ) => {
61        #[diagnostic::do_not_recommend]
62        impl<$($T,)*> ValidOrderingForDistinct<DistinctOnClause<$D>>
63            for OrderClause<($($O,)*)>
64        {}
65    };
66    (
67        @optional_untuple:
68        [generics: $($T: ident)*]
69        [distinct: $($D:ident)*]
70        [order: $O: ty,]
71    ) => {
72        #[diagnostic::do_not_recommend]
73        impl<$($T,)*> ValidOrderingForDistinct<DistinctOnClause<($($D,)*)>>
74            for OrderClause<$O>
75        {}
76    };
77    (
78        @optional_untuple:
79        [generics: $($T: ident)*]
80        [distinct: $($D:ident)*]
81        [order: $($O: ty,)*]
82    ) => {};
83    // Special-case: rule out the all ident case if the
84    // corresponding flag is set
85    // We want to have these impls if
86    // the tuple sizes do **not** match
87    // therefore we set the flag below
88    (@impl_one:
89     [allow_plain = false]
90     $generics:tt
91     $distinct:tt
92     $other:tt
93     [$($T_:ident, )*]
94    ) => {
95        /* skip this one */
96    };
97    (@impl_one:
98     [allow_plain = $allow_plain: expr]
99     [generics: $($T:ident)*]
100     [distinct: $($D:ident)*]
101     [other: $($O:ident)*]
102     [$($Ty:ty, )*]
103    ) => {
104        #[diagnostic::do_not_recommend]
105        impl<$($T,)*> ValidOrderingForDistinct<DistinctOnClause<($($D, )*)>>
106            for OrderClause<($($Ty, )* $($O,)*)>
107        {}
108        valid_ordering!(@optional_untuple: [generics: $($T)*] [distinct: $($D)*] [order: $($Ty,)* $($O,)*]);
109    };
110    (
111        @perm:
112        $allow_plain:tt
113        $generics:tt
114        $distinct:tt
115        $other:tt
116        [acc: $([$($acc:tt)*])*]
117        $T:ident
118        $($rest:tt)*
119    ) => {
120        valid_ordering! {
121            @perm:
122            $allow_plain
123            $generics
124            $distinct
125            $other
126                [acc:
127                 $(
128                     [$($acc)* crate::expression::operators::Asc<$T>, ]
129                     [$($acc)*     $T  , ]
130                     [$($acc)* crate::expression::operators::Desc<$T>, ]
131                 )*
132                ]
133                $($rest)*
134        }
135    };
136    (
137        @perm:
138        $allow_plain:tt
139        $generics:tt
140        $distinct:tt
141        $other:tt
142        [acc: $($Tys:tt)*]
143        /* nothing left */
144    ) => (
145        $(
146            valid_ordering! {@impl_one:
147                $allow_plain
148                $generics
149                $distinct
150                $other
151                $Tys
152            }
153        )*
154    );
155    (@skip_distinct_rev: [generics: $($G: ident)*] [other: $($O: ident)*] [acc: $($T: ident)*]) => {
156        valid_ordering!(@perm:
157                        [allow_plain = true]
158                        [generics: $($G)*]
159                        [distinct: $($T)*]
160                        [other: $($O)* ]
161                        [acc: []]
162                        $($T)*
163        );
164    };
165    (@skip_distinct_rev: [generics: $($G: ident)*] [other: $($O: ident)*] [acc: $($I: ident)*] $T: ident $($Ts: ident)*) => {
166        valid_ordering!(
167            @skip_distinct_rev:
168            [generics: $($G)*]
169            [other: $($O)*]
170            [acc: $T $($I)*]
171            $($Ts)*
172        );
173    };
174    (@skip_distinct:
175     [generics: $($G: ident)*]
176     [acc: $($O: ident)*]
177     $T: ident
178    ) => {};
179    (@skip_distinct:
180     [generics: $($G: ident)*]
181     [acc: $($O: ident)*]
182     $T:ident $($Ts: ident)*
183    ) => {
184        valid_ordering!(@skip_distinct_rev:
185            [generics: $($G)*]
186            [other: $($O)* $T]
187            [acc: ]
188            $($Ts)*
189        );
190        valid_ordering!(@skip_distinct: [generics: $($G)*] [acc: $($O)* $T] $($Ts)*);
191    };
192    (@skip_order_rev: [generics: $($G: ident)*] [acc: $($T: ident)*]) => {
193        valid_ordering!(@perm:
194            [allow_plain = true]
195            [generics: $($G)*]
196            [distinct: $($G)*]
197            [other: ]
198            [acc: []]
199            $($T)*
200        );
201    };
202    (@skip_order_rev: [generics: $($G: ident)*] [acc: $($I: ident)*] $T: ident $($Ts: ident)*) => {
203        valid_ordering!(
204            @skip_order_rev:
205            [generics: $($G)*]
206            [acc: $T $($I)*]
207            $($Ts)*
208        );
209    };
210    (@skip_order:
211     [generics: $($G: ident)*]
212     $T: ident
213    ) => {};
214    (@skip_order:
215     [generics: $($G: ident)*]
216     $T: ident $($Ts: ident)*
217    ) => {
218        valid_ordering!(@skip_order_rev: [generics: $($G)*] [acc: ] $($Ts)*);
219        valid_ordering!(@skip_order: [generics: $($G)*] $($Ts)*);
220    };
221    (@reverse_list: [generics: $($G: ident)*] [acc: $($I: ident)*]) => {
222        valid_ordering!(@skip_order: [generics: $($G)*] $($I)*);
223        valid_ordering!(@skip_distinct: [generics: $($G)*] [acc: ] $($I)*);
224    };
225    (@reverse_list: [generics: $($G: ident)*] [acc: $($I: ident)*] $T: ident $($Ts: ident)*) => {
226        valid_ordering!(@reverse_list: [generics: $($G)*] [acc: $T $($I)*] $($Ts)*);
227    };
228    ($(
229        $Tuple:tt {
230            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
231        }
232    )+) => {
233        $(
234            valid_ordering!(@perm:
235                [allow_plain = false]
236                [generics: $($T)*]
237                [distinct: $($T)*]
238                [other: ]
239                [acc: []]
240                $($T)*
241            );
242            valid_ordering!(@reverse_list: [generics: $($T)*] [acc: ] $($T)*);
243        )*
244    }
245}
246
247// we only generate these impl up to a tuple size of 5 as we generate n*n + 4 impls here
248// If we would generate these impls up to max_table_column_count tuple elements that
249// would be a really large number for 128 tuple elements (~64k trait impls)
250// It's fine to increase this number at some point in the future gradually
251diesel_derives::__diesel_for_each_tuple!(valid_ordering, 5);
252
253/// A decorator trait for `OrderClause`
254/// It helps to have bounds on either Col, Asc<Col> and Desc<Col>.
255pub trait OrderDecorator {
256    /// A column on a database table.
257    type Column;
258}
259
260impl<C> OrderDecorator for C
261where
262    C: crate::Column,
263{
264    type Column = C;
265}
266
267impl<C> OrderDecorator for crate::helper_types::Asc<C> {
268    type Column = C;
269}
270
271impl<C> OrderDecorator for crate::helper_types::Desc<C> {
272    type Column = C;
273}
274
275impl<T> QueryFragment<Pg> for DistinctOnClause<T>
276where
277    T: QueryFragment<Pg>,
278{
279    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
280        out.push_sql("DISTINCT ON (");
281        self.0.walk_ast(out.reborrow())?;
282        out.push_sql(") ");
283        Ok(())
284    }
285}
286
287impl<ST, F, S, D, W, O, LOf, G, H, Selection> DistinctOnDsl<Selection>
288    for SelectStatement<FromClause<F>, S, D, W, O, LOf, G, H>
289where
290    G: ValidGroupByClause,
291    F: QuerySource,
292    Selection: SelectableExpression<F>,
293    Self: SelectQuery<SqlType = ST>,
294    O: ValidOrderingForDistinct<DistinctOnClause<Selection>>,
295    SelectStatement<FromClause<F>, S, DistinctOnClause<Selection>, W, O, LOf, G, H>:
296        SelectQuery<SqlType = ST>,
297    S: SelectClauseExpression<FromClause<F>>,
298    (Selection, S::Selection): ValidGrouping<G::Expressions>,
299{
300    type Output = SelectStatement<FromClause<F>, S, DistinctOnClause<Selection>, W, O, LOf, G, H>;
301
302    fn distinct_on(self, selection: Selection) -> Self::Output {
303        SelectStatement::new(
304            self.select,
305            self.from,
306            DistinctOnClause(selection),
307            self.where_clause,
308            self.order,
309            self.limit_offset,
310            self.group_by,
311            self.having,
312            self.locking,
313        )
314    }
315}