dinoco 0.0.7

A modern Rust ORM for schema-driven queries, migrations, and database operations.
Documentation
use std::future::Future;

use dinoco_engine::{DinocoAdapter, DinocoClient, DinocoError, DinocoResult, SelectStatement};

use crate::{InsertModel, Model, Projection, ReadMode};

use super::execute_first;

pub(crate) fn execute_reload_by_identity<'a, M, S, A>(
    item: &'a M,
    client: &'a DinocoClient<A>,
) -> impl Future<Output = DinocoResult<S>> + 'a
where
    M: InsertModel + 'a,
    S: Projection<M> + 'a,
    A: DinocoAdapter,
{
    async move { load_one_by_conditions::<M, S, A>(item.insert_identity_conditions(), client).await }
}

pub(crate) fn execute_reload_many_by_identity<'a, M, S, A>(
    items: &'a [M],
    client: &'a DinocoClient<A>,
) -> impl Future<Output = DinocoResult<Vec<S>>> + 'a
where
    M: InsertModel + 'a,
    S: Projection<M> + 'a,
    A: DinocoAdapter,
{
    async move {
        let identity_conditions = items.iter().map(InsertModel::insert_identity_conditions).collect::<Vec<_>>();

        load_many_by_conditions::<M, S, A>(identity_conditions, client).await
    }
}

pub(super) async fn load_many_by_conditions<M, S, A>(
    identity_conditions: Vec<Vec<dinoco_engine::Expression>>,
    client: &DinocoClient<A>,
) -> DinocoResult<Vec<S>>
where
    M: Model,
    S: Projection<M>,
    A: DinocoAdapter,
{
    let mut rows = Vec::with_capacity(identity_conditions.len());

    for conditions in identity_conditions {
        let item = load_one_by_conditions::<M, S, A>(conditions, client).await?;
        rows.push(item);
    }

    Ok(rows)
}

async fn load_one_by_conditions<M, S, A>(
    conditions: Vec<dinoco_engine::Expression>,
    client: &DinocoClient<A>,
) -> DinocoResult<S>
where
    M: Model,
    S: Projection<M>,
    A: DinocoAdapter,
{
    let mut statement = SelectStatement::new().from(M::table_name()).select(S::columns());

    for condition in conditions {
        statement = statement.condition(condition);
    }

    execute_first::<M, S, A>(statement, ReadMode::Primary, client).await?.ok_or_else(|| {
        DinocoError::RecordNotFound(format!("Record from table '{}' could not be loaded after write.", M::table_name()))
    })
}