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!(
185 format!("{event_id}"),
186 "550e8400-e29b-41d4-a716-446655440000"
187 );
188 }
189
190 #[test]
191 fn test_from_uuid_trait() {
192 let uuid = Uuid::new_v4();
193 let event_id: EventId = uuid.into();
194 assert_eq!(event_id.as_uuid(), uuid);
195 }
196
197 #[test]
198 fn test_into_uuid_trait() {
199 let event_id = EventId::new();
200 let uuid: Uuid = event_id.into();
201 assert_eq!(uuid, event_id.as_uuid());
202 }
203
204 #[test]
205 fn test_try_from_str() {
206 let event_id: Result<EventId> = "550e8400-e29b-41d4-a716-446655440000".try_into();
207 assert!(event_id.is_ok());
208
209 let invalid: Result<EventId> = "invalid".try_into();
210 assert!(invalid.is_err());
211 }
212
213 #[test]
214 fn test_try_from_string() {
215 let event_id: Result<EventId> = "550e8400-e29b-41d4-a716-446655440000"
216 .to_string()
217 .try_into();
218 assert!(event_id.is_ok());
219
220 let invalid: Result<EventId> = String::new().try_into();
221 assert!(invalid.is_err());
222 }
223
224 #[test]
225 fn test_equality() {
226 let uuid = Uuid::new_v4();
227 let id1 = EventId::from_uuid(uuid);
228 let id2 = EventId::from_uuid(uuid);
229 let id3 = EventId::new();
230
231 assert_eq!(id1, id2);
232 assert_ne!(id1, id3);
233 }
234
235 #[test]
236 fn test_cloning() {
237 let id1 = EventId::new();
238 let id2 = id1; assert_eq!(id1, id2);
240 }
241
242 #[test]
243 fn test_hash_consistency() {
244 use std::collections::HashSet;
245
246 let uuid = Uuid::new_v4();
247 let id1 = EventId::from_uuid(uuid);
248 let id2 = EventId::from_uuid(uuid);
249
250 let mut set = HashSet::new();
251 set.insert(id1);
252
253 assert!(set.contains(&id2));
254 }
255
256 #[test]
257 fn test_serde_serialization() {
258 let event_id = EventId::parse("550e8400-e29b-41d4-a716-446655440000").unwrap();
259
260 let json = serde_json::to_string(&event_id).unwrap();
262 assert_eq!(json, "\"550e8400-e29b-41d4-a716-446655440000\"");
263
264 let deserialized: EventId = serde_json::from_str(&json).unwrap();
266 assert_eq!(deserialized, event_id);
267 }
268
269 #[test]
270 fn test_as_ref() {
271 let event_id = EventId::new();
272 let uuid_ref: &Uuid = event_id.as_ref();
273 assert_eq!(*uuid_ref, event_id.as_uuid());
274 }
275}