1#![allow(clippy::type_complexity)]
2
3use crate::cqrs::OperationState;
4use crate::{
5 AggregateRoot, AsyncDomainEventPublisher, AsyncRepository, Entity, LifecycleCompletionError,
6 LifecycleOperationError, dispatch_events_async,
7};
8use std::future::Future;
9use std::pin::Pin;
10
11struct AttemptGuard<'a> {
12 state: &'a mut OperationState,
13 succeeded: bool,
14}
15
16impl<'a> AttemptGuard<'a> {
17 fn new(state: &'a mut OperationState) -> Self {
18 Self {
19 state,
20 succeeded: false,
21 }
22 }
23
24 fn succeed(&mut self) {
25 *self.state = OperationState::Succeeded;
26 self.succeeded = true;
27 }
28}
29
30impl Drop for AttemptGuard<'_> {
31 fn drop(&mut self) {
32 if !self.succeeded {
33 *self.state = OperationState::FailedConsumed;
34 }
35 }
36}
37
38pub struct AsyncLifecycleContext<'storage, A, R, P>
42where
43 A: AggregateRoot + Send + 'storage,
44 R: AsyncRepository<Aggregate = A> + Send + 'storage,
45 P: AsyncDomainEventPublisher<Event = A::Event> + Send + 'storage,
46 A::Event: Send + Sync + 'storage,
47 R::Error: Send + 'storage,
48 P::Error: Send + 'storage,
49{
50 aggregate: &'storage mut A,
51 repository: &'storage mut R,
52 publisher: &'storage mut P,
53 save_state: OperationState,
54 dispatch_state: OperationState,
55}
56impl<'storage, A, R, P> AsyncLifecycleContext<'storage, A, R, P>
57where
58 A: AggregateRoot + Send + 'storage,
59 R: AsyncRepository<Aggregate = A> + Send + 'storage,
60 P: AsyncDomainEventPublisher<Event = A::Event> + Send + 'storage,
61 A::Event: Send + Sync + 'storage,
62 R::Error: Send + 'storage,
63 P::Error: Send + 'storage,
64{
65 pub fn new(
69 aggregate: &'storage mut A,
70 repository: &'storage mut R,
71 publisher: &'storage mut P,
72 ) -> Self {
73 Self {
74 aggregate,
75 repository,
76 publisher,
77 save_state: OperationState::Pending,
78 dispatch_state: OperationState::Pending,
79 }
80 }
81
82 pub fn save<'ctx>(
86 &'ctx mut self,
87 ) -> Pin<Box<dyn Future<Output = Result<(), LifecycleOperationError<R::Error>>> + Send + 'ctx>>
88 where
89 'storage: 'ctx,
90 A: Send + 'ctx,
91 R: Send + 'ctx,
92 R::Error: Send + 'ctx,
93 {
94 if self.save_state != OperationState::Pending {
95 return Box::pin(async { Err(LifecycleOperationError::AlreadySaved) });
96 }
97 self.save_state = OperationState::FailedConsumed;
98 let state = &mut self.save_state;
99 let repository: &'ctx mut R = &mut *self.repository;
100 let aggregate: &'ctx mut A = &mut *self.aggregate;
101 Box::pin(async move {
102 let mut guard = AttemptGuard::new(state);
103 match repository.save(&*aggregate).await {
104 Ok(()) => {
105 guard.succeed();
106 Ok(())
107 }
108 Err(error) => Err(LifecycleOperationError::Adapter(error)),
109 }
110 })
111 }
112
113 pub fn dispatch<'ctx>(
117 &'ctx mut self,
118 ) -> Pin<Box<dyn Future<Output = Result<(), LifecycleOperationError<P::Error>>> + Send + 'ctx>>
119 where
120 'storage: 'ctx,
121 A: Send + 'ctx,
122 P: Send + 'ctx,
123 A::Event: Send + Sync + 'ctx,
124 P::Error: Send + 'ctx,
125 P::Error: 'ctx,
126 {
127 if self.dispatch_state != OperationState::Pending {
128 return Box::pin(async { Err(LifecycleOperationError::AlreadyDispatched) });
129 }
130 self.dispatch_state = OperationState::FailedConsumed;
131 let state = &mut self.dispatch_state;
132 let aggregate: &'ctx mut A = &mut *self.aggregate;
133 let publisher: &'ctx mut P = &mut *self.publisher;
134 Box::pin(async move {
135 let mut guard = AttemptGuard::new(state);
136 match dispatch_events_async(aggregate, publisher).await {
137 Ok(()) => {
138 guard.succeed();
139 Ok(())
140 }
141 Err(error) => Err(LifecycleOperationError::Adapter(error)),
142 }
143 })
144 }
145
146 pub fn complete(self) -> Result<(), LifecycleCompletionError> {
150 match (self.save_state, self.dispatch_state) {
151 (OperationState::Succeeded, OperationState::Succeeded) => Ok(()),
152 (OperationState::FailedConsumed, _) => {
153 Err(LifecycleCompletionError::SaveFailedConsumed)
154 }
155 (_, OperationState::FailedConsumed) => {
156 Err(LifecycleCompletionError::DispatchFailedConsumed)
157 }
158 (OperationState::Pending, _) => Err(LifecycleCompletionError::MissingSave),
159 (_, OperationState::Pending) => Err(LifecycleCompletionError::MissingDispatch),
160 }
161 }
162}
163
164pub trait AsyncLifecycleCallback<A, R, P>
168where
169 A: AggregateRoot + Send,
170 R: AsyncRepository<Aggregate = A> + Send,
171 P: AsyncDomainEventPublisher<Event = A::Event> + Send,
172 A::Event: Send + Sync,
173 R::Error: Send,
174 P::Error: Send,
175{
176 type Output;
177 type Error;
178
179 fn call<'storage, 'callback>(
180 self,
181 context: &'callback mut AsyncLifecycleContext<'storage, A, R, P>,
182 ) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'callback>>
183 where
184 'storage: 'callback,
185 A: 'storage,
186 R: 'storage,
187 P: 'storage,
188 A::Event: 'storage,
189 R::Error: 'storage,
190 P::Error: 'storage,
191 Self: Send + 'callback,
192 Self::Output: Send + 'callback,
193 Self::Error: Send + 'callback;
194}
195
196pub trait AsyncCommandHandler {
200 type Command;
201 type Aggregate: AggregateRoot;
202 type Repository: AsyncRepository<Aggregate = Self::Aggregate>;
203 type Publisher: AsyncDomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
204 type Output;
205 type Error;
206
207 fn handle<'a, F>(
208 &'a mut self,
209 id: &'a <Self::Aggregate as Entity>::Id,
210 command: Self::Command,
211 callback: F,
212 ) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'a>>
213 where
214 Self: Send + 'a,
215 Self::Command: Send + 'a,
216 Self::Aggregate: Send + 'a,
217 <Self::Aggregate as Entity>::Id: Sync + 'a,
218 <Self::Aggregate as AggregateRoot>::Event: Send + Sync + 'a,
219 Self::Repository: Send + 'a,
220 <Self::Repository as AsyncRepository>::Error: Send + 'a,
221 Self::Publisher: Send + 'a,
222 <Self::Publisher as AsyncDomainEventPublisher>::Error: Send + 'a,
223 Self::Output: Send + 'a,
224 Self::Error: From<LifecycleOperationError<<Self::Repository as AsyncRepository>::Error>>
225 + From<LifecycleOperationError<<Self::Publisher as AsyncDomainEventPublisher>::Error>>
226 + From<LifecycleCompletionError>
227 + Send
228 + 'a,
229 F: AsyncLifecycleCallback<
230 Self::Aggregate,
231 Self::Repository,
232 Self::Publisher,
233 Output = Self::Output,
234 Error = Self::Error,
235 > + Send
236 + 'a;
237}
238
239pub trait AsyncAggregateCreator {
243 type Command;
244 type Aggregate: AggregateRoot;
245 type Repository: AsyncRepository<Aggregate = Self::Aggregate>;
246 type Publisher: AsyncDomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
247 type Output;
248 type Error;
249
250 fn create<'a, F>(
251 &'a mut self,
252 command: Self::Command,
253 callback: F,
254 ) -> Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send + 'a>>
255 where
256 Self: Send + 'a,
257 Self::Command: Send + 'a,
258 Self::Aggregate: Send + 'a,
259 <Self::Aggregate as AggregateRoot>::Event: Send + Sync + 'a,
260 Self::Repository: Send + 'a,
261 <Self::Repository as AsyncRepository>::Error: Send + 'a,
262 Self::Publisher: Send + 'a,
263 <Self::Publisher as AsyncDomainEventPublisher>::Error: Send + 'a,
264 Self::Output: Send + 'a,
265 Self::Error: From<LifecycleOperationError<<Self::Repository as AsyncRepository>::Error>>
266 + From<LifecycleOperationError<<Self::Publisher as AsyncDomainEventPublisher>::Error>>
267 + From<LifecycleCompletionError>
268 + Send
269 + 'a,
270 F: AsyncLifecycleCallback<
271 Self::Aggregate,
272 Self::Repository,
273 Self::Publisher,
274 Output = Self::Output,
275 Error = Self::Error,
276 > + Send
277 + 'a;
278}
279
280pub trait AsyncQueryHandler {
284 type Query;
285 type Result;
286 type Error;
287
288 fn handle<'a>(
289 &'a self,
290 query: Self::Query,
291 ) -> Pin<Box<dyn Future<Output = Result<Self::Result, Self::Error>> + Send + 'a>>
292 where
293 Self: Sync + 'a,
294 Self::Query: Send + 'a,
295 Self::Result: Send + 'a,
296 Self::Error: Send + 'a;
297}