1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
use crate::domain::{AggregateRoot, Entity};
/// Trait for representing a **Repository**.
///
/// > Therefore, use a Repository, the purpose of which is to encapsulate all the logic needed to
/// > obtain object references. The domain objects won’t have to deal with the infrastructure to get
/// > the needed references to other objects of the domain. They will just get them from the
/// > Repository and the model is regaining its clarity and focus.
///
/// # Example
///
/// See [InMemoryRepository](crate::infrastructure::memory::InMemoryRepository) for a sample
/// implementation of this trait.
#[async_trait::async_trait]
pub trait Repository<T: AggregateRoot>: ReadRepository<T> {
/// Adds an entity to the repository.
async fn add(&self, entity: T) -> crate::Result<T>;
/// Updates an entity on the repository.
async fn update(&self, entity: T) -> crate::Result<T>;
/// Deletes the entity from the repository.
async fn delete(&self, entity: T) -> crate::Result<()>;
/// Adds the given entities to the repository.
async fn add_range(&self, entities: Vec<T>) -> crate::Result<Vec<T>> {
let mut added_entities = Vec::new();
for entity in entities {
self.add(entity).await.map(|e| added_entities.push(e))?;
}
Ok(added_entities)
}
/// Updates the given entities on the repository.
async fn update_range(&self, entities: Vec<T>) -> crate::Result<Vec<T>> {
let mut updated_entities = Vec::new();
for entity in entities {
self.update(entity)
.await
.map(|e| updated_entities.push(e))?;
}
Ok(updated_entities)
}
/// Deletes the given entities from the repository.
async fn delete_range(&self, entities: Vec<T>) -> crate::Result<()> {
for entity in entities {
self.delete(entity).await?;
}
Ok(())
}
}
/// Trait for representing a read-only **Repository**.
#[async_trait::async_trait]
pub trait ReadRepository<T: AggregateRoot>: Send + Sync {
/// Gets an entity with the given ID.
async fn get_by_id(&self, id: <T as Entity>::Id) -> crate::Result<Option<T>>;
/// Lists all entities within a given page.
async fn list(&self, skip: usize, take: usize) -> crate::Result<Vec<T>>;
/// Returns the total number of entities in the repository.
async fn count(&self) -> crate::Result<usize>;
/// Checks whether an entity with the given ID exists in the repository.
async fn exists(&self, id: <T as Entity>::Id) -> crate::Result<bool> {
self.get_by_id(id).await.map(|e| e.is_some())
}
/// Checks if the repository is empty.
async fn is_empty(&self) -> crate::Result<bool> {
self.count().await.map(|c| c == 0)
}
}