use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::Value;
use uuid::Uuid;
use crate::{domain_id::DomainIdValues, error::SerializationError};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EventEnvelope {
pub timestamp: DateTime<Utc>,
pub correlation_id: Uuid,
pub causation_id: Uuid,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub triggering_event_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub idempotency_key: Option<Uuid>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StoredEvent<T> {
pub id: Uuid,
pub position: u64,
pub event_type: String,
pub tags: Vec<String>,
pub timestamp: DateTime<Utc>,
pub correlation_id: Uuid,
pub causation_id: Uuid,
pub triggering_event_id: Option<Uuid>,
pub idempotency_key: Option<Uuid>,
pub data: T,
}
impl<T> StoredEvent<T> {
pub fn with_data<U>(self, data: U) -> StoredEvent<U> {
StoredEvent {
id: self.id,
position: self.position,
event_type: self.event_type,
tags: self.tags,
timestamp: self.timestamp,
correlation_id: self.correlation_id,
causation_id: self.causation_id,
triggering_event_id: self.triggering_event_id,
idempotency_key: self.idempotency_key,
data,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StoredEventData<T> {
pub timestamp: DateTime<Utc>,
pub correlation_id: Uuid,
pub causation_id: Uuid,
pub triggering_event_id: Option<Uuid>,
pub idempotency_key: Option<Uuid>,
pub data: T,
}
pub trait Event: Serialize + DeserializeOwned + Sized {
const EVENT_TYPE: &'static str;
const DOMAIN_ID_FIELDS: &'static [&'static str];
fn domain_ids(&self) -> DomainIdValues;
}
#[derive(Clone, Copy, Debug)]
pub struct EventDomainId {
pub event_type: &'static str,
pub dynamic_fields: &'static [&'static str],
pub static_fields: &'static [(&'static str, &'static str)],
}
pub trait EventSet: Sized {
type Item;
fn event_types() -> Vec<&'static str>;
fn event_domain_ids() -> Vec<EventDomainId>;
fn from_event(event_type: &str, data: Value) -> Option<Result<Self::Item, SerializationError>>;
}
pub trait AsEvent<E> {
fn as_event(&self) -> Option<&E>;
}
pub trait IntoEvent<E> {
fn into_event(self) -> Option<E>;
}
impl<A> EventSet for (A,)
where
A: EventSet,
{
type Item = (Option<A::Item>,);
fn event_types() -> Vec<&'static str> {
A::event_types()
}
fn event_domain_ids() -> Vec<EventDomainId> {
A::event_domain_ids()
}
fn from_event(event_type: &str, data: Value) -> Option<Result<Self::Item, SerializationError>> {
if A::event_types().contains(&event_type) {
return Some(A::from_event(event_type, data)?.map(|a| (Some(a),)));
}
None
}
}
macro_rules! impl_tuple_event_set {
($( $t:ident:$n:tt ),*) => {
impl<$($t,)*> EventSet for ($($t,)*)
where
$(
$t: EventSet,
)*
{
type Item = ($(Option<$t::Item>,)*);
fn event_types() -> Vec<&'static str> {
let mut types = Vec::new();
$(
types.extend_from_slice(&$t::event_types());
)*
types
}
fn event_domain_ids() -> Vec<EventDomainId> {
let mut ids = Vec::new();
$(
ids.extend($t::event_domain_ids());
)*
ids
}
#[allow(non_snake_case)]
fn from_event(event_type: &str, data: Value) -> Option<Result<Self::Item, SerializationError>> {
$(
let $t = $t::from_event(event_type, data.clone());
)*
if $( $t.is_none() )&&* {
return None;
}
$(
let $t = match $t {
None => None,
Some(Ok(v)) => Some(v),
Some(Err(e)) => return Some(Err(e)),
};
)*
Some(Ok(($($t,)*)))
}
}
};
}
impl_tuple_event_set!(A:0, B:1);
impl_tuple_event_set!(A:0, B:1, C:2);
impl_tuple_event_set!(A:0, B:1, C:2, D:3);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7, I:8);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7, I:8, J:9);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7, I:8, J:9, K:10);
impl_tuple_event_set!(A:0, B:1, C:2, D:3, E:4, F:5, G:6, H:7, I:8, J:9, K:10, L:11);