gorm 0.1.4

An orm that is simple to use and prevents all mistakes at compile time
Documentation
use std::{fmt::Write, marker::PhantomData};

use rust_decimal::Decimal;

use crate::sql::{
    AverageableSqlType, OrderableSqlType, ParameterBinder, SelectableTables, SqlExpression, SqlI64,
    SqlNumeric, SqlType, SummableSqlType,
};

pub struct SqlCountRows;

impl<S: SelectableTables> SqlExpression<S> for SqlCountRows {
    type RustType = i64;
    type SqlType = SqlI64;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        _parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "COUNT(*)")
    }
}

pub struct SqlCount<S: SelectableTables, E: SqlExpression<S>> {
    expr: E,
    phantom: PhantomData<S>,
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlCount<S, E> {
    pub fn new(expr: E) -> Self {
        Self {
            expr,
            phantom: PhantomData,
        }
    }
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlExpression<S> for SqlCount<S, E> {
    type RustType = i64;
    type SqlType = SqlI64;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "COUNT(")?;
        self.expr.write_sql_string(f, parameter_binder)?;
        write!(f, ")")?;
        Ok(())
    }
}

pub struct SqlAverage<S: SelectableTables, E: SqlExpression<S>>
where
    E::SqlType: AverageableSqlType,
{
    expr: E,
    phantom: PhantomData<S>,
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlAverage<S, E>
where
    E::SqlType: AverageableSqlType,
{
    pub fn new(expr: E) -> Self {
        Self {
            expr,
            phantom: PhantomData,
        }
    }
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlExpression<S> for SqlAverage<S, E>
where
    E::SqlType: AverageableSqlType,
{
    type RustType = Decimal;
    type SqlType = SqlNumeric;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "AVG(")?;
        self.expr.write_sql_string(f, parameter_binder)?;
        write!(f, ")")?;
        Ok(())
    }
}

pub struct SqlSum<S: SelectableTables, E: SqlExpression<S>>
where
    E::SqlType: SummableSqlType,
{
    expr: E,
    phantom: PhantomData<S>,
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlSum<S, E>
where
    E::SqlType: SummableSqlType,
{
    pub fn new(expr: E) -> Self {
        Self {
            expr,
            phantom: PhantomData,
        }
    }
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlExpression<S> for SqlSum<S, E>
where
    E::SqlType: SummableSqlType,
{
    type RustType = <<E::SqlType as SummableSqlType>::OutputSqlType as SqlType>::RustType;
    type SqlType = <E::SqlType as SummableSqlType>::OutputSqlType;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "SUM(")?;
        self.expr.write_sql_string(f, parameter_binder)?;
        write!(f, ")")?;
        Ok(())
    }
}

pub struct SqlMax<S: SelectableTables, E: SqlExpression<S>>
where
    E::SqlType: OrderableSqlType,
{
    expr: E,
    phantom: PhantomData<S>,
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlMax<S, E>
where
    E::SqlType: OrderableSqlType,
{
    pub fn new(expr: E) -> Self {
        Self {
            expr,
            phantom: PhantomData,
        }
    }
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlExpression<S> for SqlMax<S, E>
where
    E::SqlType: OrderableSqlType,
{
    type RustType = E::RustType;
    type SqlType = E::SqlType;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "MAX(")?;
        self.expr.write_sql_string(f, parameter_binder)?;
        write!(f, ")")?;
        Ok(())
    }
}

pub struct SqlMin<S: SelectableTables, E: SqlExpression<S>>
where
    E::SqlType: OrderableSqlType,
{
    expr: E,
    phantom: PhantomData<S>,
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlMin<S, E>
where
    E::SqlType: OrderableSqlType,
{
    pub fn new(expr: E) -> Self {
        Self {
            expr,
            phantom: PhantomData,
        }
    }
}

impl<S: SelectableTables, E: SqlExpression<S>> SqlExpression<S> for SqlMin<S, E>
where
    E::SqlType: OrderableSqlType,
{
    type RustType = E::RustType;
    type SqlType = E::SqlType;

    const IS_AGGREGATE: bool = true;

    fn write_sql_string<'s, 'a>(
        &'s self,
        f: &mut String,
        parameter_binder: &mut ParameterBinder<'a>,
    ) -> std::fmt::Result
    where
        's: 'a,
    {
        write!(f, "MIN(")?;
        self.expr.write_sql_string(f, parameter_binder)?;
        write!(f, ")")?;
        Ok(())
    }
}