diesel/query_dsl/
positional_order_dsl.rs

1use crate::backend::{Backend, DieselReserveSpecialization};
2use crate::expression::helper_types::{Asc, Desc};
3use crate::expression::Expression;
4use crate::query_builder::{AstPass, QueryFragment, QueryId};
5use crate::QueryResult;
6
7/// The `positional_order_by` method
8///
9/// This trait is not yet part of Diesel's public API. It may change in the
10/// future without a major version bump.
11///
12/// This trait exists as a stop-gap for users who need to order by column position
13/// in their queries, so that they are not forced to drop entirely to raw SQL. The
14/// arguments to `positional_order_by` are not checked, nor is the select statement
15/// forced to be valid.
16pub trait PositionalOrderDsl<Expr: IntoPositionalOrderExpr> {
17    /// The type returned by `.positional_order_by`
18    type Output;
19
20    /// See the trait documentation.
21    fn positional_order_by(self, expr: Expr) -> Self::Output;
22}
23
24pub trait PositionalOrderExpr: Expression {}
25
26impl PositionalOrderExpr for OrderColumn {}
27impl<T: PositionalOrderExpr> PositionalOrderExpr for Asc<T> {}
28impl<T: PositionalOrderExpr> PositionalOrderExpr for Desc<T> {}
29
30pub trait IntoPositionalOrderExpr {
31    type Output: PositionalOrderExpr;
32
33    fn into_positional_expr(self) -> Self::Output;
34}
35
36impl IntoPositionalOrderExpr for u32 {
37    type Output = OrderColumn;
38
39    fn into_positional_expr(self) -> Self::Output {
40        self.into()
41    }
42}
43impl<T: PositionalOrderExpr> IntoPositionalOrderExpr for Asc<T> {
44    type Output = Asc<T>;
45
46    fn into_positional_expr(self) -> Self::Output {
47        self
48    }
49}
50impl<T: PositionalOrderExpr> IntoPositionalOrderExpr for Desc<T> {
51    type Output = Desc<T>;
52
53    fn into_positional_expr(self) -> Self::Output {
54        self
55    }
56}
57
58#[derive(Debug, Clone, Copy, QueryId)]
59pub struct OrderColumn(pub u32);
60
61impl Expression for OrderColumn {
62    type SqlType = crate::sql_types::Integer;
63}
64
65impl<DB> QueryFragment<DB> for OrderColumn
66where
67    DB: Backend + DieselReserveSpecialization,
68{
69    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
70        pass.push_sql(&self.0.to_string());
71        Ok(())
72    }
73}
74
75impl From<u32> for OrderColumn {
76    fn from(order: u32) -> Self {
77        OrderColumn(order)
78    }
79}
80
81macro_rules! impl_positional_order_expr_for_all_tuples {
82    ($(
83        $unused1:tt {
84            $(($idx:tt) -> $T:ident, $U:ident, $unused3:tt,)+
85        }
86    )+) => {
87        $(
88            impl<$($T: PositionalOrderExpr),+> PositionalOrderExpr for ($($T,)+) { }
89
90            impl<$($T, $U,)+> IntoPositionalOrderExpr for ($($T,)+)
91            where
92                $($T: IntoPositionalOrderExpr<Output = $U>,)+
93                $($U: PositionalOrderExpr,)+
94            {
95                type Output = ($($U,)+);
96
97                fn into_positional_expr(self) -> Self::Output {
98                    ($(self.$idx.into_positional_expr(),)+)
99                }
100            }
101        )+
102    };
103}
104
105diesel_derives::__diesel_for_each_tuple!(impl_positional_order_expr_for_all_tuples);