1use ddd_toolkit::{
14 AggregateReplay, AggregateRoot as _, AggregateSnapshot, AppendError, AppendResult,
15 CurrentRevision, EventStore, EventUpcaster, ExpectedRevision, LoadResult, NoStream,
16 RevisionConflict, SnapshotLoadError, SnapshotSaveError, SnapshotStore, SnapshotUse,
17 StreamHistory, StreamRevision, replay_aggregate, replay_with_optional_snapshot,
18};
19use std::{collections::HashMap, convert::Infallible};
20
21#[derive(Debug, Clone, PartialEq, ddd_toolkit::DomainEvent)]
22enum Added {
23 V1(u32),
24 V2 { amount: u32 },
25}
26struct ToV2;
27impl EventUpcaster<Added> for ToV2 {
28 type Error = Infallible;
29 fn upcast(&self, event: Added) -> Result<Added, Infallible> {
30 Ok(match event {
31 Added::V1(amount) => Added::V2 { amount },
32 current => current,
33 })
34 }
35}
36#[derive(Debug, ddd_toolkit::Entity, ddd_toolkit::AggregateRoot)]
37struct Counter {
38 #[entity(id)]
39 id: u64,
40 value: u32,
41 #[aggregate(events)]
42 events: Vec<Added>,
43}
44impl AggregateReplay for Counter {
45 type InitializationError = Infallible;
46 type ApplicationError = &'static str;
47 type Snapshot = u32;
48 type SnapshotValidationError = Infallible;
49 type SnapshotStateError = Infallible;
50 fn initial_state(id: &u64) -> Result<Self, Infallible> {
51 Ok(Self {
52 id: *id,
53 value: 0,
54 events: vec![],
55 })
56 }
57 fn apply_event(&mut self, event: &Added) -> Result<(), Self::ApplicationError> {
58 let Added::V2 { amount } = event else {
59 return Err("upcast before replay");
60 };
61 self.value = self.value.checked_add(*amount).ok_or("counter overflow")?;
62 Ok(()) }
64 fn classify_snapshot(
65 _: &AggregateSnapshot<u32>,
66 _: StreamRevision,
67 ) -> Result<SnapshotUse, Infallible> {
68 Ok(SnapshotUse::Applicable)
70 }
71 fn from_snapshot(id: &u64, snapshot: AggregateSnapshot<u32>) -> Result<Self, Infallible> {
72 Ok(Self {
73 id: *id,
74 value: snapshot.into_parts().0,
75 events: vec![],
76 })
77 }
78}
79
80#[derive(Default)]
81struct MemoryEvents(HashMap<u64, Vec<Added>>);
82impl EventStore for MemoryEvents {
83 type Aggregate = Counter;
84 type Error = Infallible;
85 fn load(&self, id: &u64) -> Result<LoadResult<Added>, Infallible> {
86 match self.0.get(id) {
87 None => Ok(LoadResult::NoStream(NoStream)),
88 Some(events) => {
89 let current = events
91 .iter()
92 .cloned()
93 .map(|event| ToV2.upcast(event).unwrap())
94 .collect();
95 Ok(LoadResult::Found(
96 StreamHistory::try_new(current, StreamRevision::new(events.len() as u64 - 1))
97 .unwrap(),
98 ))
99 }
100 }
101 }
102 fn append(
103 &mut self,
104 id: &u64,
105 expected: ExpectedRevision,
106 events: Vec<Added>,
107 ) -> Result<AppendResult, AppendError<Infallible>> {
108 if events.is_empty() {
109 return Err(AppendError::EmptyBatch);
110 }
111 let current = self
112 .0
113 .get(id)
114 .map(|events| StreamRevision::new(events.len() as u64 - 1));
115 let matches = match (expected, current) {
116 (ExpectedRevision::NoStream(_), None) => true,
117 (ExpectedRevision::Revision(want), Some(have)) => want == have,
118 _ => false,
119 };
120 if !matches {
121 return Err(AppendError::Conflict(RevisionConflict {
122 expected,
123 current: current.map_or(
124 CurrentRevision::NoStream(NoStream),
125 CurrentRevision::Revision,
126 ),
127 }));
128 }
129 let revision = match current {
130 None => StreamRevision::new(events.len() as u64 - 1),
131 Some(revision) => StreamRevision::new(
132 revision
133 .value()
134 .checked_add(events.len() as u64)
135 .ok_or(AppendError::RevisionExhausted { current: revision })?,
136 ),
137 };
138 self.0.entry(*id).or_default().extend(events);
140 Ok(AppendResult {
141 resulting_revision: revision,
142 })
143 }
144}
145#[derive(Default)]
146struct MemorySnapshots(HashMap<u64, AggregateSnapshot<u32>>);
147impl SnapshotStore for MemorySnapshots {
148 type Aggregate = Counter;
149 type State = u32;
150 type Error = Infallible;
151 fn load(
152 &self,
153 id: &u64,
154 ) -> Result<Option<AggregateSnapshot<u32>>, SnapshotLoadError<Infallible>> {
155 Ok(self
156 .0
157 .get(id)
158 .map(|snapshot| AggregateSnapshot::new(*snapshot.state(), snapshot.revision())))
159 }
160 fn save(
161 &mut self,
162 id: &u64,
163 snapshot: AggregateSnapshot<u32>,
164 ) -> Result<(), SnapshotSaveError<Infallible>> {
165 self.0.insert(*id, snapshot);
166 Ok(())
167 }
168}
169fn history(store: &MemoryEvents) -> StreamHistory<Added> {
170 let LoadResult::Found(history) = store.load(&1).unwrap() else {
171 panic!("stream missing");
172 };
173 history
174}
175fn main() {
176 let mut store = MemoryEvents::default();
177 assert!(matches!(store.load(&1).unwrap(), LoadResult::NoStream(_)));
178 let first = store
179 .append(&1, ExpectedRevision::NoStream(NoStream), vec![Added::V1(2)])
180 .unwrap();
181 assert_eq!(first.resulting_revision, StreamRevision::new(0));
182 let mut replayed = replay_aggregate::<Counter>(&1, &history(&store)).unwrap();
183 assert_eq!(replayed.aggregate.value, 2);
184 assert!(replayed.aggregate.pull_events().is_empty());
185 let mut snapshots = MemorySnapshots::default();
186 snapshots
187 .save(
188 &1,
189 AggregateSnapshot::new(replayed.aggregate.value, replayed.revision),
190 )
191 .unwrap();
192 store
193 .append(
194 &1,
195 ExpectedRevision::Revision(replayed.revision),
196 vec![Added::V2 { amount: 3 }],
197 )
198 .unwrap();
199 assert!(matches!(
200 store.append(
201 &1,
202 ExpectedRevision::Revision(replayed.revision),
203 vec![Added::V1(99)]
204 ),
205 Err(AppendError::Conflict(_))
206 ));
207 let history = history(&store);
208 let mut restored =
209 replay_with_optional_snapshot::<Counter>(&1, &history, snapshots.load(&1).unwrap())
210 .unwrap();
211 let full = replay_aggregate::<Counter>(&1, &history).unwrap();
212 assert_eq!(restored.aggregate.value, 5);
213 assert_eq!(restored.aggregate.value, full.aggregate.value);
214 assert_eq!(restored.revision, StreamRevision::new(1));
215 assert!(restored.aggregate.pull_events().is_empty());
216 println!("event_sourcing: upcast v1; rejected stale write; snapshot + tail = 5");
217}