Skip to main content

ddd_toolkit_core/cqrs/
query_handler.rs

1#![allow(clippy::type_complexity)]
2
3use crate::{
4    AggregateRoot, DomainEventPublisher, Entity, LifecycleCompletionError, LifecycleOperationError,
5    Repository, cqrs::OperationState, dispatch_events,
6};
7
8/// **English:**<br>
9/// Coordinates one synchronous aggregate save and event dispatch sequence.
10///
11/// **日本語:**<br>
12/// 同期の集約保存とイベント配信を一連で調整します。
13pub 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    /// **English:**<br>
33    /// Creates a lifecycle context borrowing the aggregate, repository, and publisher mutably.
34    ///
35    /// **日本語:**<br>
36    /// 集約、リポジトリ、パブリッシャーを可変借用するライフサイクルコンテキストを作成します。
37    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    /// **English:**<br>
48    /// Attempts repository persistence once; adapter errors are returned and the attempt cannot be retried.
49    ///
50    /// **日本語:**<br>
51    /// リポジトリへの保存を一度試行します。アダプターエラーを返し、再試行はできません。
52    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    /// **English:**<br>
67    /// Attempts event dispatch once; adapter errors are returned and the attempt cannot be retried.
68    ///
69    /// **日本語:**<br>
70    /// イベント配信を一度試行します。アダプターエラーを返し、再試行はできません。
71    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    /// **English:**<br>
86    /// Consumes the context and succeeds only when both save and dispatch succeeded.
87    ///
88    /// **日本語:**<br>
89    /// コンテキストを消費し、保存と配信の両方が成功した場合にのみ成功します。
90    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
105/// **English:**<br>
106/// Defines work performed with a mutable lifecycle context. The callback result and error become the handler result and error.
107///
108/// **日本語:**<br>
109/// 可変ライフサイクルコンテキストを使って実行する処理を定義します。コールバックの出力とエラーがハンドラーの出力とエラーになります。
110pub 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
127/// **English:**<br>
128/// Loads an aggregate for a command, runs its lifecycle callback, and returns the callback output or an error.
129///
130/// **日本語:**<br>
131/// コマンド対象の集約を読み込み、ライフサイクルコールバックを実行し、その出力またはエラーを返します。
132pub 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
160/// **English:**<br>
161/// Creates an aggregate from a command and runs the lifecycle callback before returning its output.
162///
163/// **日本語:**<br>
164/// コマンドから集約を作成し、ライフサイクルコールバックを実行してから出力を返します。
165pub 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
192/// **English:**<br>
193/// Handles a query without requiring aggregate lifecycle operations.
194///
195/// **日本語:**<br>
196/// 集約ライフサイクル操作を伴わずにクエリを処理します。
197pub 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}