qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
//! Ordering helpers for `order by`.

use crate::{
    alias::Aliased,
    count_idents,
    expression::Expression,
    impl_for_all_tuples,
    lower::{Instructions, LowerCtx},
    query::LowerProject,
};

/// Lowers one or more `order by` expressions.
pub trait LowerOrderBy {
    /// Appends the ordering node or nodes to the lowering context.
    fn lower_order_by(self, ctx: &mut LowerCtx);
}

impl<E> LowerOrderBy for E
where
    E: Expression,
{
    fn lower_order_by(self, ctx: &mut LowerCtx) {
        self.lower(ctx);
    }
}

impl LowerOrderBy for &'static str {
    fn lower_order_by(self, ctx: &mut LowerCtx) {
        ctx.lower_table(self);
    }
}

impl<T: LowerProject> LowerOrderBy for Aliased<T> {
    fn lower_order_by(self, ctx: &mut LowerCtx) {
        ctx.lower_table(self.alias);
    }
}

/// Adds `.asc()` and `.desc()` to orderable values.
pub trait Order: Sized {
    /// Marks the value as ascending.
    fn asc(self) -> OrderNode<Self>;
    /// Marks the value as descending.
    fn desc(self) -> OrderNode<Self>;
}

impl<E> Order for E
where
    E: LowerOrderBy,
{
    fn asc(self) -> OrderNode<Self> {
        OrderNode {
            inner: self,
            kind: SortKind::Asc,
        }
    }

    fn desc(self) -> OrderNode<Self> {
        OrderNode {
            inner: self,
            kind: SortKind::Desc,
        }
    }
}

/// Sort directions supported by `order by`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortKind {
    Asc,
    Desc,
}

/// An expression paired with its sort direction.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrderNode<E> {
    kind: SortKind,
    inner: E,
}

impl<E> LowerOrderBy for OrderNode<E>
where
    E: LowerOrderBy,
{
    fn lower_order_by(self, ctx: &mut LowerCtx) {
        self.inner.lower_order_by(ctx);
        let _ = ctx.lower_order_by(self.kind, 1);
    }
}

macro_rules! impl_orderby_macro {
    ($($T:ident),+) => {
        impl<$($T,)+> LowerOrderBy for ($($T,)+)
        where
            $($T: LowerOrderBy,)+
        {
            fn lower_order_by(self, ctx: &mut LowerCtx) {
                #[allow(non_snake_case)]
                let ($($T,)+) = self;
                $(
                    $T.lower_order_by(ctx);
                )+
                let count = count_idents!($($T,)+);
                ctx.instrs.push_seperated(count);
            }
        }
    };
}

impl_for_all_tuples!(impl_orderby_macro);