1use crate::domain::value_objects::{EntityId, EventType, TenantId};
2use crate::error::Result;
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20pub struct Event {
21 pub id: Uuid,
22 pub event_type: EventType,
23 pub entity_id: EntityId,
24 #[serde(default = "default_tenant_id")]
25 pub tenant_id: TenantId,
26 pub payload: serde_json::Value,
27 pub timestamp: DateTime<Utc>,
28 pub metadata: Option<serde_json::Value>,
29 pub version: i64,
30}
31
32fn default_tenant_id() -> TenantId {
33 TenantId::default_tenant()
34}
35
36impl Event {
37 pub fn new(
39 event_type: EventType,
40 entity_id: EntityId,
41 tenant_id: TenantId,
42 payload: serde_json::Value,
43 ) -> Self {
44 Self {
45 id: Uuid::new_v4(),
46 event_type,
47 entity_id,
48 tenant_id,
49 payload,
50 timestamp: Utc::now(),
51 metadata: None,
52 version: 1,
53 }
54 }
55
56 pub fn with_metadata(
58 event_type: EventType,
59 entity_id: EntityId,
60 tenant_id: TenantId,
61 payload: serde_json::Value,
62 metadata: serde_json::Value,
63 ) -> Self {
64 Self {
65 id: Uuid::new_v4(),
66 event_type,
67 entity_id,
68 tenant_id,
69 payload,
70 timestamp: Utc::now(),
71 metadata: Some(metadata),
72 version: 1,
73 }
74 }
75
76 pub fn with_default_tenant(
78 event_type: EventType,
79 entity_id: EntityId,
80 payload: serde_json::Value,
81 ) -> Self {
82 Self::new(event_type, entity_id, TenantId::default_tenant(), payload)
83 }
84
85 pub fn from_strings(
90 event_type: String,
91 entity_id: String,
92 tenant_id: String,
93 payload: serde_json::Value,
94 metadata: Option<serde_json::Value>,
95 ) -> Result<Self> {
96 let event_type = EventType::new(event_type)?;
97 let entity_id = EntityId::new(entity_id)?;
98 let tenant_id = TenantId::new(tenant_id)?;
99
100 Ok(Self {
101 id: Uuid::new_v4(),
102 event_type,
103 entity_id,
104 tenant_id,
105 payload,
106 timestamp: Utc::now(),
107 metadata,
108 version: 1,
109 })
110 }
111
112 pub fn reconstruct(
114 id: Uuid,
115 event_type: EventType,
116 entity_id: EntityId,
117 tenant_id: TenantId,
118 payload: serde_json::Value,
119 timestamp: DateTime<Utc>,
120 metadata: Option<serde_json::Value>,
121 version: i64,
122 ) -> Self {
123 Self {
124 id,
125 event_type,
126 entity_id,
127 tenant_id,
128 payload,
129 timestamp,
130 metadata,
131 version,
132 }
133 }
134
135 pub fn reconstruct_from_strings(
137 id: Uuid,
138 event_type: String,
139 entity_id: String,
140 tenant_id: String,
141 payload: serde_json::Value,
142 timestamp: DateTime<Utc>,
143 metadata: Option<serde_json::Value>,
144 version: i64,
145 ) -> Self {
146 Self {
147 id,
148 event_type: EventType::new_unchecked(event_type),
149 entity_id: EntityId::new_unchecked(entity_id),
150 tenant_id: TenantId::new_unchecked(tenant_id),
151 payload,
152 timestamp,
153 metadata,
154 version,
155 }
156 }
157
158 pub fn id(&self) -> Uuid {
161 self.id
162 }
163
164 pub fn event_type(&self) -> &EventType {
165 &self.event_type
166 }
167
168 pub fn event_type_str(&self) -> &str {
169 self.event_type.as_str()
170 }
171
172 pub fn entity_id(&self) -> &EntityId {
173 &self.entity_id
174 }
175
176 pub fn entity_id_str(&self) -> &str {
177 self.entity_id.as_str()
178 }
179
180 pub fn tenant_id(&self) -> &TenantId {
181 &self.tenant_id
182 }
183
184 pub fn tenant_id_str(&self) -> &str {
185 self.tenant_id.as_str()
186 }
187
188 pub fn payload(&self) -> &serde_json::Value {
189 &self.payload
190 }
191
192 pub fn timestamp(&self) -> DateTime<Utc> {
193 self.timestamp
194 }
195
196 pub fn metadata(&self) -> Option<&serde_json::Value> {
197 self.metadata.as_ref()
198 }
199
200 pub fn version(&self) -> i64 {
201 self.version
202 }
203
204 pub fn belongs_to_tenant(&self, tenant_id: &TenantId) -> bool {
208 &self.tenant_id == tenant_id
209 }
210
211 pub fn belongs_to_tenant_str(&self, tenant_id: &str) -> bool {
213 self.tenant_id.as_str() == tenant_id
214 }
215
216 pub fn relates_to_entity(&self, entity_id: &EntityId) -> bool {
218 &self.entity_id == entity_id
219 }
220
221 pub fn relates_to_entity_str(&self, entity_id: &str) -> bool {
223 self.entity_id.as_str() == entity_id
224 }
225
226 pub fn is_type(&self, event_type: &EventType) -> bool {
228 &self.event_type == event_type
229 }
230
231 pub fn is_type_str(&self, event_type: &str) -> bool {
233 self.event_type.as_str() == event_type
234 }
235
236 pub fn is_in_namespace(&self, namespace: &str) -> bool {
238 self.event_type.is_in_namespace(namespace)
239 }
240
241 pub fn occurred_between(&self, start: DateTime<Utc>, end: DateTime<Utc>) -> bool {
243 self.timestamp >= start && self.timestamp <= end
244 }
245
246 pub fn occurred_before(&self, time: DateTime<Utc>) -> bool {
248 self.timestamp < time
249 }
250
251 pub fn occurred_after(&self, time: DateTime<Utc>) -> bool {
253 self.timestamp > time
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use serde_json::json;
261
262 fn test_event_type() -> EventType {
263 EventType::new("user.created".to_string()).unwrap()
264 }
265
266 fn test_entity_id() -> EntityId {
267 EntityId::new("user-123".to_string()).unwrap()
268 }
269
270 fn test_tenant_id() -> TenantId {
271 TenantId::new("tenant-1".to_string()).unwrap()
272 }
273
274 #[test]
275 fn test_event_creation_with_value_objects() {
276 let event = Event::new(
277 test_event_type(),
278 test_entity_id(),
279 test_tenant_id(),
280 json!({"name": "Alice"}),
281 );
282
283 assert_eq!(event.event_type_str(), "user.created");
284 assert_eq!(event.entity_id_str(), "user-123");
285 assert_eq!(event.tenant_id_str(), "tenant-1");
286 assert_eq!(event.version(), 1);
287 }
288
289 #[test]
290 fn test_event_creation_from_strings() {
291 let event = Event::from_strings(
292 "user.created".to_string(),
293 "user-123".to_string(),
294 "tenant-1".to_string(),
295 json!({"name": "Alice"}),
296 None,
297 );
298
299 assert!(event.is_ok());
300 let event = event.unwrap();
301 assert_eq!(event.event_type_str(), "user.created");
302 assert_eq!(event.entity_id_str(), "user-123");
303 assert_eq!(event.tenant_id_str(), "tenant-1");
304 }
305
306 #[test]
307 fn test_event_with_metadata() {
308 let event = Event::with_metadata(
309 test_event_type(),
310 test_entity_id(),
311 test_tenant_id(),
312 json!({"name": "Bob"}),
313 json!({"source": "api"}),
314 );
315
316 assert!(event.metadata().is_some());
317 assert_eq!(event.metadata().unwrap(), &json!({"source": "api"}));
318 }
319
320 #[test]
321 fn test_event_with_default_tenant() {
322 let event = Event::with_default_tenant(test_event_type(), test_entity_id(), json!({}));
323
324 assert_eq!(event.tenant_id_str(), "default");
325 }
326
327 #[test]
328 fn test_from_strings_validates_event_type() {
329 let result = Event::from_strings(
331 "User.Created".to_string(),
332 "e1".to_string(),
333 "t1".to_string(),
334 json!({}),
335 None,
336 );
337 assert!(result.is_err());
338
339 let result = Event::from_strings(
341 "".to_string(),
342 "e1".to_string(),
343 "t1".to_string(),
344 json!({}),
345 None,
346 );
347 assert!(result.is_err());
348 }
349
350 #[test]
351 fn test_from_strings_validates_entity_id() {
352 let result = Event::from_strings(
354 "user.created".to_string(),
355 "".to_string(),
356 "t1".to_string(),
357 json!({}),
358 None,
359 );
360 assert!(result.is_err());
361 }
362
363 #[test]
364 fn test_from_strings_validates_tenant_id() {
365 let result = Event::from_strings(
367 "user.created".to_string(),
368 "e1".to_string(),
369 "".to_string(),
370 json!({}),
371 None,
372 );
373 assert!(result.is_err());
374 }
375
376 #[test]
377 fn test_belongs_to_tenant() {
378 let tenant1 = TenantId::new("tenant-1".to_string()).unwrap();
379 let tenant2 = TenantId::new("tenant-2".to_string()).unwrap();
380
381 let event = Event::new(
382 test_event_type(),
383 test_entity_id(),
384 tenant1.clone(),
385 json!({}),
386 );
387
388 assert!(event.belongs_to_tenant(&tenant1));
389 assert!(!event.belongs_to_tenant(&tenant2));
390 }
391
392 #[test]
393 fn test_belongs_to_tenant_str() {
394 let event = Event::new(
395 test_event_type(),
396 test_entity_id(),
397 test_tenant_id(),
398 json!({}),
399 );
400
401 assert!(event.belongs_to_tenant_str("tenant-1"));
402 assert!(!event.belongs_to_tenant_str("tenant-2"));
403 }
404
405 #[test]
406 fn test_relates_to_entity() {
407 let entity1 = EntityId::new("order-456".to_string()).unwrap();
408 let entity2 = EntityId::new("order-789".to_string()).unwrap();
409
410 let event = Event::new(
411 EventType::new("order.placed".to_string()).unwrap(),
412 entity1.clone(),
413 test_tenant_id(),
414 json!({}),
415 );
416
417 assert!(event.relates_to_entity(&entity1));
418 assert!(!event.relates_to_entity(&entity2));
419 }
420
421 #[test]
422 fn test_relates_to_entity_str() {
423 let event = Event::new(
424 EventType::new("order.placed".to_string()).unwrap(),
425 EntityId::new("order-456".to_string()).unwrap(),
426 test_tenant_id(),
427 json!({}),
428 );
429
430 assert!(event.relates_to_entity_str("order-456"));
431 assert!(!event.relates_to_entity_str("order-789"));
432 }
433
434 #[test]
435 fn test_is_type() {
436 let type1 = EventType::new("order.placed".to_string()).unwrap();
437 let type2 = EventType::new("order.cancelled".to_string()).unwrap();
438
439 let event = Event::new(type1.clone(), test_entity_id(), test_tenant_id(), json!({}));
440
441 assert!(event.is_type(&type1));
442 assert!(!event.is_type(&type2));
443 }
444
445 #[test]
446 fn test_is_type_str() {
447 let event = Event::new(
448 EventType::new("order.placed".to_string()).unwrap(),
449 test_entity_id(),
450 test_tenant_id(),
451 json!({}),
452 );
453
454 assert!(event.is_type_str("order.placed"));
455 assert!(!event.is_type_str("order.cancelled"));
456 }
457
458 #[test]
459 fn test_is_in_namespace() {
460 let event = Event::new(
461 EventType::new("order.placed".to_string()).unwrap(),
462 test_entity_id(),
463 test_tenant_id(),
464 json!({}),
465 );
466
467 assert!(event.is_in_namespace("order"));
468 assert!(!event.is_in_namespace("user"));
469 }
470
471 #[test]
472 fn test_time_range_queries() {
473 let event = Event::new(
474 test_event_type(),
475 test_entity_id(),
476 test_tenant_id(),
477 json!({}),
478 );
479
480 let past = Utc::now() - chrono::Duration::hours(1);
481 let future = Utc::now() + chrono::Duration::hours(1);
482
483 assert!(event.occurred_after(past));
484 assert!(event.occurred_before(future));
485 assert!(event.occurred_between(past, future));
486 }
487
488 #[test]
489 fn test_serde_serialization() {
490 let event = Event::new(
491 test_event_type(),
492 test_entity_id(),
493 test_tenant_id(),
494 json!({"test": "data"}),
495 );
496
497 let json = serde_json::to_string(&event);
499 assert!(json.is_ok());
500
501 let deserialized = serde_json::from_str::<Event>(&json.unwrap());
503 assert!(deserialized.is_ok());
504
505 let deserialized = deserialized.unwrap();
506 assert_eq!(deserialized.event_type_str(), "user.created");
507 assert_eq!(deserialized.entity_id_str(), "user-123");
508 }
509
510 #[test]
511 fn test_reconstruct_from_strings() {
512 let id = Uuid::new_v4();
513 let timestamp = Utc::now();
514
515 let event = Event::reconstruct_from_strings(
516 id,
517 "order.placed".to_string(),
518 "order-123".to_string(),
519 "tenant-1".to_string(),
520 json!({"amount": 100}),
521 timestamp,
522 Some(json!({"source": "api"})),
523 1,
524 );
525
526 assert_eq!(event.id(), id);
527 assert_eq!(event.event_type_str(), "order.placed");
528 assert_eq!(event.entity_id_str(), "order-123");
529 assert_eq!(event.tenant_id_str(), "tenant-1");
530 assert_eq!(event.version(), 1);
531 }
532}