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