qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
//! `from` clause lowering and table sources.

use std::marker::PhantomData;

use crate::{
    Qrafting, Query,
    alias::{Alias, Aliased},
    builder::{FormatContext, FormatWriter},
    count_idents, impl_for_all_tuples,
    lower::{Instructions, LowerCtx},
};

/// Lowers a complete `from` clause into the query instruction stream.
pub trait LowerFrom {
    /// Appends the source or sources to the lowering context.
    fn lower_from(self, ctx: &mut LowerCtx);
}

/// Lowers a single source item inside a `from` clause.
pub trait LowerFromItem {
    /// Appends one source item to the lowering context.
    fn lower_from_item(self, ctx: &mut LowerCtx);
}

impl<T> LowerFrom for T
where
    T: LowerFromItem,
{
    fn lower_from(self, ctx: &mut LowerCtx) {
        self.lower_from_item(ctx);
    }
}

impl<T> LowerFromItem for Aliased<T>
where
    T: Alias + LowerFromItem,
{
    fn lower_from_item(self, ctx: &mut LowerCtx) {
        self.inner.lower_from_item(ctx);
        let _ = ctx.lower_alias(self.alias, 1);
    }
}

impl LowerFromItem for Aliased<Query> {
    fn lower_from_item(self, ctx: &mut LowerCtx) {
        let alias = self.alias;
        let inner_query = self.inner;
        let inner = ctx.lower_subquery_ref(&inner_query);
        let _ = ctx.lower_alias(alias, inner);
    }
}

impl LowerFromItem for &'static str {
    fn lower_from_item(self, ctx: &mut LowerCtx) {
        let _ = ctx.lower_table(self);
    }
}

impl<M> Alias for Table<M> {}

impl<M> LowerFromItem for Table<M> {
    fn lower_from_item(self, ctx: &mut LowerCtx) {
        let _ = ctx.lower_table(self.table);
    }
}

/// A typed table reference.
#[derive(Debug)]
pub struct Table<M> {
    /// SQL table name as it should be emitted.
    pub table: &'static str,
    marker: PhantomData<M>,
}

impl<M> FormatWriter for Table<M>
where
    M: Qrafting,
{
    fn format_writer<'w, W: std::fmt::Write>(
        &self,
        context: &mut FormatContext<'w, W>,
    ) -> std::fmt::Result {
        context.write_table(M::TABLE)
    }
}

impl<M> Copy for Table<M> {}

impl<M> Clone for Table<M> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<M> Table<M> {
    /// Creates a typed table reference from a static name.
    pub const fn new(table: &'static str) -> Self {
        Self {
            table,
            marker: PhantomData,
        }
    }

    /// Returns the underlying SQL table name.
    pub const fn name(self) -> &'static str {
        self.table
    }
}

// impl for tuples
macro_rules! impl_from_macro {
    ($($T:ident),+) => {
        impl<$($T,)+> LowerFrom for ($($T,)+)
        where
            $($T: LowerFrom,)+
        {
            fn lower_from(self, ctx: &mut LowerCtx) {
                #[allow(non_snake_case)]
                let ($($T,)+) = self;
                $(
                    $T.lower_from(ctx);
                )+
                let count = count_idents!($($T,)+);
                ctx.instrs.push_cross_join(count);
            }
        }
    };
}

impl_for_all_tuples!(impl_from_macro);