ddd_rs/domain/aggregate.rs
1/// Trait for representing an **Aggregate Root**.
2///
3/// > An Aggregate is a group of associated objects which are considered as one unit with regard to
4/// > data changes. The Aggregate is demarcated by a boundary which separates the objects inside
5/// > from those outside. Each Aggregate has one root. The root is an Entity, and it is the only
6/// > object accessible from outside. The root can hold references to any of the aggregate objects,
7/// > and the other objects can hold references to each other, but an outside object can hold
8/// > references only to the root object. If there are other Entities inside the boundary, the
9/// > identity of those entities is local, making sense only inside the aggregate.
10///
11/// # Examples
12///
13/// Derive its implementation using the [ddd_rs::AggregateRoot](crate::AggregateRoot) macro:
14///
15/// ```
16/// // The `AggregateRoot` usually holds references to other entities, acting as a means to access
17/// // and even modify them.
18/// //
19/// // Note that we also need to derive the `Entity` trait, since an `AggregateRoot` is an `Entity`.
20/// #[derive(ddd_rs::AggregateRoot, ddd_rs::Entity)]
21/// struct MyAggregateRoot {
22/// #[entity(id)]
23/// id: u32,
24/// foo: Foo,
25/// bars: Vec<Bar>,
26/// }
27///
28/// #[derive(ddd_rs::Entity)]
29/// struct Foo {
30/// #[entity(id)]
31/// id: u32,
32/// foo: String,
33/// }
34///
35/// #[derive(ddd_rs::Entity)]
36/// struct Bar {
37/// #[entity(id)]
38/// id: String,
39/// bar: u32,
40/// }
41/// ```
42pub trait AggregateRoot: super::Entity + Send + Sync + 'static {}
43
44/// Extensions to the [AggregateRoot] behavior.
45///
46/// # Examples
47///
48/// Implement this trait explicitly when you need non-trivial use-cases, such as registering domain
49/// events on immutable instances of your entity:
50///
51/// ```
52/// use std::sync::Mutex;
53///
54/// use ddd_rs::domain::AggregateRootEx;
55///
56/// // The `DomainEvent` will usually be an arithmetic enum type, in order to allow for multiple
57/// // distinguishable event kinds within a single type.
58/// #[derive(Debug, PartialEq)]
59/// enum MyDomainEvent {
60/// DidSomething { something: String },
61/// DidSomethingElse { something_else: String },
62/// }
63///
64/// // The `AggregateRoot` owns a list of its own `DomainEvent`s.
65/// //
66/// // The [Interior Mutability](https://doc.rust-lang.org/reference/interior-mutability.html)
67/// // pattern may be relevant when semantically immutable actions need to register domain events.
68/// #[derive(ddd_rs::AggregateRoot, ddd_rs::Entity)]
69/// struct MyAggregateRoot {
70/// #[entity(id)]
71/// id: u32,
72/// domain_events: Mutex<Vec<MyDomainEvent>>,
73/// }
74///
75/// // The aggregate root's methods may register domain events upon different actions.
76/// impl MyAggregateRoot {
77/// pub fn new(id: u32) -> Self {
78/// Self {
79/// id,
80/// domain_events: Default::default(),
81/// }
82/// }
83///
84/// pub fn do_something(&self, something: impl ToString) {
85/// let something = something.to_string();
86///
87/// // Do something...
88///
89/// self.register_domain_event(MyDomainEvent::DidSomething { something });
90/// }
91///
92/// pub fn do_something_else(&mut self, something_else: impl ToString) {
93/// let something_else = something_else.to_string();
94///
95/// // Do something else...
96///
97/// self.register_domain_event(MyDomainEvent::DidSomethingElse { something_else });
98/// }
99///
100/// fn register_domain_event(&self, domain_event: <Self as AggregateRootEx>::DomainEvent) {
101/// let mut domain_events = self.domain_events.lock().unwrap();
102///
103/// domain_events.push(domain_event);
104/// }
105/// }
106///
107/// impl AggregateRootEx for MyAggregateRoot {
108/// type DomainEvent = MyDomainEvent;
109///
110/// fn take_domain_events(&mut self) -> Vec<Self::DomainEvent> {
111/// let mut domain_events = self.domain_events.lock().unwrap();
112///
113/// domain_events.drain(..).collect()
114/// }
115/// }
116///
117/// let aggregate_root = MyAggregateRoot::new(42);
118///
119/// // This registers a `MyDomainEvent::DidSomething` event.
120/// //
121/// // Note that this happens under an immutable reference to the aggregate.
122/// aggregate_root.do_something("foo");
123///
124/// let mut aggregate_root = aggregate_root;
125///
126/// // This registers a `MyDomainEvent::DidSomethingElse` event.
127/// aggregate_root.do_something_else("bar");
128///
129/// // Take the domain events and assert that they are gone afterwards.
130/// let domain_events = aggregate_root.take_domain_events();
131///
132/// assert_eq!(
133/// domain_events[0],
134/// MyDomainEvent::DidSomething {
135/// something: "foo".to_string()
136/// }
137/// );
138/// assert_eq!(
139/// domain_events[1],
140/// MyDomainEvent::DidSomethingElse {
141/// something_else: "bar".to_string()
142/// }
143/// );
144///
145/// assert!(aggregate_root.take_domain_events().is_empty());
146/// ```
147///
148/// Otherwise, derive its implementation using the [ddd_rs::AggregateRoot](crate::AggregateRoot)
149/// macro and the `#[aggregate_root(domain_events)]` attribute:
150///
151/// ```
152/// use ddd_rs::domain::AggregateRootEx;
153///
154/// #[derive(Debug, PartialEq)]
155/// enum MyDomainEvent {
156/// DidSomething { something: String },
157/// }
158///
159/// #[derive(ddd_rs::AggregateRoot, ddd_rs::Entity)]
160/// struct MyAggregateRoot {
161/// #[entity(id)]
162/// id: u32,
163/// #[aggregate_root(domain_events)]
164/// domain_events: Vec<MyDomainEvent>,
165/// }
166///
167/// impl MyAggregateRoot {
168/// pub fn new(id: u32) -> Self {
169/// Self {
170/// id,
171/// domain_events: Default::default(),
172/// }
173/// }
174///
175/// pub fn do_something(&mut self, something: impl ToString) {
176/// let something = something.to_string();
177///
178/// // Do something...
179///
180/// // The `register_domain_event` method is automatically derived.
181/// self.register_domain_event(MyDomainEvent::DidSomething { something });
182/// }
183/// }
184///
185/// // This time around, the aggregate may only register domain events on mutable methods.
186/// let mut aggregate_root = MyAggregateRoot::new(42);
187///
188/// aggregate_root.do_something("foo");
189///
190/// let domain_events = aggregate_root.take_domain_events();
191///
192/// assert_eq!(
193/// domain_events[0],
194/// MyDomainEvent::DidSomething {
195/// something: "foo".to_string()
196/// }
197/// );
198///
199/// assert!(aggregate_root.take_domain_events().is_empty());
200/// ```
201pub trait AggregateRootEx: AggregateRoot {
202 /// Domain event type.
203 ///
204 /// > Use domain events to explicitly implement side effects of changes within your domain.
205 /// > In other words, and using DDD terminology, use domain events to explicitly implement side
206 /// > effects across multiple aggregates.
207 type DomainEvent: Send;
208
209 /// Clears all domain events from the aggregate, returning them in order of occurrence.
210 fn take_domain_events(&mut self) -> Vec<Self::DomainEvent>;
211}