dojo-orm 0.2.2

A simple ORM for Rust
Documentation
use std::collections::HashMap;
use std::fmt::Debug;
use std::marker::PhantomData;

use crate::execution;
use crate::execution::Execution;
use tracing::debug;

use crate::model::Model;
use crate::order_by::{OrderBy, OrderPredicate};
use crate::pagination::{Cursor, DefaultSortKeys, Pagination};
use crate::pool::*;
use crate::predicates::{Expr, ExprValueType, Predicate};
use crate::query_builder::{QueryBuilder, QueryType};
use crate::types::ToSql;

pub struct WhereSelect<'a, T> {
    pub(crate) pool: &'a Pool<PostgresConnectionManager<NoTls>>,
    pub(crate) params: Vec<&'a (dyn ToSql + Sync)>,
    pub(crate) columns: &'a [&'a str],
    pub(crate) order_by: Vec<OrderPredicate<'a>>,
    pub(crate) predicates: Vec<Predicate<'a>>,
    pub(crate) _t: PhantomData<T>,
}

impl<'a, T> WhereSelect<'a, T>
where
    T: Model + Debug,
{
    pub fn where_by(&'a mut self, predicate: Predicate<'a>) -> &'a mut Self {
        self.predicates.push(predicate);
        self
    }

    pub fn order_by(&'a mut self, order_by: OrderPredicate<'a>) -> &'a mut Self {
        self.order_by.push(order_by);
        self
    }

    pub async fn cursor(
        &'a self,
        first: Option<i64>,
        after: Option<Cursor>,
        last: Option<i64>,
        before: Option<Cursor>,
    ) -> anyhow::Result<Pagination<T>> {
        let qb = QueryBuilder::builder()
            .table_name(T::NAME)
            .default_keys(T::sort_keys())
            .columns(self.columns)
            .params(&self.params)
            .predicates(&self.predicates)
            .first(first)
            .after(&after)
            .last(last)
            .before(&before)
            .ty(QueryType::Paging)
            .build();

        let execution = Execution::new(self.pool, &qb);
        let query_all_fut = execution.all::<T>();

        let qb = QueryBuilder::builder()
            .table_name(T::NAME)
            .columns(&["COUNT(*) as count"])
            .params(&self.params)
            .predicates(&self.predicates)
            .ty(QueryType::Paging)
            .build();

        let execution = Execution::new(self.pool, &qb);
        let query_count_fut = execution.query_one();

        let (records, row) = tokio::try_join!(query_all_fut, query_count_fut)?;
        let count = row.get("count");

        debug!(?records);
        debug!(?count);

        Ok(Pagination::new(records, first, after, last, before, count))
    }

    fn query_by_limit(&'a self, limit: i64) -> QueryBuilder<'a> {
        QueryBuilder::builder()
            .table_name(T::NAME)
            .columns(self.columns)
            .params(&self.params)
            .predicates(&self.predicates)
            .order_by(&self.order_by)
            .ty(QueryType::Select)
            .limit(limit)
            .build()
    }

    pub async fn count(&'a self) -> anyhow::Result<i64> {
        let qb = QueryBuilder::builder()
            .table_name(T::NAME)
            .columns(&["COUNT(*) as count"])
            .params(&self.params)
            .predicates(&self.predicates)
            .ty(QueryType::Select)
            .build();

        let execution = Execution::new(self.pool, &qb);
        let row = execution.query_one().await?;

        let count = row.get("count");

        Ok(count)
    }

    pub async fn limit(&'a self, limit: i64) -> anyhow::Result<Vec<T>> {
        let qb = self.query_by_limit(limit);

        let execution = Execution::new(self.pool, &qb);
        execution.all().await
    }

    pub async fn first(&'a self) -> anyhow::Result<Option<T>> {
        let qb = self.query_by_limit(1);

        let execution = Execution::new(self.pool, &qb);
        execution.first().await
    }

    pub async fn all(&'a self) -> anyhow::Result<Vec<T>> {
        let qb = self.query_by_limit(500);

        let execution = Execution::new(self.pool, &qb);
        execution.all().await
    }
}