cherry 0.2.1

An asynchronous ORM, which support MySQL, PostgreSQL, SQLite and SQL Server.
use std::any::TypeId;

use anyhow::anyhow;
use sql_builder::SqlBuilder;
use sqlx::{Encode, Type};

use crate::{Cherry, connection, gen_execute, gen_where};
use crate::query::query_builder::QueryBuilder;
use crate::types::{Database, QueryResult, Result, Transaction};

pub struct InsertUpdate<'a> {
    pub(crate) query: QueryBuilder<'a>,
    pub(crate) columns: Vec<&'static str>,
    pub(crate) size: usize,
    pub(crate) fields: Vec<String>,
}

impl<'a> InsertUpdate<'a> {

    fn new<T>(datasource: TypeId) -> Self where T: Cherry {
        Self {
            query: QueryBuilder::new::<T>(datasource, SqlBuilder::insert_into(T::table())),
            columns: T::columns(),
            size: 0,
            fields: vec![]
        }
    }

    pub(crate) fn insert_update<T>(datasource: TypeId, v: &'a [T]) -> Self where T: Cherry {
        let mut t = Self::new::<T>(datasource);
        t.size = v.len();
        v.iter().for_each(|v| v.arguments(&mut t.query.arguments) );
        t
    }

    pub fn field<T: AsRef<str>>(mut self, f: T) -> Self {
        self.field_ref(f);
        self
    }

    pub fn field_ref<T: AsRef<str>>(&mut self, f: T) -> &Self {
        self.fields.push(f.as_ref().to_owned());
        self
    }

    pub fn fields<T: AsRef<str>>(mut self, f: &[T]) -> Self {
        self.fields_ref(f);
        self
    }

    pub fn fields_ref<T: AsRef<str>>(&mut self, f: &[T]) -> &Self {
        f.iter().for_each(|f| {
            self.fields.push(f.as_ref().to_owned());
        });
        self
    }

    gen_where!();

    fn build_sql(&mut self) -> Result<String> {
        if self.fields.is_empty() {
            return Err(anyhow!("Empty update fields."));
        }

        let holders = vec!["?"; self.columns.len()];
        self.query.sql_builder.fields(self.columns.as_slice());
        (0..self.size).for_each(|_| {
            self.query.sql_builder.values(holders.as_slice());
        });

        let insert = self.query.sql_builder.sql()?.strip_suffix(";")
            .ok_or(anyhow!("Empty sql. This wasn’t supposed to happen."))?
            .to_owned();
        let update = self.fields.iter().map(|x| format!("{0} = new.{0}, ", x))
            .collect::<String>()
            .strip_suffix(",")
            .ok_or(anyhow!("Empty sql. This wasn’t supposed to happen."))?
            .to_owned();
        Ok(format!("{} AS new ON DUPLICATE KEY UPDATE {};", insert, update))
    }

    gen_execute!();

}