1use std::future::Future;
2use std::marker::PhantomData;
3
4use crate::view::ViewStateComputation;
5
6#[cfg(not(feature = "not-send-futures"))]
14pub trait ViewStateRepository<E, S, Error> {
15 fn fetch_state(&self, event: &E) -> impl Future<Output = Result<Option<S>, Error>> + Send;
19 fn save(&self, state: &S) -> impl Future<Output = Result<S, Error>> + Send;
23}
24
25#[cfg(feature = "not-send-futures")]
33pub trait ViewStateRepository<E, S, Error> {
34 fn fetch_state(&self, event: &E) -> impl Future<Output = Result<Option<S>, Error>>;
38 fn save(&self, state: &S) -> impl Future<Output = Result<S, Error>>;
42}
43
44pub struct MaterializedView<S, E, Repository, View, Error>
57where
58 Repository: ViewStateRepository<E, S, Error>,
59 View: ViewStateComputation<E, S>,
60{
61 repository: Repository,
62 view: View,
63 _marker: PhantomData<(S, E, Error)>,
64}
65
66impl<S, E, Repository, View, Error> ViewStateComputation<E, S>
67 for MaterializedView<S, E, Repository, View, Error>
68where
69 Repository: ViewStateRepository<E, S, Error>,
70 View: ViewStateComputation<E, S>,
71{
72 fn compute_new_state(&self, current_state: Option<S>, events: &[&E]) -> S {
74 self.view.compute_new_state(current_state, events)
75 }
76}
77
78#[cfg(not(feature = "not-send-futures"))]
79impl<S, E, Repository, View, Error> ViewStateRepository<E, S, Error>
80 for MaterializedView<S, E, Repository, View, Error>
81where
82 Repository: ViewStateRepository<E, S, Error> + Sync,
83 View: ViewStateComputation<E, S> + Sync,
84 E: Sync,
85 S: Sync,
86 Error: Sync,
87{
88 async fn fetch_state(&self, event: &E) -> Result<Option<S>, Error> {
90 let state = self.repository.fetch_state(event).await?;
91 Ok(state)
92 }
93 async fn save(&self, state: &S) -> Result<S, Error> {
95 self.repository.save(state).await
96 }
97}
98
99#[cfg(feature = "not-send-futures")]
100impl<S, E, Repository, View, Error> ViewStateRepository<E, S, Error>
101 for MaterializedView<S, E, Repository, View, Error>
102where
103 Repository: ViewStateRepository<E, S, Error>,
104 View: ViewStateComputation<E, S>,
105{
106 async fn fetch_state(&self, event: &E) -> Result<Option<S>, Error> {
108 let state = self.repository.fetch_state(event).await?;
109 Ok(state)
110 }
111 async fn save(&self, state: &S) -> Result<S, Error> {
113 self.repository.save(state).await
114 }
115}
116
117#[cfg(not(feature = "not-send-futures"))]
118impl<S, E, Repository, View, Error> MaterializedView<S, E, Repository, View, Error>
119where
120 Repository: ViewStateRepository<E, S, Error> + Sync,
121 View: ViewStateComputation<E, S> + Sync,
122 E: Sync,
123 S: Sync,
124 Error: Sync,
125{
126 pub fn new(repository: Repository, view: View) -> Self {
128 MaterializedView {
129 repository,
130 view,
131 _marker: PhantomData,
132 }
133 }
134 pub async fn handle(&self, event: &E) -> Result<S, Error> {
136 let state = self.fetch_state(event).await?;
137 let new_state = self.compute_new_state(state, &[event]);
138 let saved_state = self.save(&new_state).await?;
139 Ok(saved_state)
140 }
141}
142
143#[cfg(feature = "not-send-futures")]
144impl<S, E, Repository, View, Error> MaterializedView<S, E, Repository, View, Error>
145where
146 Repository: ViewStateRepository<E, S, Error>,
147 View: ViewStateComputation<E, S>,
148{
149 pub fn new(repository: Repository, view: View) -> Self {
151 MaterializedView {
152 repository,
153 view,
154 _marker: PhantomData,
155 }
156 }
157 pub async fn handle(&self, event: &E) -> Result<S, Error> {
159 let state = self.fetch_state(event).await?;
160 let new_state = self.compute_new_state(state, &[event]);
161 let saved_state = self.save(&new_state).await?;
162 Ok(saved_state)
163 }
164}