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}