arel 0.0.2

simulate rails arel
Documentation
use serde_json::{Value as Json, json};
use std::marker::PhantomData;
use std::default::Default;
use crate::traits::ModelAble;
use crate::statements::StatementAble;
use crate::nodes::SqlLiteral;
use crate::methods;

#[derive(Clone, Debug)]
pub enum Op {
    Count,
    Sum(String),
    Avg(String),
    Min(String),
    Max(String),
}

#[derive(Clone, Debug)]
pub struct Select<M: ModelAble> {
    pub value: Json,
    pub distinct: bool,
    pub op: Option<Op>,
    _marker: PhantomData<M>,
}

impl<M> StatementAble<M> for Select<M> where M: ModelAble {
    fn json_value(&self) -> Option<&Json> {
        Some(&self.value)
    }
    fn to_sql_literals(&self) -> Vec<SqlLiteral> {
        let mut vec = vec![];
        if let Some(json_value) = self.json_value() {
            match json_value {
                Json::Array(json_array) => {
                    for column_name in json_array.iter() {
                        if let Json::String(column_name) = column_name {
                            let table_column_name = methods::table_column_name::<M>(column_name);
                            vec.push(SqlLiteral::new(format!("{}", table_column_name)));
                        } else {
                            panic!("Error: Not Support");
                        }
                    }
                },
                Json::String(_) =>  vec.append(&mut StatementAble::to_sql_literals_default(self)),
                _ => panic!("Error: Not Support")
            }
        }
        // Ok(vec.join(" AND "))
        vec
    }
    fn to_sql(&self) -> String {
        let mut sql = self.to_sql_with_concat(", ");
        if self.distinct {
            sql = format!("DISTINCT {}", &sql);
        }
        if let Some(op) = &self.op {
            match op {
                Op::Count => {
                    sql = format!("COUNT({})", &sql);
                },
                Op::Sum(column_name) => {
                    let select = Select::<M>::new(json!([column_name]), self.distinct);
                    sql = format!("SUM({})", &select.to_sql());
                },
                Op::Avg(column_name) => {
                    let select = Select::<M>::new(json!([column_name]), self.distinct);
                    sql = format!("AVG({})", &select.to_sql());
                },
                Op::Min(column_name) => {
                    let select = Select::<M>::new(json!([column_name]), self.distinct);
                    sql = format!("MIN({})", &select.to_sql());
                },
                Op::Max(column_name) => {
                    let select = Select::<M>::new(json!([column_name]), self.distinct);
                    sql = format!("MAX({})", &select.to_sql());
                }
            }
        }
        sql
    }
}

impl<M> Default for Select<M> where M: ModelAble {
    fn default() -> Self {
        Self {
            value: json!(["*"]),
            distinct: false,
            op: None,
            _marker: PhantomData
        }
    }
}

impl<M> Select<M> where M: ModelAble {
    pub fn new(value: Json, distinct: bool) -> Self {
        Self {
            value,
            distinct,
            op: None,
            _marker: PhantomData,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::{json};
    #[test]
    fn to_sql() {
        #[derive(Clone, Debug)]
        struct User {}
        impl ModelAble for User {}

        let select = Select::<User>::new(json!("name, age"), false);
        assert_eq!(select.to_sql(), "name, age");

        let select = Select::<User>::new(json!(["name", "age"]), false);
        assert_eq!(select.to_sql(), "`users`.`name`, `users`.`age`");
    }
}