1#![allow(clippy::type_complexity)]
2
3use crate::{
4 AggregateRoot, DomainEventPublisher, Entity, LifecycleCompletionError, LifecycleOperationError,
5 Repository, cqrs::OperationState, dispatch_events,
6};
7
8pub struct LifecycleContext<'a, A, R, P>
14where
15 A: AggregateRoot,
16 R: Repository<Aggregate = A>,
17 P: DomainEventPublisher<Event = A::Event>,
18{
19 aggregate: &'a mut A,
20 repository: &'a mut R,
21 publisher: &'a mut P,
22 save_state: OperationState,
23 dispatch_state: OperationState,
24}
25
26impl<'a, A, R, P> LifecycleContext<'a, A, R, P>
27where
28 A: AggregateRoot,
29 R: Repository<Aggregate = A>,
30 P: DomainEventPublisher<Event = A::Event>,
31{
32 pub fn new(aggregate: &'a mut A, repository: &'a mut R, publisher: &'a mut P) -> Self {
38 Self {
39 aggregate,
40 repository,
41 publisher,
42 save_state: OperationState::Pending,
43 dispatch_state: OperationState::Pending,
44 }
45 }
46
47 pub fn save(&mut self) -> Result<(), LifecycleOperationError<R::Error>> {
53 if self.save_state != OperationState::Pending {
54 return Err(LifecycleOperationError::AlreadySaved);
55 }
56 self.save_state = OperationState::FailedConsumed;
57 match self.repository.save(self.aggregate) {
58 Ok(()) => {
59 self.save_state = OperationState::Succeeded;
60 Ok(())
61 }
62 Err(error) => Err(LifecycleOperationError::Adapter(error)),
63 }
64 }
65
66 pub fn dispatch(&mut self) -> Result<(), LifecycleOperationError<P::Error>> {
72 if self.dispatch_state != OperationState::Pending {
73 return Err(LifecycleOperationError::AlreadyDispatched);
74 }
75 self.dispatch_state = OperationState::FailedConsumed;
76 match dispatch_events(self.aggregate, self.publisher) {
77 Ok(()) => {
78 self.dispatch_state = OperationState::Succeeded;
79 Ok(())
80 }
81 Err(error) => Err(LifecycleOperationError::Adapter(error)),
82 }
83 }
84
85 pub fn complete(self) -> Result<(), LifecycleCompletionError> {
91 match (self.save_state, self.dispatch_state) {
92 (OperationState::Succeeded, OperationState::Succeeded) => Ok(()),
93 (OperationState::FailedConsumed, _) => {
94 Err(LifecycleCompletionError::SaveFailedConsumed)
95 }
96 (_, OperationState::FailedConsumed) => {
97 Err(LifecycleCompletionError::DispatchFailedConsumed)
98 }
99 (OperationState::Pending, _) => Err(LifecycleCompletionError::MissingSave),
100 (_, OperationState::Pending) => Err(LifecycleCompletionError::MissingDispatch),
101 }
102 }
103}
104
105pub trait LifecycleCallback<'storage, A, R, P>
111where
112 A: AggregateRoot,
113 R: Repository<Aggregate = A>,
114 P: DomainEventPublisher<Event = A::Event>,
115{
116 type Output;
117 type Error;
118
119 fn call<'callback>(
120 self,
121 context: &'callback mut LifecycleContext<'storage, A, R, P>,
122 ) -> Result<Self::Output, Self::Error>
123 where
124 'storage: 'callback;
125}
126
127pub trait CommandHandler {
133 type Command;
134 type Aggregate: AggregateRoot;
135 type Repository: Repository<Aggregate = Self::Aggregate>;
136 type Publisher: DomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
137 type Output;
138 type Error;
139
140 fn handle<F>(
141 &mut self,
142 id: &<Self::Aggregate as Entity>::Id,
143 command: Self::Command,
144 callback: F,
145 ) -> Result<Self::Output, Self::Error>
146 where
147 F: for<'a> LifecycleCallback<
148 'a,
149 Self::Aggregate,
150 Self::Repository,
151 Self::Publisher,
152 Output = Self::Output,
153 Error = Self::Error,
154 >,
155 Self::Error: From<LifecycleOperationError<<Self::Repository as Repository>::Error>>
156 + From<LifecycleOperationError<<Self::Publisher as DomainEventPublisher>::Error>>
157 + From<LifecycleCompletionError>;
158}
159
160pub trait AggregateCreator {
166 type Command;
167 type Aggregate: AggregateRoot;
168 type Repository: Repository<Aggregate = Self::Aggregate>;
169 type Publisher: DomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
170 type Output;
171 type Error;
172
173 fn create<F>(
174 &mut self,
175 command: Self::Command,
176 callback: F,
177 ) -> Result<Self::Output, Self::Error>
178 where
179 F: for<'a> LifecycleCallback<
180 'a,
181 Self::Aggregate,
182 Self::Repository,
183 Self::Publisher,
184 Output = Self::Output,
185 Error = Self::Error,
186 >,
187 Self::Error: From<LifecycleOperationError<<Self::Repository as Repository>::Error>>
188 + From<LifecycleOperationError<<Self::Publisher as DomainEventPublisher>::Error>>
189 + From<LifecycleCompletionError>;
190}
191
192pub trait QueryHandler {
198 type Query;
199 type Result;
200 type Error;
201
202 fn handle(&self, query: Self::Query) -> Result<Self::Result, Self::Error>;
203}