konduto/types/events/
event.rs1use crate::types::validation_errors::ValidationError;
2use serde::{Deserialize, Serialize};
3
4use super::{EventName, EventSubtype, EventType, Ticket, Venue};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct Event {
11 pub name: EventName,
13
14 pub date: String,
16
17 #[serde(rename = "type")]
19 pub event_type: EventType,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub subtype: Option<EventSubtype>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub venue: Option<Venue>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub tickets: Option<Vec<Ticket>>,
32}
33
34impl Event {
35 pub fn builder() -> EventBuilder {
37 EventBuilder::default()
38 }
39}
40
41#[derive(Default)]
43pub struct EventBuilder {
44 name: Option<EventName>,
45 date: Option<String>,
46 event_type: Option<EventType>,
47 subtype: Option<EventSubtype>,
48 venue: Option<Venue>,
49 tickets: Vec<Ticket>,
50}
51
52impl EventBuilder {
53 pub fn name(mut self, name: EventName) -> Self {
54 self.name = Some(name);
55 self
56 }
57
58 pub fn name_str(mut self, name: impl Into<String>) -> Result<Self, ValidationError> {
59 self.name = Some(EventName::try_new(name)?);
60 Ok(self)
61 }
62
63 pub fn date(mut self, date: impl Into<String>) -> Self {
64 self.date = Some(date.into());
65 self
66 }
67
68 pub fn event_type(mut self, event_type: EventType) -> Self {
69 self.event_type = Some(event_type);
70 self
71 }
72
73 pub fn subtype(mut self, subtype: EventSubtype) -> Self {
74 self.subtype = Some(subtype);
75 self
76 }
77
78 pub fn subtype_str(mut self, subtype: impl Into<String>) -> Result<Self, ValidationError> {
79 self.subtype = Some(EventSubtype::try_new(subtype)?);
80 Ok(self)
81 }
82
83 pub fn venue(mut self, venue: Venue) -> Self {
84 self.venue = Some(venue);
85 self
86 }
87
88 pub fn add_ticket(mut self, ticket: Ticket) -> Self {
89 self.tickets.push(ticket);
90 self
91 }
92
93 pub fn tickets(mut self, tickets: Vec<Ticket>) -> Self {
94 self.tickets = tickets;
95 self
96 }
97
98 pub fn build(self) -> Result<Event, ValidationError> {
99 let date = self
100 .date
101 .ok_or_else(|| ValidationError::EmptyField("event_date".to_string()))?;
102
103 if date.len() > 17 {
105 return Err(ValidationError::TooLong {
106 field: "event_date".to_string(),
107 max: 17,
108 actual: date.len(),
109 });
110 }
111
112 let tickets = if self.tickets.is_empty() {
113 None
114 } else {
115 Some(self.tickets)
116 };
117
118 Ok(Event {
119 name: self
120 .name
121 .ok_or_else(|| ValidationError::EmptyField("event_name".to_string()))?,
122 date,
123 event_type: self
124 .event_type
125 .ok_or_else(|| ValidationError::EmptyField("event_type".to_string()))?,
126 subtype: self.subtype,
127 venue: self.venue,
128 tickets,
129 })
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::types::address::Country;
137 use crate::types::events::{Attendee, TicketCategory};
138
139 #[test]
140 fn test_event_complete() {
141 let venue = Venue::builder()
142 .name_str("Teatro Municipal")
143 .unwrap()
144 .city_str("São Paulo")
145 .unwrap()
146 .country(Country::BR)
147 .capacity(500)
148 .build()
149 .unwrap();
150
151 let attendee = Attendee::builder()
152 .name_str("João Silva")
153 .unwrap()
154 .document_str("12345678900")
155 .unwrap()
156 .build()
157 .unwrap();
158
159 let ticket = Ticket::builder()
160 .category(TicketCategory::Regular)
161 .premium(false)
162 .attendee(attendee)
163 .build()
164 .unwrap();
165
166 let event = Event::builder()
167 .name_str("Peça de Teatro")
168 .unwrap()
169 .date("2025-12-01T20:00Z")
170 .event_type(EventType::Theater)
171 .subtype_str("drama")
172 .unwrap()
173 .venue(venue)
174 .add_ticket(ticket)
175 .build()
176 .unwrap();
177
178 assert_eq!(event.name.as_str(), "Peça de Teatro");
179 assert_eq!(event.date, "2025-12-01T20:00Z");
180 assert_eq!(event.event_type, EventType::Theater);
181 assert!(event.venue.is_some());
182 assert!(event.tickets.is_some());
183 }
184
185 #[test]
186 fn test_event_minimal() {
187 let event = Event::builder()
188 .name_str("Show Simples")
189 .unwrap()
190 .date("2025-12-01T20:00Z")
191 .event_type(EventType::Show)
192 .build()
193 .unwrap();
194
195 assert_eq!(event.name.as_str(), "Show Simples");
196 assert!(event.venue.is_none());
197 assert!(event.tickets.is_none());
198 assert!(event.subtype.is_none());
199 }
200
201 #[test]
202 fn test_event_multiple_tickets() {
203 let attendee1 = Attendee::builder()
204 .document_str("111")
205 .unwrap()
206 .build()
207 .unwrap();
208
209 let attendee2 = Attendee::builder()
210 .document_str("222")
211 .unwrap()
212 .build()
213 .unwrap();
214
215 let ticket1 = Ticket::builder()
216 .category(TicketCategory::Student)
217 .premium(false)
218 .attendee(attendee1)
219 .build()
220 .unwrap();
221
222 let ticket2 = Ticket::builder()
223 .category(TicketCategory::Regular)
224 .premium(true)
225 .attendee(attendee2)
226 .build()
227 .unwrap();
228
229 let event = Event::builder()
230 .name_str("Festival")
231 .unwrap()
232 .date("2025-12-01T20:00Z")
233 .event_type(EventType::Festival)
234 .add_ticket(ticket1)
235 .add_ticket(ticket2)
236 .build()
237 .unwrap();
238
239 assert_eq!(event.tickets.as_ref().unwrap().len(), 2);
240 }
241
242 #[test]
243 fn test_event_missing_name() {
244 let result = Event::builder()
245 .date("2025-12-01T20:00Z")
246 .event_type(EventType::Show)
247 .build();
248
249 assert!(result.is_err());
250 }
251
252 #[test]
253 fn test_event_missing_date() {
254 let result = Event::builder()
255 .name_str("Test")
256 .unwrap()
257 .event_type(EventType::Show)
258 .build();
259
260 assert!(result.is_err());
261 }
262
263 #[test]
264 fn test_event_missing_type() {
265 let result = Event::builder()
266 .name_str("Test")
267 .unwrap()
268 .date("2025-12-01T20:00Z")
269 .build();
270
271 assert!(result.is_err());
272 }
273
274 #[test]
275 fn test_event_serialization() {
276 let event = Event::builder()
277 .name_str("Rock Concert")
278 .unwrap()
279 .date("2025-12-01T20:00Z")
280 .event_type(EventType::Show)
281 .subtype_str("rock")
282 .unwrap()
283 .build()
284 .unwrap();
285
286 let json = serde_json::to_string_pretty(&event).unwrap();
287 assert!(json.contains("Rock Concert"));
288 assert!(json.contains("2025-12-01T20:00Z"));
289 assert!(json.contains("show"));
290 assert!(json.contains("rock"));
291 }
292
293 #[test]
294 fn test_event_deserialization() {
295 let json = r#"{
296 "name": "Test Event",
297 "date": "2025-12-01T20:00Z",
298 "type": "theater"
299 }"#;
300
301 let event: Event = serde_json::from_str(json).unwrap();
302 assert_eq!(event.name.as_str(), "Test Event");
303 assert_eq!(event.event_type, EventType::Theater);
304 }
305
306 #[test]
307 fn test_event_roundtrip() {
308 let original = Event::builder()
309 .name_str("Test")
310 .unwrap()
311 .date("2025-12-01T20:00Z")
312 .event_type(EventType::Sports)
313 .build()
314 .unwrap();
315
316 let json = serde_json::to_string(&original).unwrap();
317 let deserialized: Event = serde_json::from_str(&json).unwrap();
318
319 assert_eq!(original, deserialized);
320 }
321
322 #[test]
323 fn test_event_all_types() {
324 let types = vec![
325 EventType::Show,
326 EventType::Theater,
327 EventType::Movies,
328 EventType::Party,
329 EventType::Festival,
330 EventType::Course,
331 EventType::Sports,
332 EventType::Corporate,
333 ];
334
335 for event_type in types {
336 let event = Event::builder()
337 .name_str("Test Event")
338 .unwrap()
339 .date("2025-12-01T20:00Z")
340 .event_type(event_type)
341 .build()
342 .unwrap();
343
344 assert_eq!(event.event_type, event_type);
345 }
346 }
347}
348