qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
//! Projection lowering for `select` and `returning` clauses.

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

/// Lowers projection values into a separated list of selected expressions.
pub trait LowerProject {
    /// Appends the projection to the lowering context.
    fn lower_project(self, ctx: &mut LowerCtx);
}

/// Marker for `*`.
#[derive(Debug, Clone, Copy)]
pub struct Star {
    _priv: (),
}

/// Returns a projection value for `*`.
pub fn star() -> Star {
    Star { _priv: () }
}

impl LowerProject for Star {
    fn lower_project(self, ctx: &mut LowerCtx) {
        let _ = ctx.lower_star();
    }
}

impl<E> LowerProject for E
where
    E: Expression,
{
    fn lower_project(self, ctx: &mut LowerCtx) {
        let _ = self.lower(ctx);
    }
}

impl<E> LowerProject for Aliased<E>
where
    E: Expression,
{
    fn lower_project(self, ctx: &mut LowerCtx) {
        let inner = self.inner.lower(ctx);
        let _ = ctx.lower_alias(self.alias, inner);
    }
}

impl LowerProject for &'static str {
    fn lower_project(self, ctx: &mut LowerCtx) {
        let span = TextSpan::new_static(self);
        ctx.instrs.push_column(None, span);
    }
}

impl LowerProject for Aliased<&'static str> {
    fn lower_project(self, ctx: &mut LowerCtx) {
        self.inner.lower_project(ctx);
        let _ = ctx.lower_alias(self.alias, 1);
    }
}

/// A table-qualified column used by generated pivot metadata.
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ColumnOf {
    /// Table name to qualify the column with.
    pub table: &'static str,
    /// Column name to emit.
    pub name: &'static str,
}

impl ColumnOf {
    /// Creates a table-qualified column description.
    pub const fn new(table: &'static str, name: &'static str) -> Self {
        Self { table, name }
    }
}

impl LowerProject for ColumnOf {
    fn lower_project(self, ctx: &mut LowerCtx) {
        let _ = ctx.lower_column(Some(self.table), self.name);
    }
}

impl LowerProject for Aliased<ColumnOf> {
    fn lower_project(self, ctx: &mut LowerCtx) {
        self.inner.lower_project(ctx);
        let _ = ctx.lower_alias(self.alias, 1);
    }
}

impl<T: LowerProject, const N: usize> LowerProject for [T; N] {
    fn lower_project(self, ctx: &mut LowerCtx) {
        let len = self.len();
        for item in self {
            item.lower_project(ctx);
        }
        ctx.instrs.push_seperated(len);
    }
}

impl<T: LowerProject> LowerProject for Vec<T> {
    fn lower_project(self, ctx: &mut LowerCtx) {
        let len = self.len();
        for item in self {
            item.lower_project(ctx);
        }
        ctx.instrs.push_seperated(len);
    }
}

// impl for tuples
// todo: change here when stable https://github.com/rust-lang/rust/issues/83527
macro_rules! impl_project_macro {
    ($($T:ident),+) => {
        impl<$($T,)+> LowerProject for ($($T,)+)
        where
            $($T: LowerProject,)+
        {
            fn lower_project(self, ctx: &mut LowerCtx) {
                #[allow(non_snake_case)]
                let ($($T,)+) = self;
                $(
                    $T.lower_project(ctx);
                )+
                let count = count_idents!($($T,)+);
                ctx.instrs.push_seperated(count);
            }
        }
    };
}

impl_for_all_tuples!(impl_project_macro);