use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::DomainEvent;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventEnvelope<E: DomainEvent> {
pub id: String,
pub event_type: &'static str,
pub aggregate_id: String,
pub aggregate_type: &'static str,
#[serde(skip)]
event: Option<E>,
pub occurred_at: DateTime<Utc>,
pub published_at: DateTime<Utc>,
pub correlation_id: Option<String>,
pub causation_id: Option<String>,
pub version: u32,
#[serde(default)]
pub metadata: std::collections::HashMap<String, String>,
}
impl<E: DomainEvent> EventEnvelope<E> {
pub fn new(event: E) -> Self {
Self {
id: Uuid::new_v4().to_string(),
event_type: event.event_type(),
aggregate_id: event.aggregate_id().to_string(),
aggregate_type: event.aggregate_type(),
occurred_at: event.occurred_at(),
published_at: Utc::now(),
version: event.version(),
event: Some(event),
correlation_id: None,
causation_id: None,
metadata: std::collections::HashMap::new(),
}
}
pub fn event(&self) -> Option<&E> {
self.event.as_ref()
}
pub fn into_event(self) -> Option<E> {
self.event
}
pub fn with_correlation_id(mut self, id: impl Into<String>) -> Self {
self.correlation_id = Some(id.into());
self
}
pub fn with_causation_id(mut self, id: impl Into<String>) -> Self {
self.causation_id = Some(id.into());
self
}
pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
pub fn is_correlated_with(&self, other: &Self) -> bool {
match (&self.correlation_id, &other.correlation_id) {
(Some(a), Some(b)) => a == b,
_ => false,
}
}
pub fn was_caused_by(&self, other: &Self) -> bool {
match &self.causation_id {
Some(causation) => causation == &other.id,
None => false,
}
}
}
pub struct EventEnvelopeBuilder<E: DomainEvent> {
envelope: EventEnvelope<E>,
}
impl<E: DomainEvent> EventEnvelopeBuilder<E> {
pub fn new(event: E) -> Self {
Self {
envelope: EventEnvelope::new(event),
}
}
pub fn correlation_id(mut self, id: impl Into<String>) -> Self {
self.envelope.correlation_id = Some(id.into());
self
}
pub fn causation_id(mut self, id: impl Into<String>) -> Self {
self.envelope.causation_id = Some(id.into());
self
}
pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.envelope.metadata.insert(key.into(), value.into());
self
}
pub fn build(self) -> EventEnvelope<E> {
self.envelope
}
}