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
use uuid::Uuid;

use crate::store::EventStoreLockGuard;
use crate::store::StoreEvent;
use crate::types::SequenceNumber;

/// The internal state for an Aggregate.
/// It contains:
/// - an id uniquely representing the aggregate,
/// - an incremental sequence number,
/// - a lock representing the atomicity of the access to the aggregate,
/// - a state defined by the user of this library.
pub struct AggregateState<S> {
    id: Uuid,
    sequence_number: SequenceNumber,
    lock: Option<EventStoreLockGuard>,
    inner: S,
}

impl<S: std::fmt::Debug> std::fmt::Debug for AggregateState<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("AggregateState")
            .field("id", &self.id)
            .field("sequence_number", &self.sequence_number)
            .field("lock", &self.lock.is_some())
            .field("inner", &self.inner)
            .finish()
    }
}

/// Default implementation for [`AggregateState`]
impl<S: Default> Default for AggregateState<S> {
    fn default() -> Self {
        Self::new()
    }
}

impl<S: Default> AggregateState<S> {
    /// Creates a new instance of an [`AggregateState`] with a new unique id.
    pub fn new() -> Self {
        Self {
            id: Uuid::new_v4(),
            inner: Default::default(),
            sequence_number: 0,
            lock: None,
        }
    }

    /// Creates a new instance of an [`AggregateState`] with the given aggregate id.
    ///
    /// This should be used almost exclusively when loading by aggregate id yields nothing,
    /// and this becomes the brand new aggregate state for that id.
    ///
    /// Other uses are strongly discouraged, since the id could be already existing
    /// and a clash might happen when persisting events.
    pub fn with_id(id: impl Into<Uuid>) -> Self {
        Self {
            id: id.into(),
            inner: Default::default(),
            sequence_number: 0,
            lock: None,
        }
    }

    /// Consumes the aggregate state and generates a new one with the events applied to it,
    /// as dictated by `apply_event`.
    pub fn apply_store_events<T, F>(self, store_events: Vec<StoreEvent<T>>, apply_event: F) -> Self
    where
        F: Fn(S, T) -> S,
    {
        store_events.into_iter().fold(self, |state, store_event| {
            let sequence_number = *store_event.sequence_number();
            let inner = apply_event(state.inner, store_event.payload);

            Self {
                sequence_number,
                inner,
                ..state
            }
        })
    }

    /// Returns an Uuid representing the aggregate id.
    pub const fn id(&self) -> &Uuid {
        &self.id
    }

    /// Returns the internal state.
    pub const fn inner(&self) -> &S {
        &self.inner
    }

    /// Consumes self and extracts the internal state.
    pub fn into_inner(self) -> S {
        self.inner
    }

    /// Returns the internal sequence number.
    pub const fn sequence_number(&self) -> &SequenceNumber {
        &self.sequence_number
    }

    /// Computes the internal sequence number incremented by 1.
    pub fn next_sequence_number(&mut self) -> SequenceNumber {
        self.sequence_number += 1;
        self.sequence_number
    }

    /// Inserts the lock guard into self, replacing any current one.
    pub fn set_lock(&mut self, guard: EventStoreLockGuard) {
        self.lock = Some(guard);
    }

    /// Extracts the lock from self, leaving nothing behind.
    pub fn take_lock(&mut self) -> Option<EventStoreLockGuard> {
        self.lock.take()
    }
}