Skip to main content

qraft_core/select/
order.rs

1//! Ordering helpers for `order by`.
2
3use crate::{
4    alias::Aliased,
5    count_idents,
6    expression::Expression,
7    impl_for_all_tuples,
8    lower::{Instructions, LowerCtx},
9    query::LowerProject,
10};
11
12/// Lowers one or more `order by` expressions.
13pub trait LowerOrderBy {
14    /// Appends the ordering node or nodes to the lowering context.
15    fn lower_order_by(self, ctx: &mut LowerCtx);
16}
17
18impl<E> LowerOrderBy for E
19where
20    E: Expression,
21{
22    fn lower_order_by(self, ctx: &mut LowerCtx) {
23        self.lower(ctx);
24    }
25}
26
27impl LowerOrderBy for &'static str {
28    fn lower_order_by(self, ctx: &mut LowerCtx) {
29        ctx.lower_table(self);
30    }
31}
32
33impl<T: LowerProject> LowerOrderBy for Aliased<T> {
34    fn lower_order_by(self, ctx: &mut LowerCtx) {
35        ctx.lower_table(self.alias);
36    }
37}
38
39/// Adds `.asc()` and `.desc()` to orderable values.
40pub trait Order: Sized {
41    /// Marks the value as ascending.
42    fn asc(self) -> OrderNode<Self>;
43    /// Marks the value as descending.
44    fn desc(self) -> OrderNode<Self>;
45}
46
47impl<E> Order for E
48where
49    E: LowerOrderBy,
50{
51    fn asc(self) -> OrderNode<Self> {
52        OrderNode {
53            inner: self,
54            kind: SortKind::Asc,
55        }
56    }
57
58    fn desc(self) -> OrderNode<Self> {
59        OrderNode {
60            inner: self,
61            kind: SortKind::Desc,
62        }
63    }
64}
65
66/// Sort directions supported by `order by`.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum SortKind {
69    Asc,
70    Desc,
71}
72
73/// An expression paired with its sort direction.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub struct OrderNode<E> {
76    kind: SortKind,
77    inner: E,
78}
79
80impl<E> LowerOrderBy for OrderNode<E>
81where
82    E: LowerOrderBy,
83{
84    fn lower_order_by(self, ctx: &mut LowerCtx) {
85        self.inner.lower_order_by(ctx);
86        let _ = ctx.lower_order_by(self.kind, 1);
87    }
88}
89
90macro_rules! impl_orderby_macro {
91    ($($T:ident),+) => {
92        impl<$($T,)+> LowerOrderBy for ($($T,)+)
93        where
94            $($T: LowerOrderBy,)+
95        {
96            fn lower_order_by(self, ctx: &mut LowerCtx) {
97                #[allow(non_snake_case)]
98                let ($($T,)+) = self;
99                $(
100                    $T.lower_order_by(ctx);
101                )+
102                let count = count_idents!($($T,)+);
103                ctx.instrs.push_seperated(count);
104            }
105        }
106    };
107}
108
109impl_for_all_tuples!(impl_orderby_macro);