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>
12where
13 A: AggregateRoot,
14 R: Repository<Aggregate = A>,
15 P: DomainEventPublisher<Event = A::Event>,
16{
17 aggregate: &'a mut A,
18 repository: &'a mut R,
19 publisher: &'a mut P,
20 save_state: OperationState,
21 dispatch_state: OperationState,
22}
23
24impl<'a, A, R, P> LifecycleContext<'a, A, R, P>
25where
26 A: AggregateRoot,
27 R: Repository<Aggregate = A>,
28 P: DomainEventPublisher<Event = A::Event>,
29{
30 pub fn new(aggregate: &'a mut A, repository: &'a mut R, publisher: &'a mut P) -> Self {
34 Self {
35 aggregate,
36 repository,
37 publisher,
38 save_state: OperationState::Pending,
39 dispatch_state: OperationState::Pending,
40 }
41 }
42
43 pub fn save(&mut self) -> Result<(), LifecycleOperationError<R::Error>> {
47 if self.save_state != OperationState::Pending {
48 return Err(LifecycleOperationError::AlreadySaved);
49 }
50 self.save_state = OperationState::FailedConsumed;
51 match self.repository.save(self.aggregate) {
52 Ok(()) => {
53 self.save_state = OperationState::Succeeded;
54 Ok(())
55 }
56 Err(error) => Err(LifecycleOperationError::Adapter(error)),
57 }
58 }
59
60 pub fn dispatch(&mut self) -> Result<(), LifecycleOperationError<P::Error>> {
64 if self.dispatch_state != OperationState::Pending {
65 return Err(LifecycleOperationError::AlreadyDispatched);
66 }
67 self.dispatch_state = OperationState::FailedConsumed;
68 match dispatch_events(self.aggregate, self.publisher) {
69 Ok(()) => {
70 self.dispatch_state = OperationState::Succeeded;
71 Ok(())
72 }
73 Err(error) => Err(LifecycleOperationError::Adapter(error)),
74 }
75 }
76
77 pub fn complete(self) -> Result<(), LifecycleCompletionError> {
81 match (self.save_state, self.dispatch_state) {
82 (OperationState::Succeeded, OperationState::Succeeded) => Ok(()),
83 (OperationState::FailedConsumed, _) => {
84 Err(LifecycleCompletionError::SaveFailedConsumed)
85 }
86 (_, OperationState::FailedConsumed) => {
87 Err(LifecycleCompletionError::DispatchFailedConsumed)
88 }
89 (OperationState::Pending, _) => Err(LifecycleCompletionError::MissingSave),
90 (_, OperationState::Pending) => Err(LifecycleCompletionError::MissingDispatch),
91 }
92 }
93}
94
95pub trait LifecycleCallback<'storage, A, R, P>
99where
100 A: AggregateRoot,
101 R: Repository<Aggregate = A>,
102 P: DomainEventPublisher<Event = A::Event>,
103{
104 type Output;
105 type Error;
106
107 fn call<'callback>(
108 self,
109 context: &'callback mut LifecycleContext<'storage, A, R, P>,
110 ) -> Result<Self::Output, Self::Error>
111 where
112 'storage: 'callback;
113}
114
115pub trait CommandHandler {
119 type Command;
120 type Aggregate: AggregateRoot;
121 type Repository: Repository<Aggregate = Self::Aggregate>;
122 type Publisher: DomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
123 type Output;
124 type Error;
125
126 fn handle<F>(
127 &mut self,
128 id: &<Self::Aggregate as Entity>::Id,
129 command: Self::Command,
130 callback: F,
131 ) -> Result<Self::Output, Self::Error>
132 where
133 F: for<'a> LifecycleCallback<
134 'a,
135 Self::Aggregate,
136 Self::Repository,
137 Self::Publisher,
138 Output = Self::Output,
139 Error = Self::Error,
140 >,
141 Self::Error: From<LifecycleOperationError<<Self::Repository as Repository>::Error>>
142 + From<LifecycleOperationError<<Self::Publisher as DomainEventPublisher>::Error>>
143 + From<LifecycleCompletionError>;
144}
145
146pub trait AggregateCreator {
150 type Command;
151 type Aggregate: AggregateRoot;
152 type Repository: Repository<Aggregate = Self::Aggregate>;
153 type Publisher: DomainEventPublisher<Event = <Self::Aggregate as AggregateRoot>::Event>;
154 type Output;
155 type Error;
156
157 fn create<F>(
158 &mut self,
159 command: Self::Command,
160 callback: F,
161 ) -> Result<Self::Output, Self::Error>
162 where
163 F: for<'a> LifecycleCallback<
164 'a,
165 Self::Aggregate,
166 Self::Repository,
167 Self::Publisher,
168 Output = Self::Output,
169 Error = Self::Error,
170 >,
171 Self::Error: From<LifecycleOperationError<<Self::Repository as Repository>::Error>>
172 + From<LifecycleOperationError<<Self::Publisher as DomainEventPublisher>::Error>>
173 + From<LifecycleCompletionError>;
174}
175
176pub trait QueryHandler {
180 type Query;
181 type Result;
182 type Error;
183
184 fn handle(&self, query: Self::Query) -> Result<Self::Result, Self::Error>;
185}