use crate::{
alias::Aliased,
count_idents,
expression::Expression,
impl_for_all_tuples,
lower::{Instructions, LowerCtx},
query::LowerProject,
};
pub trait LowerOrderBy {
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);
}
}
pub trait Order: Sized {
fn asc(self) -> OrderNode<Self>;
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,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortKind {
Asc,
Desc,
}
#[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);