nitinol_projection/
resolver.rs1use crate::errors::ProjectionError;
2use crate::projection::Projection;
3use async_trait::async_trait;
4use futures_util::FutureExt;
5use nitinol_core::event::Event;
6use nitinol_resolver::resolver::ResolveHandler;
7use std::panic::AssertUnwindSafe;
8
9pub(crate) const HANDLER_TYPE: &str = "projection";
10
11pub struct Project;
12
13#[async_trait]
14impl<E: Event, T> ResolveHandler<E, T> for Project
15where
16 T: Projection<E>,
17{
18 const HANDLER_TYPE: &'static str = HANDLER_TYPE;
19 type Error = ProjectionError;
20
21 async fn apply(entity: &mut Option<T>, event: E) -> Result<(), Self::Error> {
22 let Some(entity) = entity else {
23 let first = match AssertUnwindSafe(T::first(event))
24 .catch_unwind()
25 .await
26 .map_err(|_| ProjectionError::FirstFormation)?
27 {
28 Ok(a) => a,
29 Err(e) => {
30 tracing::error!("First formation failed: {:?}", e);
31 return Err(ProjectionError::ApplyEvent {
32 backtrace: format!("{:?}", e),
33 });
34 }
35 };
36 *entity = Some(first);
37 return Ok(());
38 };
39
40 if let Err(e) = T::apply(entity, event).await {
41 tracing::error!("Projection failed: {:?}", e);
42 return Err(ProjectionError::ApplyEvent {
43 backtrace: format!("{:?}", e),
44 });
45 }
46
47 Ok(())
48 }
49}