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