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
use serde::{
    de::DeserializeOwned,
    Serialize,
};

use crate::events::DomainEvent;

use super::errors::AggregateError;

/// In CQRS (and Domain Driven Design) an `Aggregate` is the
/// fundamental component that encapsulates the state and application
/// logic (aka business rules) for the application. An `Aggregate` is
/// always an entity along with all objects associated with it.
///
/// # Examples
/// ```rust
/// # use cqrs_es2::doc::{CustomerEvent, CustomerCommand, NameAdded};
/// # use cqrs_es2::{Aggregate, AggregateError};
/// # use serde::{Serialize,Deserialize};
/// #[derive(Serialize,Deserialize)]
/// struct Customer {
///     customer_id: String,
///     name: String,
///     email: String,
/// }
///
/// impl Aggregate for Customer {
///     type Command = CustomerCommand;
///     type Event = CustomerEvent;
///
///     fn aggregate_type() -> &'static str { "customer" }
///
///     fn handle(&self, command: Self::Command) -> Result<Vec<Self::Event>, AggregateError> {
///         match command {
///             CustomerCommand::AddCustomerName(payload) => {
///                 if self.name.as_str() != "" {
///                     return Err(AggregateError::new("a name has already been added for this customer"));
///                 }
///                 let payload = NameAdded {
///                     changed_name: payload.changed_name
///                 };
///                 Ok(vec![CustomerEvent::NameAdded(payload)])
///             }
///             CustomerCommand::UpdateEmail(_) => {
///                 Ok(Default::default())
///             }
///         }
///     }
///
///     fn apply(&mut self, event: &Self::Event) {
///         match event {
///             CustomerEvent::NameAdded(payload) => {
///                 self.name = payload.changed_name.clone();
///             }
///             CustomerEvent::EmailUpdated(payload) => {
///                 self.email = payload.new_email.clone();
///             }
///         }
///     }
/// }
///
/// impl Default for Customer {fn default() -> Self {
///         Customer {
///             customer_id: "".to_string(),
///             name: "".to_string(),
///             email: "".to_string(),
///         }
///     }
/// }
/// ```
pub trait Aggregate:
    Default + Serialize + DeserializeOwned + Sync + Send {
    /// An inbound command used to make changes in the state of the
    /// Aggregate
    type Command;
    /// An event representing some change in state of the Aggregate
    type Event: DomainEvent;
    /// aggregate_type is a unique identifier for this aggregate
    fn aggregate_type() -> &'static str;
    /// handle inbound command and return a vector of events or an
    /// error
    fn handle(
        &self,
        command: Self::Command,
    ) -> Result<Vec<Self::Event>, AggregateError>;
    /// Update the aggregate's state with an event
    fn apply(
        &mut self,
        event: &Self::Event,
    );
}