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:** Coordinates one synchronous aggregate save and event dispatch sequence.
9///
10/// **日本語:** 同期の集約保存とイベント配信を一連で調整します。
11pub 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    /// **English:** Creates a lifecycle context borrowing the aggregate, repository, and publisher mutably.
31    ///
32    /// **日本語:** 集約、リポジトリ、パブリッシャーを可変借用するライフサイクルコンテキストを作成します。
33    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    /// **English:** Attempts repository persistence once; adapter errors are returned and the attempt cannot be retried.
44    ///
45    /// **日本語:** リポジトリへの保存を一度試行します。アダプターエラーを返し、再試行はできません。
46    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    /// **English:** Attempts event dispatch once; adapter errors are returned and the attempt cannot be retried.
61    ///
62    /// **日本語:** イベント配信を一度試行します。アダプターエラーを返し、再試行はできません。
63    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    /// **English:** Consumes the context and succeeds only when both save and dispatch succeeded.
78    ///
79    /// **日本語:** コンテキストを消費し、保存と配信の両方が成功した場合にのみ成功します。
80    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
95/// **English:** Defines work performed with a mutable lifecycle context. The callback result and error become the handler result and error.
96///
97/// **日本語:** 可変ライフサイクルコンテキストを使って実行する処理を定義します。コールバックの出力とエラーがハンドラーの出力とエラーになります。
98pub 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
115/// **English:** Loads an aggregate for a command, runs its lifecycle callback, and returns the callback output or an error.
116///
117/// **日本語:** コマンド対象の集約を読み込み、ライフサイクルコールバックを実行し、その出力またはエラーを返します。
118pub 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
146/// **English:** Creates an aggregate from a command and runs the lifecycle callback before returning its output.
147///
148/// **日本語:** コマンドから集約を作成し、ライフサイクルコールバックを実行してから出力を返します。
149pub 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
176/// **English:** Handles a query without requiring aggregate lifecycle operations.
177///
178/// **日本語:** 集約ライフサイクル操作を伴わずにクエリを処理します。
179pub 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}