use async_trait::async_trait;
use futures::Stream;
use std::fmt::Debug;
use crate::{
aggregate::{Aggregate, Context},
event::{DomainEvent, EventStoreEvent},
};
#[derive(Debug, thiserror::Error)]
pub enum RepositoryError<E, EventId, DE> {
#[error("Aggregate was not found")]
AggregateNotFound,
#[error("Failed to apply events to aggregate from event stream. Event Id: {0} caused: {1}")]
Apply(EventId, #[source] E),
#[error("Event store failed while streaming events: {0}")]
Repository(#[from] DE),
}
#[derive(Debug, Clone)]
pub struct Snapshot<T>
where
T: Aggregate,
{
pub aggregate: T,
pub version: u64,
pub snapshot_version: u64,
}
#[async_trait]
pub trait RepositoryReader<T: Aggregate> {
type DbError;
#[doc(hidden)]
fn stream_from(
&mut self,
id: &T::AggregateId,
version: u64,
) -> impl Stream<Item = Result<EventStoreEvent<T::DomainEvent>, Self::DbError>>;
#[doc(hidden)]
async fn get_event(
&mut self,
aggregate_id: &T::AggregateId,
event_id: &<<T as Aggregate>::DomainEvent as DomainEvent>::EventId,
) -> Result<Option<EventStoreEvent<T::DomainEvent>>, Self::DbError>;
#[doc(hidden)]
async fn get_snapshot(
&mut self,
id: &T::AggregateId,
) -> Result<Option<Snapshot<T>>, Self::DbError>;
}
#[async_trait]
pub trait RepositoryWriter<T: Aggregate>: RepositoryReader<T> {
#[doc(hidden)]
async fn store_events(
&mut self,
id: &T::AggregateId,
events: Vec<EventStoreEvent<T::DomainEvent>>,
) -> Result<Vec<<<T as Aggregate>::DomainEvent as DomainEvent>::EventId>, Self::DbError>;
#[doc(hidden)]
async fn store_snapshot(&mut self, snapshot: Snapshot<T>) -> Result<(), Self::DbError>;
#[doc(hidden)]
async fn store_side_effects(
&mut self,
side_effects: Vec<T::SideEffect>,
) -> Result<(), Self::DbError>;
}
#[async_trait]
pub trait Repository<T: Aggregate> {
type Error;
async fn load(&self, aggregate_id: &T::AggregateId) -> Result<Context<T>, Self::Error>;
}