qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
use std::{marker::PhantomData, ops};

use crate::{
    BigInt, BinaryType, Bool, Double, Float, Int, MathType, Nullable, Numeric,
    expression::{As, Binary, Bound, Column, Expression, LitNumber, Scalar},
    lower::{Instructions, LowerCtx},
};

macro_rules! define_math_binary {
    ($name:ident, $method:ident, $trait:ident, $variant:expr) => {
        pub struct $name<L, R, Out> {
            pub(crate) left: L,
            pub(crate) right: R,
            pub(crate) marker: PhantomData<Out>,
        }

        #[qraft_expression_macro::as_expression]
        impl<L, R, Out> Expression for $name<L, R, Out>
        where
            L: Expression,
            R: Expression,
            L::Type: Numeric,
            R::Type: Numeric,
            Out: Numeric,
            BinaryType<L::Type, R::Type>: MathType<Output = Out>,
        {
            type Type = Out;

            fn lower(&self, ctx: &mut LowerCtx) -> usize {
                let lhs = self.left.lower(ctx);
                let rhs = self.right.lower(ctx);
                ctx.instrs.push_binary($variant, lhs, rhs);
                lhs + rhs + 1
            }
        }

        impl<M, T, Rhs, Out> ops::$trait<Rhs> for Column<M, T>
        where
            T: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<T, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }

        impl<M, T, Rhs, Out> ops::$trait<Rhs> for As<Column<M, T>>
        where
            T: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<T, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }

        impl<T, Rhs, Out> ops::$trait<Rhs> for Scalar<T>
        where
            T: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<T, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }

        impl<Op, L, R, Rhs, LeftTy, Out> ops::$trait<Rhs> for Binary<Op, L, R>
        where
            Self: Expression<Type = LeftTy>,
            LeftTy: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<LeftTy, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }

        impl<T, Rhs, Out> ops::$trait<Rhs> for LitNumber<T>
        where
            T: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<T, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }

        impl<L, R, Current, Rhs, Out> ops::$trait<Rhs> for $name<L, R, Current>
        where
            Self: Expression<Type = Current>,
            Current: Numeric,
            Rhs: Expression,
            Rhs::Type: Numeric,
            Out: Numeric,
            BinaryType<Current, Rhs::Type>: MathType<Output = Out>,
        {
            type Output = $name<Self, Rhs, Out>;

            fn $method(self, rhs: Rhs) -> Self::Output {
                $name {
                    left: self,
                    right: rhs,
                    marker: PhantomData,
                }
            }
        }
    };
}

define_math_binary!(MathAdd, add, Add, super::Operator::Add);
define_math_binary!(MathSub, sub, Sub, super::Operator::Sub);
define_math_binary!(MathMul, mul, Mul, super::Operator::Mul);
define_math_binary!(MathDiv, div, Div, super::Operator::Div);
define_math_binary!(MathRem, rem, Rem, super::Operator::Rem);

impl Expression for i32 {
    type Type = Int;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<Int>::new((*self).into()).lower(ctx)
    }
}

impl Expression for i64 {
    type Type = BigInt;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<BigInt>::new((*self).into()).lower(ctx)
    }
}

impl Expression for f32 {
    type Type = Float;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<Float>::new((*self).into()).lower(ctx)
    }
}

impl Expression for f64 {
    type Type = Double;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<Double>::new((*self).into()).lower(ctx)
    }
}

impl Expression for bool {
    type Type = Bool;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<Bool>::new((*self).into()).lower(ctx)
    }
}

impl Expression for Option<bool> {
    type Type = Nullable<Bool>;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        Bound::<Nullable<Bool>>::new((*self).into()).lower(ctx)
    }
}