debil 0.5.0

Lightweight ORM for Rust
Documentation
use crate::{QueryBuilder, SqlMapper, SqlTable};
use async_trait::async_trait;

pub struct Params<ValueType>(pub Vec<(String, ValueType)>);

impl<V> Params<V> {
    pub fn new() -> Params<V> {
        Params(Vec::new())
    }
}

pub trait HasNotFound {
    fn not_found() -> Self;
}

#[async_trait]
pub trait SqlConn<V: 'static + Sync + Send> {
    type Error: HasNotFound;

    async fn sql_exec(&mut self, query: String, params: Params<V>) -> Result<u64, Self::Error>;

    async fn sql_query<T: SqlMapper<ValueType = V> + Sync + Send>(
        &mut self,
        query: String,
        params: Params<V>,
    ) -> Result<Vec<T>, Self::Error>;

    async fn sql_batch_exec(
        &mut self,
        query: String,
        params: Vec<Params<V>>,
    ) -> Result<(), Self::Error>;

    async fn create_table<T: SqlTable<ValueType = V> + Sync + Send>(
        &mut self,
    ) -> Result<(), Self::Error> {
        self.sql_exec(
            SqlTable::create_table_query(std::marker::PhantomData::<T>),
            Params::<V>(Vec::new()),
        )
        .await?;

        Ok(())
    }

    async fn create<T: SqlTable<ValueType = V> + Sync + Send>(
        &mut self,
        data: T,
    ) -> Result<u64, Self::Error> {
        let (query, ps) = data.insert_query_with_params();

        self.sql_exec(query, Params::<V>(ps)).await
    }

    async fn save<T: SqlTable<ValueType = V> + Sync + Send + Clone>(
        &mut self,
        data: T,
    ) -> Result<u64, Self::Error> {
        let (query, ps) = data.clone().update_query_with_params();
        let affected_rows = self.sql_exec(query, Params::<V>(ps)).await?;

        if affected_rows == 0 {
            self.create(data).await
        } else {
            Ok(affected_rows)
        }
    }

    async fn load2<T: SqlTable, U: SqlMapper<ValueType = V> + Sync + Send>(
        &mut self,
        builder: QueryBuilder<V>,
    ) -> Result<Vec<U>, Self::Error> {
        let schema = SqlTable::schema_of(std::marker::PhantomData::<T>);
        let table_name = SqlTable::table_name(std::marker::PhantomData::<T>);
        let (query, params) = builder
            .table(table_name.clone())
            .append_selects(
                schema
                    .iter()
                    .map(|(k, _, _)| format!("{}.{}", table_name, k))
                    .collect::<Vec<_>>(),
            )
            .build();
        self.sql_query::<U>(query, params).await
    }

    async fn load<T: SqlTable<ValueType = V> + Sync + Send>(
        &mut self,
        builder: QueryBuilder<V>,
    ) -> Result<Vec<T>, Self::Error> {
        self.load2::<T, T>(builder).await
    }

    async fn first<T: SqlTable<ValueType = V> + Sync + Send>(
        &mut self,
        builder: QueryBuilder<V>,
    ) -> Result<T, Self::Error> {
        let schema = SqlTable::schema_of(std::marker::PhantomData::<T>);
        let table_name = SqlTable::table_name(std::marker::PhantomData::<T>);
        let (query, params) = builder
            .table(table_name.clone())
            .append_selects(
                schema
                    .iter()
                    .map(|(k, _, _)| format!("{}.{}", table_name, k))
                    .collect::<Vec<_>>(),
            )
            .limit(1)
            .build();

        self.sql_query::<T>(query, params)
            .await
            .and_then(|mut vs| vs.pop().ok_or(HasNotFound::not_found()))
    }
}