use crate::{AggregateRoot, AsyncDomainEventPublisher};
use std::future::Future;
use std::pin::Pin;
struct EventRestorationGuard<'a, A: AggregateRoot> {
aggregate: &'a mut A,
snapshot: Option<Vec<A::Event>>,
}
impl<'a, A: AggregateRoot> EventRestorationGuard<'a, A> {
fn new(aggregate: &'a mut A, snapshot: Vec<A::Event>) -> Self {
Self {
aggregate,
snapshot: Some(snapshot),
}
}
fn events(&self) -> impl Iterator<Item = &A::Event> {
self.snapshot.as_deref().into_iter().flatten()
}
fn commit(&mut self) {
self.snapshot.take();
}
}
impl<A: AggregateRoot> Drop for EventRestorationGuard<'_, A> {
fn drop(&mut self) {
if let Some(snapshot) = self.snapshot.take() {
for event in snapshot {
self.aggregate.record_event(event);
}
}
}
}
pub fn dispatch_events_async<'a, A, P>(
aggregate: &'a mut A,
publisher: &'a mut P,
) -> Pin<Box<dyn Future<Output = Result<(), P::Error>> + Send + 'a>>
where
A: AggregateRoot + Send + 'a,
A::Event: Send + Sync + 'a,
P: AsyncDomainEventPublisher<Event = A::Event> + Send + 'a,
P::Error: 'a,
{
Box::pin(async move {
let snapshot = aggregate.pull_events();
let mut guard = EventRestorationGuard::new(aggregate, snapshot);
for event in guard.events() {
publisher.publish(event).await?
}
guard.commit();
Ok(())
})
}