qraft-core 0.1.2

Core type system, query model, decoding, and SQL lowering primitives for qraft.
Documentation
//! Portable scalar function expressions.

use crate::{
    BigInt, Date, LowerCompatible, Numeric, Text, Time, Timestamp,
    expression::Expression,
    lower::{Instructions, LowerCtx},
};

/// Emits the dialect's random-number function.
pub struct Random;
/// Emits `current_date`.
pub struct CurrentDate;
/// Emits `current_time`.
pub struct CurrentTime;
/// Emits `current_timestamp`.
pub struct Now;
/// Emits a typed SQL `null`.
pub struct Null<T>(std::marker::PhantomData<T>);

/// Emits `lower(...)`.
pub struct Lower<E> {
    inner: E,
}

/// Emits `upper(...)`.
pub struct Upper<E> {
    inner: E,
}

/// Emits `length(...)`.
pub struct Length<E> {
    inner: E,
}

/// Emits `abs(...)`.
pub struct Abs<E> {
    inner: E,
}

/// Emits `round(...)`.
pub struct Round<E> {
    inner: E,
}

/// Emits `nullif(left, right)`.
pub struct NullIf<L, R> {
    left: L,
    right: R,
}

/// Emits `coalesce(left, right)`.
pub struct Coalesce<L, R> {
    left: L,
    right: R,
}

/// Builds a portable random-number expression.
pub fn random() -> Random {
    Random
}

/// Builds a `current_date` expression.
pub fn current_date() -> CurrentDate {
    CurrentDate
}

/// Builds a `current_time` expression.
pub fn current_time() -> CurrentTime {
    CurrentTime
}

/// Builds a `current_timestamp` expression.
pub fn now() -> Now {
    Now
}

/// Builds a typed `null` expression.
pub fn null<T>() -> Null<T> {
    Null(std::marker::PhantomData)
}

/// Builds a `lower(...)` expression.
pub fn lower<E>(inner: E) -> Lower<E> {
    Lower { inner }
}

/// Builds an `upper(...)` expression.
pub fn upper<E>(inner: E) -> Upper<E> {
    Upper { inner }
}

/// Builds a `length(...)` expression.
pub fn length<E>(inner: E) -> Length<E> {
    Length { inner }
}

/// Builds an `abs(...)` expression.
pub fn abs<E>(inner: E) -> Abs<E> {
    Abs { inner }
}

/// Builds a `round(...)` expression.
pub fn round<E>(inner: E) -> Round<E> {
    Round { inner }
}

/// Builds a `nullif(left, right)` expression.
pub fn null_if<L, R>(left: L, right: R) -> NullIf<L, R> {
    NullIf { left, right }
}

/// Builds a `coalesce(left, right)` expression.
pub fn coalesce<L, R>(left: L, right: R) -> Coalesce<L, R> {
    Coalesce { left, right }
}

#[qraft_expression_macro::as_expression]
impl Expression for Random {
    type Type = crate::Double;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        ctx.lower_fn("random", 0)
    }
}

#[qraft_expression_macro::as_expression]
impl Expression for CurrentDate {
    type Type = Date;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        ctx.lower_fn("current_date", 0)
    }
}

#[qraft_expression_macro::as_expression]
impl Expression for CurrentTime {
    type Type = Time;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        ctx.lower_fn("current_time", 0)
    }
}

#[qraft_expression_macro::as_expression]
impl Expression for Now {
    type Type = Timestamp;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        ctx.lower_fn("current_timestamp", 0)
    }
}

#[qraft_expression_macro::as_expression]
impl<T> Expression for Null<T>
where
    T: crate::TypeMeta,
{
    type Type = crate::Nullable<T>;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        ctx.lower_null()
    }
}

#[qraft_expression_macro::as_expression]
impl<E> Expression for Lower<E>
where
    E: Expression<Type = Text>,
{
    type Type = Text;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let inner = self.inner.lower(ctx);
        ctx.lower_fn("lower", inner)
    }
}

#[qraft_expression_macro::as_expression]
impl<E> Expression for Upper<E>
where
    E: Expression<Type = Text>,
{
    type Type = Text;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let inner = self.inner.lower(ctx);
        ctx.lower_fn("upper", inner)
    }
}

#[qraft_expression_macro::as_expression]
impl<E> Expression for Length<E>
where
    E: Expression<Type = Text>,
{
    type Type = BigInt;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let inner = self.inner.lower(ctx);
        ctx.lower_fn("length", inner)
    }
}

#[qraft_expression_macro::as_expression]
impl<E> Expression for Abs<E>
where
    E: Expression,
    E::Type: Numeric,
{
    type Type = E::Type;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let inner = self.inner.lower(ctx);
        ctx.lower_fn("abs", inner)
    }
}

#[qraft_expression_macro::as_expression]
impl<E> Expression for Round<E>
where
    E: Expression,
    E::Type: Numeric,
{
    type Type = E::Type;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let inner = self.inner.lower(ctx);
        ctx.lower_fn("round", inner)
    }
}

#[qraft_expression_macro::as_expression]
impl<L, R> Expression for NullIf<L, R>
where
    L: Expression,
    R: LowerCompatible<L::Type>,
{
    type Type = L::Type;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let lhs = self.left.lower(ctx);
        let rhs = self.right.lower_compatible(ctx);
        ctx.instrs.push_seperated(2);
        ctx.lower_fn("nullif", lhs + rhs + 1)
    }
}

#[qraft_expression_macro::as_expression]
impl<L, R> Expression for Coalesce<L, R>
where
    L: Expression,
    R: LowerCompatible<L::Type>,
{
    type Type = L::Type;

    fn lower(&self, ctx: &mut LowerCtx) -> usize {
        let lhs = self.left.lower(ctx);
        let rhs = self.right.lower_compatible(ctx);
        ctx.instrs.push_seperated(2);
        ctx.lower_fn("coalesce", lhs + rhs + 1)
    }
}