use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Event {
pub id: EventId,
pub event_type: EventType,
pub source: EventSource,
pub data: EventData,
pub metadata: EventMetadata,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct EventId(pub String);
impl EventId {
pub fn new() -> Self {
EventId(uuid::Uuid::new_v4().to_string())
}
}
impl Default for EventId {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum EventType {
Create,
Update,
Delete,
Truncate,
Schema,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventSource {
pub database: String,
pub schema: String,
pub table: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventData {
pub key: serde_json::Value,
pub old: Option<HashMap<String, serde_json::Value>>,
pub new: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventMetadata {
pub transaction_id: Option<String>,
pub position: String,
#[serde(flatten)]
pub custom: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CdcEvent {
pub event_type: EventType,
pub table: String,
pub schema: String,
pub data: HashMap<String, serde_json::Value>,
pub timestamp: DateTime<Utc>,
pub position: Option<super::Position>,
}
impl From<CdcEvent> for Event {
fn from(cdc: CdcEvent) -> Self {
let key = cdc
.data
.get("id")
.or_else(|| cdc.data.get("_id"))
.cloned()
.unwrap_or(serde_json::Value::Null);
let data = match cdc.event_type {
EventType::Create => EventData {
key: key.clone(),
old: None,
new: Some(cdc.data),
},
EventType::Update => EventData {
key: key.clone(),
old: None, new: Some(cdc.data),
},
EventType::Delete => EventData {
key: key.clone(),
old: Some(cdc.data),
new: None,
},
_ => EventData {
key,
old: None,
new: None,
},
};
Event {
id: EventId::new(),
event_type: cdc.event_type,
source: EventSource {
database: String::new(), schema: cdc.schema,
table: cdc.table,
},
data,
metadata: EventMetadata {
transaction_id: None,
position: String::new(), custom: HashMap::new(),
},
timestamp: cdc.timestamp,
}
}
}