allsource_core/domain/value_objects/
event_id.rs1use crate::error::Result;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use uuid::Uuid;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct EventId(Uuid);
22
23impl EventId {
24 pub fn new() -> Self {
34 Self(Uuid::new_v4())
35 }
36
37 pub fn from_uuid(uuid: Uuid) -> Self {
49 Self(uuid)
50 }
51
52 pub fn parse(value: &str) -> Result<Self> {
65 let uuid = Uuid::parse_str(value).map_err(|e| {
66 crate::error::AllSourceError::InvalidInput(format!("Invalid event ID '{}': {}", value, e))
67 })?;
68 Ok(Self(uuid))
69 }
70
71 pub fn as_uuid(&self) -> Uuid {
73 self.0
74 }
75
76 pub fn is_nil(&self) -> bool {
78 self.0.is_nil()
79 }
80
81 pub fn nil() -> Self {
83 Self(Uuid::nil())
84 }
85}
86
87impl Default for EventId {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl fmt::Display for EventId {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(f, "{}", self.0)
96 }
97}
98
99impl From<Uuid> for EventId {
100 fn from(uuid: Uuid) -> Self {
101 Self(uuid)
102 }
103}
104
105impl From<EventId> for Uuid {
106 fn from(event_id: EventId) -> Self {
107 event_id.0
108 }
109}
110
111impl TryFrom<&str> for EventId {
112 type Error = crate::error::AllSourceError;
113
114 fn try_from(value: &str) -> Result<Self> {
115 EventId::parse(value)
116 }
117}
118
119impl TryFrom<String> for EventId {
120 type Error = crate::error::AllSourceError;
121
122 fn try_from(value: String) -> Result<Self> {
123 EventId::parse(&value)
124 }
125}
126
127impl AsRef<Uuid> for EventId {
128 fn as_ref(&self) -> &Uuid {
129 &self.0
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn test_create_event_id() {
139 let event_id = EventId::new();
140 assert!(!event_id.is_nil());
141 }
142
143 #[test]
144 fn test_from_uuid() {
145 let uuid = Uuid::new_v4();
146 let event_id = EventId::from_uuid(uuid);
147 assert_eq!(event_id.as_uuid(), uuid);
148 }
149
150 #[test]
151 fn test_parse_valid_uuid() {
152 let uuid_str = "550e8400-e29b-41d4-a716-446655440000";
153 let event_id = EventId::parse(uuid_str);
154 assert!(event_id.is_ok());
155 assert_eq!(event_id.unwrap().to_string(), uuid_str);
156 }
157
158 #[test]
159 fn test_parse_invalid_uuid() {
160 let invalid = "not-a-uuid";
161 let result = EventId::parse(invalid);
162 assert!(result.is_err());
163 }
164
165 #[test]
166 fn test_nil_event_id() {
167 let nil_id = EventId::nil();
168 assert!(nil_id.is_nil());
169 assert_eq!(nil_id.to_string(), "00000000-0000-0000-0000-000000000000");
170 }
171
172 #[test]
173 fn test_default_creates_new_uuid() {
174 let id1 = EventId::default();
175 let id2 = EventId::default();
176 assert_ne!(id1, id2);
177 assert!(!id1.is_nil());
178 }
179
180 #[test]
181 fn test_display_trait() {
182 let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
183 let event_id = EventId::from_uuid(uuid);
184 assert_eq!(format!("{}", event_id), "550e8400-e29b-41d4-a716-446655440000");
185 }
186
187 #[test]
188 fn test_from_uuid_trait() {
189 let uuid = Uuid::new_v4();
190 let event_id: EventId = uuid.into();
191 assert_eq!(event_id.as_uuid(), uuid);
192 }
193
194 #[test]
195 fn test_into_uuid_trait() {
196 let event_id = EventId::new();
197 let uuid: Uuid = event_id.into();
198 assert_eq!(uuid, event_id.as_uuid());
199 }
200
201 #[test]
202 fn test_try_from_str() {
203 let event_id: Result<EventId> = "550e8400-e29b-41d4-a716-446655440000".try_into();
204 assert!(event_id.is_ok());
205
206 let invalid: Result<EventId> = "invalid".try_into();
207 assert!(invalid.is_err());
208 }
209
210 #[test]
211 fn test_try_from_string() {
212 let event_id: Result<EventId> = "550e8400-e29b-41d4-a716-446655440000".to_string().try_into();
213 assert!(event_id.is_ok());
214
215 let invalid: Result<EventId> = String::new().try_into();
216 assert!(invalid.is_err());
217 }
218
219 #[test]
220 fn test_equality() {
221 let uuid = Uuid::new_v4();
222 let id1 = EventId::from_uuid(uuid);
223 let id2 = EventId::from_uuid(uuid);
224 let id3 = EventId::new();
225
226 assert_eq!(id1, id2);
227 assert_ne!(id1, id3);
228 }
229
230 #[test]
231 fn test_cloning() {
232 let id1 = EventId::new();
233 let id2 = id1; assert_eq!(id1, id2);
235 }
236
237 #[test]
238 fn test_hash_consistency() {
239 use std::collections::HashSet;
240
241 let uuid = Uuid::new_v4();
242 let id1 = EventId::from_uuid(uuid);
243 let id2 = EventId::from_uuid(uuid);
244
245 let mut set = HashSet::new();
246 set.insert(id1);
247
248 assert!(set.contains(&id2));
249 }
250
251 #[test]
252 fn test_serde_serialization() {
253 let event_id = EventId::parse("550e8400-e29b-41d4-a716-446655440000").unwrap();
254
255 let json = serde_json::to_string(&event_id).unwrap();
257 assert_eq!(json, "\"550e8400-e29b-41d4-a716-446655440000\"");
258
259 let deserialized: EventId = serde_json::from_str(&json).unwrap();
261 assert_eq!(deserialized, event_id);
262 }
263
264 #[test]
265 fn test_as_ref() {
266 let event_id = EventId::new();
267 let uuid_ref: &Uuid = event_id.as_ref();
268 assert_eq!(*uuid_ref, event_id.as_uuid());
269 }
270}