orm 0.2.0

A ORM framework written in Rust, unfinished yet
use mysql::Value;

#[derive(Debug, Clone)]
pub struct Cond {
    items: Vec<Item>,
}

impl Cond {
    pub fn new() -> Self {
        Cond { items: Vec::new() }
    }

    pub fn by_id<V>(id: V) -> Self
        where Value: From<V>
    {
        let mut cond = Cond::new();
        cond.id(id);
        cond
    }
    pub fn by_eq<V>(field: &str, value: V) -> Self
        where Value: From<V>
    {
        let mut cond = Cond::new();
        cond.eq(field, value);
        cond
    }
    pub fn by_ne<V>(field: &str, value: V) -> Self
        where Value: From<V>
    {
        let mut cond = Cond::new();
        cond.ne(field, value);
        cond
    }
    pub fn by_gt<V>(field: &str, value: V) -> Self
        where Value: From<V>
    {
        let mut cond = Cond::new();
        cond.gt(field, value);
        cond
    }
    pub fn by_lt<V>(field: &str, value: V) -> Self
        where Value: From<V>
    {
        let mut cond = Cond::new();
        cond.lt(field, value);
        cond
    }
}

impl Cond {
    pub fn id<V>(&mut self, id: V) -> &mut Self
        where Value: From<V>
    {
        self.items.push(Item::Id(Value::from(id)));
        self
    }
    pub fn eq<V>(&mut self, field: &str, value: V) -> &mut Self
        where Value: From<V>
    {
        self.items.push(Item::Eq(field.to_string(), Value::from(value)));
        self
    }
    pub fn ne<V>(&mut self, field: &str, value: V) -> &mut Self
        where Value: From<V>
    {
        self.items.push(Item::Ne(field.to_string(), Value::from(value)));
        self
    }
    pub fn gt<V>(&mut self, field: &str, value: V) -> &mut Self
        where Value: From<V>
    {
        self.items.push(Item::Gt(field.to_string(), Value::from(value)));
        self
    }
    pub fn lt<V>(&mut self, field: &str, value: V) -> &mut Self
        where Value: From<V>
    {
        self.items.push(Item::Lt(field.to_string(), Value::from(value)));
        self
    }

    pub fn to_sql(&self, alias: &str) -> String {
        self.items
            .iter()
            .map(|item| item.to_sql(alias))
            .collect::<Vec<_>>()
            .join(" AND ")
    }
    pub fn to_params(&self, alias: &str) -> Vec<(String, Value)> {
        self.items
            .iter()
            .map(|item| item.to_params(alias))
            .collect::<Vec<_>>()
    }
}

#[derive(Debug, Clone)]
enum Item {
    Id(Value),
    Eq(String, Value),
    Ne(String, Value),
    Gt(String, Value),
    Lt(String, Value),
}

fn concat(alias: &str, field: &str) -> String {
    format!("{}_{}", alias.to_lowercase(), field)
}

impl Item {
    fn to_sql(&self, alias: &str) -> String {
        match self {
            &Item::Id(..) => format!("{}.id = :{}", alias, concat(alias, "id")),
            &Item::Eq(ref field, ..) => format!("{}.{} = :{}", alias, field, concat(alias, field)),
            &Item::Ne(ref field, ..) => format!("{}.{} <> :{}", alias, field, concat(alias, field)),
            &Item::Gt(ref field, ..) => format!("{}.{} > :{}", alias, field, concat(alias, field)),
            &Item::Lt(ref field, ..) => format!("{}.{} < :{}", alias, field, concat(alias, field)),
        }
    }
    fn to_params(&self, alias: &str) -> (String, Value) {
        match self {
            &Item::Id(ref value) => (concat(alias, "id"), value.clone()),
            &Item::Eq(ref field, ref value) => (concat(alias, field), value.clone()),
            &Item::Ne(ref field, ref value) => (concat(alias, field), value.clone()),
            &Item::Gt(ref field, ref value) => (concat(alias, field), value.clone()),
            &Item::Lt(ref field, ref value) => (concat(alias, field), value.clone()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct JoinCond {
    items: Vec<JoinItem>,
}

impl JoinCond {
    pub fn new() -> Self {
        JoinCond { items: Vec::new() }
    }
    pub fn by_eq(f1: &str, f2: &str) -> Self {
        let mut cond = JoinCond::new();
        cond.eq(f1, f2);
        cond
    }
    pub fn by_ne(f1: &str, f2: &str) -> Self {
        let mut cond = JoinCond::new();
        cond.ne(f1, f2);
        cond
    }
    pub fn by_gt(f1: &str, f2: &str) -> Self {
        let mut cond = JoinCond::new();
        cond.gt(f1, f2);
        cond
    }
    pub fn by_lt(f1: &str, f2: &str) -> Self {
        let mut cond = JoinCond::new();
        cond.lt(f1, f2);
        cond
    }
}

impl JoinCond {
    pub fn eq(&mut self, f1: &str, f2: &str) -> &mut Self {
        self.items.push(JoinItem::Eq(f1.to_string(), f2.to_string()));
        self
    }
    pub fn ne(&mut self, f1: &str, f2: &str) -> &mut Self {
        self.items.push(JoinItem::Ne(f1.to_string(), f2.to_string()));
        self
    }
    pub fn gt(&mut self, f1: &str, f2: &str) -> &mut Self {
        self.items.push(JoinItem::Gt(f1.to_string(), f2.to_string()));
        self
    }
    pub fn lt(&mut self, f1: &str, f2: &str) -> &mut Self {
        self.items.push(JoinItem::Lt(f1.to_string(), f2.to_string()));
        self
    }

    pub fn to_sql(&self, a1: &str, a2: &str) -> String {
        self.items
            .iter()
            .map(|item| item.to_sql(a1, a2))
            .collect::<Vec<_>>()
            .join(" AND ")
    }
}

#[derive(Debug, Clone)]
enum JoinItem {
    Eq(String, String),
    Ne(String, String),
    Gt(String, String),
    Lt(String, String),
}

impl JoinItem {
    fn to_sql(&self, a1: &str, a2: &str) -> String {
        match self {
            &JoinItem::Eq(ref f1, ref f2) => format!("{}.{} = {}.{}", a1, f1, a2, f2),
            &JoinItem::Ne(ref f1, ref f2) => format!("{}.{} <> {}.{}", a1, f1, a2, f2),
            &JoinItem::Gt(ref f1, ref f2) => format!("{}.{} > {}.{}", a1, f1, a2, f2),
            &JoinItem::Lt(ref f1, ref f2) => format!("{}.{} < {}.{}", a1, f1, a2, f2),
        }
    }
}