Skip to main content

ddd_toolkit_core/domain/
aggregate.rs

1use crate::domain::{DomainEvent, Entity};
2
3/// An [`Entity`] that is a consistency boundary and the unit of persistence:
4/// changes to it (and whatever it contains) are saved and loaded together,
5/// and it records the domain events those changes produce.
6///
7/// # Examples
8///
9/// ```
10/// use ddd_toolkit_core::domain::{AggregateRoot, DomainEvent, Entity, EntityId, ValueObject};
11/// use std::fmt::Display;
12///
13/// #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14/// struct OrderId(u32);
15///
16/// impl ValueObject for OrderId {}
17///
18/// impl Display for OrderId {
19///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20///         write!(f, "order-{}", self.0)
21///     }
22/// }
23///
24/// impl EntityId for OrderId {}
25///
26/// #[derive(Debug, PartialEq)]
27/// enum OrderEvent {
28///     Placed,
29/// }
30///
31/// impl DomainEvent for OrderEvent {}
32///
33/// struct Order {
34///     id: OrderId,
35///     events: Vec<OrderEvent>,
36/// }
37///
38/// impl Entity for Order {
39///     type Id = OrderId;
40///
41///     fn id(&self) -> &Self::Id {
42///         &self.id
43///     }
44/// }
45///
46/// impl AggregateRoot for Order {
47///     type Event = OrderEvent;
48///
49///     fn record(&mut self, event: Self::Event) {
50///         self.events.push(event);
51///     }
52///
53///     fn take_events(&mut self) -> Vec<Self::Event> {
54///         std::mem::take(&mut self.events)
55///     }
56/// }
57///
58/// let mut order = Order { id: OrderId(1), events: Vec::new() };
59/// order.record(OrderEvent::Placed);
60///
61/// // draining hands ownership of the recorded events to the caller (e.g. a
62/// // repository, to publish after a successful save) and clears the buffer
63/// assert_eq!(order.take_events(), vec![OrderEvent::Placed]);
64/// assert_eq!(order.take_events(), vec![]);
65/// ```
66pub trait AggregateRoot: Entity {
67    /// The domain event type this aggregate records.
68    type Event: DomainEvent;
69
70    /// Records that `event` happened, to be drained later via
71    /// [`AggregateRoot::take_events`].
72    fn record(&mut self, event: Self::Event);
73
74    /// Returns and clears every event recorded since the last call.
75    fn take_events(&mut self) -> Vec<Self::Event>;
76}
77
78#[cfg(test)]
79mod test {
80    use std::fmt::Display;
81
82    use crate::domain::{EntityId, ValueObject};
83
84    use super::*;
85
86    #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
87    struct FooId(String);
88
89    impl ValueObject for FooId {}
90
91    impl Display for FooId {
92        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93            write!(f, "{}", self.0)
94        }
95    }
96
97    impl EntityId for FooId {}
98
99    #[derive(Debug, PartialEq)]
100    struct FooEvent {
101        name: String,
102    }
103
104    impl DomainEvent for FooEvent {}
105
106    fn event(name: &str) -> FooEvent {
107        FooEvent {
108            name: name.to_string(),
109        }
110    }
111
112    struct Foo {
113        id: FooId,
114        events: Vec<FooEvent>,
115    }
116
117    impl Foo {
118        fn new(id: &str) -> Self {
119            Self {
120                id: FooId(id.to_string()),
121                events: Vec::new(),
122            }
123        }
124    }
125
126    impl Entity for Foo {
127        type Id = FooId;
128
129        fn id(&self) -> &Self::Id {
130            &self.id
131        }
132    }
133
134    impl AggregateRoot for Foo {
135        type Event = FooEvent;
136
137        fn record(&mut self, event: Self::Event) {
138            self.events.push(event);
139        }
140
141        fn take_events(&mut self) -> Vec<Self::Event> {
142            std::mem::take(&mut self.events)
143        }
144    }
145
146    #[test]
147    fn record_single_event_take_events_returns_it() {
148        let mut foo = Foo::new("foo-1");
149
150        foo.record(event("created"));
151
152        assert_eq!(foo.take_events(), vec![event("created")]);
153    }
154
155    #[test]
156    fn record_multiple_events_take_events_returns_in_recorded_order() {
157        let mut foo = Foo::new("foo-1");
158
159        foo.record(event("created"));
160        foo.record(event("updated"));
161        foo.record(event("deleted"));
162
163        assert_eq!(
164            foo.take_events(),
165            vec![event("created"), event("updated"), event("deleted")]
166        );
167    }
168
169    #[test]
170    fn take_events_clears_recorded_events() {
171        let mut foo = Foo::new("foo-1");
172        foo.record(event("created"));
173
174        foo.take_events();
175
176        assert_eq!(foo.take_events(), vec![]);
177    }
178
179    #[test]
180    fn record_after_take_events_returns_only_new_events() {
181        let mut foo = Foo::new("foo-1");
182        foo.record(event("created"));
183        foo.take_events();
184
185        foo.record(event("updated"));
186
187        assert_eq!(foo.take_events(), vec![event("updated")]);
188    }
189
190    #[test]
191    fn aggregate_root_impl_satisfies_entity_supertrait() {
192        let a = Foo::new("foo-1");
193        let b = Foo::new("foo-1");
194        let c = Foo::new("foo-2");
195
196        assert_eq!(a.id(), &FooId("foo-1".to_string()));
197        assert!(a.is_same_as(&b));
198        assert!(!a.is_same_as(&c));
199    }
200
201    #[test]
202    fn aggregate_root_impl_satisfies_send_and_sync() {
203        fn assert_impl<T: Send + Sync>() {}
204        assert_impl::<Foo>();
205    }
206
207    #[test]
208    fn generic_fn_accepts_aggregate_root_impl() {
209        fn drain<T: AggregateRoot>(aggregate: &mut T, event: T::Event) -> Vec<T::Event> {
210            aggregate.record(event);
211            aggregate.take_events()
212        }
213
214        let mut foo = Foo::new("foo-1");
215
216        assert_eq!(drain(&mut foo, event("created")), vec![event("created")]);
217    }
218
219    #[test]
220    fn take_events_on_fresh_aggregate_returns_empty_vec() {
221        let mut foo = Foo::new("foo-1");
222
223        assert_eq!(foo.take_events(), vec![]);
224    }
225
226    #[test]
227    fn record_duplicate_events_are_both_returned() {
228        let mut foo = Foo::new("foo-1");
229
230        foo.record(event("created"));
231        foo.record(event("created"));
232
233        assert_eq!(foo.take_events(), vec![event("created"), event("created")]);
234    }
235}