Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions contract/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub struct Event {
pub aggregate_id: String,
/// Type of event (Created, Updated, Deleted, etc.)
pub event_type: String,
/// Schema version of this event type (for backward-compatible evolution)
#[serde(default = "default_version")]
pub version: u32,
/// Event payload as JSON
pub data: serde_json::Value,
/// Timestamp when event occurred
Expand All @@ -23,6 +26,11 @@ pub struct Event {
pub metadata: Option<serde_json::Value>,
}

/// Default event schema version (v1).
fn default_version() -> u32 {
1
}

impl Event {
/// Create a new event
pub fn new(
Expand All @@ -35,6 +43,7 @@ impl Event {
id: Uuid::new_v4().to_string(),
aggregate_id,
event_type,
version: 1,
data,
timestamp: Utc::now(),
sequence: 0,
Expand Down Expand Up @@ -77,6 +86,7 @@ mod tests {

assert_eq!(event.aggregate_id, "doc-1");
assert_eq!(event.event_type, "Created");
assert_eq!(event.version, 1);
assert!(!event.id.is_empty());
}

Expand All @@ -94,5 +104,39 @@ mod tests {

assert_eq!(event.id, deserialized.id);
assert_eq!(event.aggregate_id, deserialized.aggregate_id);
assert_eq!(deserialized.version, 1);
}

#[test]
fn test_version_in_serialized_json() {
let event = Event::new(
"doc-2".to_string(),
"Updated".to_string(),
serde_json::json!({"field": "value"}),
"user-2".to_string(),
);

let json_str = event.to_json().unwrap();
let raw: serde_json::Value = serde_json::from_str(&json_str).unwrap();
assert_eq!(raw["version"], 1);
}

#[test]
fn test_backward_compat_missing_version_defaults_to_1() {
// Simulate a legacy event stored before version field was added
let legacy_json = serde_json::json!({
"id": "legacy-001",
"aggregate_id": "doc-old",
"event_type": "Created",
"data": {"title": "Legacy"},
"timestamp": "2025-01-01T00:00:00Z",
"sequence": 42,
"actor": "system",
"metadata": null
});

let event: Event = serde_json::from_value(legacy_json).unwrap();
assert_eq!(event.version, 1, "Missing version should default to 1");
assert_eq!(event.aggregate_id, "doc-old");
}
}