-
Notifications
You must be signed in to change notification settings - Fork 115
/
main.rs
267 lines (234 loc) · 6.41 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
use std::{
borrow::{Borrow, BorrowMut},
num::NonZeroU64,
};
fn main() {
println!("Refactor me!");
}
/// A projected state built from a series of events.
pub trait Aggregate: Default {
/// A static string representing the type of the aggregate.
///
/// Note: This should effectively be a constant value, and should never change.
fn aggregate_type() -> &'static str;
/// Consumes the event, applying its effects to the aggregate.
fn apply<E>(&mut self, event: E)
where
E: AggregateEvent<Self>,
{
event.apply_to(self);
}
}
/// An identifier for an aggregate.
pub trait AggregateId<A>
where
A: Aggregate,
{
/// Gets the stringified aggregate identifier.
fn as_str(&self) -> &str;
}
/// A thing that happened.
pub trait Event {
/// A static description of the event.
fn event_type(&self) -> &'static str;
}
/// An event that can be applied to an aggregate.
pub trait AggregateEvent<A: Aggregate>: Event {
/// Consumes the event, applying its effects to the aggregate.
fn apply_to(self, aggregate: &mut A);
}
/// Represents an event sequence number, starting at 1
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EventNumber(NonZeroU64);
impl EventNumber {
/// The minimum [EventNumber].
#[allow(unsafe_code)]
pub const MIN_VALUE: EventNumber =
// One is absolutely non-zero, and this is required for this to be
// usable in a `const` context.
EventNumber(unsafe { NonZeroU64::new_unchecked(1) });
/// Increments the event number to the next value.
#[inline]
pub fn incr(&mut self) {
self.0 = NonZeroU64::new(self.0.get() + 1).unwrap();
}
}
/// An aggregate version.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Version {
/// The version of an aggregate that has not had any events applied to it.
Initial,
/// The version of the last event applied to the aggregate.
Number(EventNumber),
}
impl Default for Version {
#[inline]
fn default() -> Self {
Version::Initial
}
}
impl Version {
/// Creates a new `Version` from a number.
///
/// The number `0` gets interpreted as being `Version::Initial`, while any other number is interpreted as the
/// latest event number applied.
#[inline]
pub fn new(number: u64) -> Self {
NonZeroU64::new(number)
.map(EventNumber)
.map(Version::Number)
.unwrap_or(Version::Initial)
}
/// Increments the version number to the next in sequence.
#[inline]
pub fn incr(&mut self) {
match *self {
Version::Initial => *self = Version::Number(EventNumber::MIN_VALUE),
Version::Number(ref mut en) => en.incr(),
}
}
}
/// An aggregate that has been loaded from a source, which keeps track of the version of its last snapshot and the current version of the aggregate.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub struct HydratedAggregate<A>
where
A: Aggregate,
{
version: Version,
snapshot_version: Option<Version>,
state: A,
}
impl<A> HydratedAggregate<A>
where
A: Aggregate,
{
/// The current version of the aggregate.
pub fn version(&self) -> Version {
self.version
}
/// The version of the snapshot from which the aggregate was loaded.
pub fn snapshot_version(&self) -> Option<Version> {
self.snapshot_version
}
/// Updates the snapshot version. Generally used to indicate that a snapshot was taken.
pub fn set_snapshot_version(&mut self, new_snapshot_version: Version) {
self.snapshot_version = Some(new_snapshot_version);
}
/// The actual aggregate.
pub fn state(&self) -> &A {
&self.state
}
/// Applies a sequence of events to the internal aggregate.
pub fn apply_events<E: AggregateEvent<A>, I: IntoIterator<Item = E>>(&mut self, events: I) {
for event in events {
self.apply(event);
}
}
/// Applies a single event to the aggregate, keeping track of the new aggregate version.
pub fn apply<E: AggregateEvent<A>>(&mut self, event: E) {
self.state.apply(event);
self.version.incr();
}
}
impl<A> AsRef<A> for HydratedAggregate<A>
where
A: Aggregate,
{
fn as_ref(&self) -> &A {
&self.state
}
}
impl<A> Borrow<A> for HydratedAggregate<A>
where
A: Aggregate,
{
fn borrow(&self) -> &A {
&self.state
}
}
/// An identified, specific instance of a hydrated aggregate.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
pub struct Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
id: I,
aggregate: HydratedAggregate<A>,
}
impl<I, A> Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
/// Creates a new entity from an identifier and an associated hydrated aggregate.
pub fn new(id: I, aggregate: HydratedAggregate<A>) -> Self {
Entity { id, aggregate }
}
/// The entity's identifier.
pub fn id(&self) -> &I {
&self.id
}
/// An immutable reference to the underlying aggregate.
pub fn aggregate(&self) -> &HydratedAggregate<A> {
&self.aggregate
}
/// A mutable reference to the underlying aggregate.
pub fn aggregate_mut(&mut self) -> &mut HydratedAggregate<A> {
&mut self.aggregate
}
}
impl<I, A> From<Entity<I, A>> for HydratedAggregate<A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn from(entity: Entity<I, A>) -> Self {
entity.aggregate
}
}
impl<I, A> AsRef<HydratedAggregate<A>> for Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn as_ref(&self) -> &HydratedAggregate<A> {
&self.aggregate
}
}
impl<I, A> AsMut<HydratedAggregate<A>> for Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn as_mut(&mut self) -> &mut HydratedAggregate<A> {
&mut self.aggregate
}
}
impl<I, A> Borrow<HydratedAggregate<A>> for Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn borrow(&self) -> &HydratedAggregate<A> {
&self.aggregate
}
}
impl<I, A> Borrow<A> for Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn borrow(&self) -> &A {
self.aggregate.borrow()
}
}
impl<I, A> BorrowMut<HydratedAggregate<A>> for Entity<I, A>
where
A: Aggregate,
I: AggregateId<A>,
{
fn borrow_mut(&mut self) -> &mut HydratedAggregate<A> {
&mut self.aggregate
}
}