typed-sql 0.2.1

A strongly typed sql serialization/deserialization framework
Documentation
use crate::types::Primitive;
use crate::types::{Bind, Field};
use crate::{CheckedSql, Table};
use std::{fmt::Write, marker::PhantomData};

pub trait Predicate {
    fn write_predicate(&self, sql: &mut String);
}

pub struct And<H, T> {
    pub(crate) head: H,
    pub(crate) tail: T,
}

impl<H, T> Predicate for And<H, T>
where
    H: Predicate,
    T: Predicate,
{
    fn write_predicate(&self, sql: &mut String) {
        self.head.write_predicate(sql);
        sql.push_str(" AND ");
        self.tail.write_predicate(sql);
    }
}

impl<H: CheckedSql, T: CheckedSql> CheckedSql for And<H, T> {}

pub struct Or<H, T> {
    pub(crate) head: H,
    pub(crate) tail: T,
}

impl<H, T> Predicate for Or<H, T>
where
    H: Predicate,
    T: Predicate,
{
    fn write_predicate(&self, sql: &mut String) {
        self.head.write_predicate(sql);
        sql.push_str(" OR ");
        self.tail.write_predicate(sql);
    }
}

impl<H: CheckedSql, T: CheckedSql> CheckedSql for Or<H, T> {}

pub trait Operator {
    fn write_operator(sql: &mut String);
}

pub struct Eq;

impl Operator for Eq {
    fn write_operator(sql: &mut String) {
        sql.push('=');
    }
}

pub struct Neq;

impl Operator for Neq {
    fn write_operator(sql: &mut String) {
        sql.push_str("!=");
    }
}

pub struct Gt;

impl Operator for Gt {
    fn write_operator(sql: &mut String) {
        sql.push('>');
    }
}

pub struct Lt;

impl Operator for Lt {
    fn write_operator(sql: &mut String) {
        sql.push('<');
    }
}

pub struct Op<T, A, U, O> {
    lhs: Field<T, A>,
    rhs: U,
    _operator: PhantomData<O>,
}

impl<T, A, U, O> Op<T, A, U, O> {
    pub(crate) fn new(lhs: Field<T, A>, rhs: U) -> Self {
        Self {
            lhs,
            rhs,
            _operator: PhantomData,
        }
    }
}

impl<T, A, U, O> Predicate for Op<T, A, U, O>
where
    T: Table,
    U: Primitive,
    O: Operator,
{
    fn write_predicate(&self, sql: &mut String) {
        self.lhs.write_field(sql);
        sql.push(' ');
        O::write_operator(sql);
        sql.push(' ');
        self.rhs.write_primative(sql);
    }
}

impl<T, T2, A, O> Predicate for Op<T, A, Field<T2, A>, O>
where
    T: Table,
    T2: Table,
    O: Operator,
{
    fn write_predicate(&self, sql: &mut String) {
        self.lhs.write_field(sql);
        sql.push(' ');
        O::write_operator(sql);
        sql.push(' ');
        self.rhs.write_field(sql);
    }
}

impl<T, A, O> Predicate for Op<T, A, Bind, O>
where
    T: Table,
    O: Operator,
{
    fn write_predicate(&self, sql: &mut String) {
        self.lhs.write_field(sql);
        sql.push(' ');
        O::write_operator(sql);
        sql.write_fmt(format_args!(" ${}", self.rhs.n)).unwrap();
    }
}

impl<T, A, U: CheckedSql, O> CheckedSql for Op<T, A, U, O> {}