datasources 0.1.5

Async datasource interfaces, middleware, registry, and test doubles
Documentation
use crate::bulk_write_strategy::BulkWriteStrategy;
use crate::i_where::IWhere;
use crate::repository::ICRUDRepository;
use crate::response::Response;
use crate::result::Result;
use crate::row::Row;
use crate::value::Value;
use async_trait::async_trait;
use std::sync::{Arc, OnceLock, Weak};

#[derive(Default)]
pub struct SingleCommandIBulkWriteStrategy {
    repo: OnceLock<Weak<dyn ICRUDRepository>>,
}

impl SingleCommandIBulkWriteStrategy {
    pub fn new() -> Self {
        Self::default()
    }

    fn repo(&self) -> Result<Arc<dyn ICRUDRepository>> {
        self.repo
            .get()
            .and_then(Weak::upgrade)
            .ok_or_else(|| crate::DatasourceError::message("Repo required"))
    }
}

#[async_trait]
impl BulkWriteStrategy for SingleCommandIBulkWriteStrategy {
    fn set_repo(&self, repo: Arc<dyn ICRUDRepository>) {
        let _ = self.repo.set(Arc::downgrade(&repo));
    }

    async fn create(&self, items: &mut [Row]) -> Result<Response> {
        let repo = self.repo()?;
        for item in items.iter_mut() {
            repo.create(item).await?;
        }
        Ok(Response::new(Value::Null, items.len() as i64, None))
    }

    async fn update(
        &self,
        items: &[Row],
        by_where: Option<&dyn IWhere>,
    ) -> Result<Response> {
        let repo = self.repo()?;
        let mut result = Value::Null;
        let mut rows_affected = 0;
        for item in items {
            let mut item = item.clone();
            let response = repo.update(&mut item, by_where).await?;
            result = response.result;
            rows_affected += response.rows_affected;
        }
        Ok(Response::new(result, rows_affected, None))
    }

    async fn delete(
        &self,
        items: &[Row],
        by_where: Option<&dyn IWhere>,
    ) -> Result<Response> {
        let repo = self.repo()?;
        let mut result = Value::Null;
        let mut rows_affected = 0;
        for item in items {
            let response = repo.delete(item, by_where).await?;
            result = response.result;
            rows_affected += response.rows_affected;
        }
        Ok(Response::new(result, rows_affected, None))
    }
}