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
use actix::Message;
use chrono::DateTime;
use chrono::Utc;
use serde::Serialize;
use serde_json::json;
use uuid::Uuid;

pub mod error;

pub use error::*;

#[cfg(test)]
mod test;

/// Represent event that can be handled by an `EventStore`
pub trait Event: Serialize + Send + std::convert::TryFrom<RecordedEvent> {
    /// Returns a `'static str` which defines the event type
    ///
    /// This `str` must be as precise as possible.
    fn event_type(&self) -> &'static str;

    /// Returns every possible string representations of the event.
    ///
    /// Useful to define particular variant types for an enum
    fn all_event_types() -> Vec<&'static str>;
}

/// A `RecordedEvent` represents an `Event` which have been append to a `Stream`
#[derive(sqlx::FromRow, Debug, Clone, Message, Serialize)]
#[rtype(result = "()")]
pub struct RecordedEvent {
    /// an incrementing and gapless integer used to order the event in a stream.
    #[sqlx(try_from = "i64")]
    pub event_number: u64,
    /// Unique identifier for this event
    pub event_uuid: Uuid,
    /// The stream identifier for thie event
    pub stream_uuid: String,
    /// The stream version when this event was appended
    pub stream_version: Option<i64>,
    /// a `causation_id` defines who caused this event
    pub causation_id: Option<Uuid>,
    /// a `correlation_id` correlates multiple events
    pub correlation_id: Option<Uuid>,
    /// Human readable event type
    pub event_type: String,
    /// Payload of this event
    pub data: serde_json::Value,
    /// Metadata defined for this event
    pub metadata: Option<String>,
    /// Event time creation
    pub created_at: DateTime<chrono::offset::Utc>,
}

impl RecordedEvent {
    /// # Errors
    pub fn try_deserialize<
        'de,
        T: serde::Deserialize<'de> + Event + serde::de::Deserialize<'de>,
    >(
        &'de self,
    ) -> Result<T, RecordedEventError> {
        Ok(T::deserialize(&self.data)?)
    }
}

/// An `UnsavedEvent` is created from a type that implement `Event`
///
/// This kind of event represents an unsaved event, meaning that it has less informations
/// than a `RecordedEvent`. It's a generic form to simplify the event processing but also a way to
/// define `metadata`, `causation_id` and `correlation_id`.
#[derive(Debug, Clone, PartialEq)]
pub struct UnsavedEvent {
    /// a `causation_id` defines who caused this event
    pub causation_id: Option<Uuid>,
    /// a `correlation_id` correlates multiple events
    pub correlation_id: Option<Uuid>,
    /// Human readable event type
    pub event_type: String,
    /// Payload of this event
    pub data: serde_json::Value,
    /// Metadata defined for this event
    pub metadata: serde_json::Value,
    pub event_uuid: Uuid,
    pub stream_uuid: String,
    pub stream_version: u64,
    pub created_at: DateTime<chrono::offset::Utc>,
}

impl UnsavedEvent {
    /// Try to create an `UnsavedEvent` from a struct that implement `Event`.
    ///
    /// In case of a success an `UnsavedEvent` is returned with no context or metadata.
    ///
    /// # Errors
    /// If `serde` isn't able to serialize the `Event` an `UnsavedEventError::SerializeError` is
    /// returned
    pub fn try_from<E: Event>(event: &E) -> Result<Self, UnsavedEventError> {
        Ok(Self {
            causation_id: None,
            correlation_id: None,
            event_type: event.event_type().to_owned(),
            data: serde_json::to_value(event)?,
            metadata: json!({}),
            event_uuid: Uuid::new_v4(),
            stream_uuid: String::new(),
            stream_version: 0,
            created_at: Utc::now(),
        })
    }
}