1use regex::Regex;
2use serde::{Deserialize, Serialize};
3use std::{
4 error::Error,
5 fmt::{Display, Formatter, Result as FmtResult},
6 str::FromStr,
7};
8use tracing::{debug, error, warn};
9
10#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub enum ErrorType {
15 UndefinedError,
20
21 CreationError,
25
26 UpdatingError,
30
31 UpdatingManyError,
35
36 FetchingError,
40
41 DeletionError,
45
46 UseCaseError,
50
51 ExecutionError,
56
57 InvalidRepositoryError,
61
62 InvalidArgumentError,
66
67 DataTransferLayerError,
71
72 GeneralError(String),
76}
77
78impl ErrorType {
79 fn default() -> Self {
80 Self::UndefinedError
81 }
82}
83
84impl Display for ErrorType {
85 fn fmt(&self, f: &mut Formatter) -> FmtResult {
86 match self {
87 ErrorType::UndefinedError => write!(f, "undefined-error"),
88 ErrorType::CreationError => write!(f, "creation-error"),
89 ErrorType::UpdatingError => write!(f, "updating-error"),
90 ErrorType::UpdatingManyError => write!(f, "updating-many-error"),
91 ErrorType::FetchingError => write!(f, "fetching-error"),
92 ErrorType::DeletionError => write!(f, "deletion-error"),
93 ErrorType::UseCaseError => write!(f, "use-case-error"),
94 ErrorType::ExecutionError => write!(f, "execution-error"),
95 ErrorType::InvalidRepositoryError => {
96 write!(f, "invalid-repository-error")
97 }
98 ErrorType::InvalidArgumentError => {
99 write!(f, "invalid-argument-error")
100 }
101 ErrorType::DataTransferLayerError => {
102 write!(f, "data-transfer-layer-error")
103 }
104 ErrorType::GeneralError(msg) => write!(f, "{}", msg),
105 }
106 }
107}
108
109impl FromStr for ErrorType {
110 type Err = ();
111
112 fn from_str(s: &str) -> Result<ErrorType, ()> {
113 match s {
114 "undefined-error" => Ok(ErrorType::UndefinedError),
115 "creation-error" => Ok(ErrorType::CreationError),
116 "updating-error" => Ok(ErrorType::UpdatingError),
117 "updating-many-error" => Ok(ErrorType::UpdatingManyError),
118 "fetching-error" => Ok(ErrorType::FetchingError),
119 "deletion-error" => Ok(ErrorType::DeletionError),
120 "use-case-error" => Ok(ErrorType::UseCaseError),
121 "execution-error" => Ok(ErrorType::ExecutionError),
122 "invalid-repository-error" => Ok(ErrorType::InvalidRepositoryError),
123 "invalid-argument-error" => Ok(ErrorType::InvalidArgumentError),
124 "data-transfer-layer-error" => {
125 Ok(ErrorType::DataTransferLayerError)
126 }
127 other => Ok(ErrorType::GeneralError(other.to_string())),
128 }
129 }
130}
131
132#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub enum ErrorCodes {
135 Codes(Vec<String>),
136 Unmapped,
137}
138
139impl ErrorCodes {
140 pub fn default() -> ErrorCodes {
141 ErrorCodes::Unmapped
142 }
143}
144
145impl Display for ErrorCodes {
146 fn fmt(&self, f: &mut Formatter) -> FmtResult {
147 match self {
148 ErrorCodes::Codes(codes) => {
149 write!(f, "{}", codes.join(MappedErrors::codes_delimiter()))
150 }
151 ErrorCodes::Unmapped => write!(f, "unmapped"),
152 }
153 }
154}
155
156#[derive(Debug, Deserialize, Serialize, Clone)]
157pub struct MappedErrors {
158 msg: String,
160
161 error_type: ErrorType,
164
165 expected: bool,
167
168 codes: ErrorCodes,
171}
172
173impl Error for MappedErrors {}
174
175impl Display for MappedErrors {
176 fn fmt(&self, f: &mut Formatter) -> FmtResult {
177 let code_key = MappedErrors::code_key();
178 let error_type_key = MappedErrors::error_type_key();
179
180 let code_value = match self.codes.to_owned() {
181 ErrorCodes::Codes(codes) => codes.join(Self::codes_delimiter()),
182 ErrorCodes::Unmapped => String::from("none"),
183 };
184
185 write!(
186 f,
187 "[{}={}{}{}={}] {}",
188 code_key,
189 code_value,
190 Self::msg_paras_delimiter(),
191 error_type_key,
192 self.error_type,
193 self.msg
194 )
195 }
196}
197
198impl MappedErrors {
199 pub fn error_type(&self) -> ErrorType {
208 self.error_type.to_owned()
209 }
210
211 pub fn msg(&self) -> String {
213 self.msg.to_owned()
214 }
215
216 pub fn code(&self) -> ErrorCodes {
218 self.codes.to_owned()
219 }
220
221 pub fn expected(&self) -> bool {
223 self.expected.to_owned()
224 }
225
226 pub fn has_str_code(&self, code: &str) -> bool {
229 if code == "none" {
230 return false;
231 }
232
233 if let ErrorCodes::Codes(inner_code) = &self.codes {
234 return inner_code.iter().any(|i| i.as_str() == code);
235 };
236
237 false
238 }
239
240 pub fn is_in<T: ToString>(&self, codes: Vec<T>) -> bool {
241 for code in codes {
242 if self.has_str_code(code.to_string().as_str()) {
243 return true;
244 }
245 }
246
247 false
248 }
249
250 pub fn as_error<T>(self) -> Result<T, Self> {
259 if self.expected {
260 debug!("{:?}", &self.to_string());
261 } else {
262 error!("{:?}", &self.to_string());
263 }
264
265 Err(self)
266 }
267
268 pub fn with_exp_true(mut self) -> Self {
270 self.expected = true;
271 self
272 }
273
274 pub fn with_code<T: ToString>(mut self, code: T) -> Self {
276 let binding = code.to_string();
277 let code = binding.as_str();
278 if code == "none" {
279 return self;
280 }
281
282 let mut codes = match self.to_owned().codes {
283 ErrorCodes::Codes(codes) => codes,
284 ErrorCodes::Unmapped => vec![],
285 };
286
287 codes.push(code.to_string());
288 codes.sort();
289 codes.dedup();
290
291 self.codes = ErrorCodes::Codes(codes);
292 self
293 }
294
295 pub fn with_previous(mut self, prev: MappedErrors) -> Self {
297 self.msg = format!(
298 "[CURRENT_ERROR] {}; [PRECEDING_ERROR] {}",
299 self.msg,
300 &prev.to_string()
301 );
302
303 self
304 }
305
306 pub fn with_error_type(mut self, error_type: ErrorType) -> Self {
308 self.error_type = error_type;
309 self
310 }
311
312 pub(super) fn default(msg: String) -> Self {
318 Self {
319 msg: Self::sanitize_msg(msg),
320 error_type: ErrorType::default(),
321 expected: false,
322 codes: ErrorCodes::default(),
323 }
324 }
325
326 pub(super) fn new(
328 msg: String,
329 exp: Option<bool>,
330 prev: Option<MappedErrors>,
331 error_type: ErrorType,
332 ) -> Self {
333 let exp = exp.unwrap_or(true);
334
335 if !exp {
336 error!("Unexpected error: ({}){}", &error_type, &msg);
337 } else {
338 warn!("{:?}", &msg);
339 }
340
341 if prev.is_some() {
342 let updated_msg = format!(
343 "[CURRENT_ERROR] {:?}; [PRECEDING_ERROR] {:?}",
344 msg,
345 &prev.unwrap().msg
346 );
347
348 return Self::new(updated_msg, Some(exp), None, error_type);
349 }
350
351 Self {
352 msg,
353 error_type,
354 expected: exp,
355 codes: ErrorCodes::default(),
356 }
357 }
358
359 fn code_key() -> &'static str {
361 "codes"
362 }
363
364 pub(self) fn codes_delimiter() -> &'static str {
366 ","
367 }
368
369 pub(self) fn msg_paras_delimiter() -> &'static str {
371 " "
372 }
373
374 fn error_type_key() -> &'static str {
376 "error_type"
377 }
378
379 fn sanitize_msg(msg: String) -> String {
381 msg.as_str().replace(";", ",").to_string()
382 }
383
384 pub fn from_str_msg(msg: String) -> Self {
386 let pattern = Regex::new(
387 r"^\[codes=([a-zA-Z0-9,]+)\serror_type=([a-zA-Z-]+)\]\s(.+)$",
388 )
389 .unwrap();
390
391 if pattern.is_match(&msg) {
392 let capture = pattern.captures(&msg).unwrap();
393 let code = &capture[1];
394 let msg = capture[3].to_string();
395
396 let error_type = match ErrorType::from_str(&capture[2]) {
397 Ok(error_type) => error_type,
398 Err(_) => ErrorType::UndefinedError,
399 };
400
401 return MappedErrors::new(msg, None, None, error_type)
402 .with_code(code);
403 };
404
405 MappedErrors::new(msg, None, None, ErrorType::UndefinedError)
406 }
407}
408
409#[cfg(test)]
414mod tests {
415
416 #[test]
417 fn test_error_type() {
418 fn error_dispatcher() -> Result<(), super::MappedErrors> {
419 Err(super::MappedErrors::new(
420 "This is a test error".to_string(),
421 Some(true),
422 None,
423 super::ErrorType::UndefinedError,
424 ))
425 }
426
427 fn error_handler() -> Result<(), super::MappedErrors> {
428 error_dispatcher()?;
429 Ok(())
430 }
431
432 let response = error_handler().unwrap_err();
433
434 assert_eq!(response.error_type(), super::ErrorType::UndefinedError);
435 }
436
437 #[test]
438 fn test_error_msg() {
439 fn error_dispatcher() -> Result<(), super::MappedErrors> {
440 Err(super::MappedErrors::new(
441 "This is a test error".to_string(),
442 Some(true),
443 None,
444 super::ErrorType::UndefinedError,
445 ))
446 }
447
448 fn error_handler() -> Result<(), super::MappedErrors> {
449 error_dispatcher()?;
450 Ok(())
451 }
452
453 let response = error_handler().unwrap_err();
454
455 assert_eq!(
456 response.to_string(),
457 format!(
458 "[{}=none{}{}=undefined-error] This is a test error",
459 super::MappedErrors::code_key(),
460 super::MappedErrors::msg_paras_delimiter(),
461 super::MappedErrors::error_type_key()
462 )
463 );
464 }
465
466 #[test]
467 fn test_from_msg() {
468 let msg = format!(
469 "[{}=none{}{}=undefined-error] This is a test error",
470 super::MappedErrors::code_key(),
471 super::MappedErrors::msg_paras_delimiter(),
472 super::MappedErrors::error_type_key()
473 );
474
475 let response = super::MappedErrors::from_str_msg(msg.to_string());
476 let previous = response.to_owned();
477
478 assert_eq!(response.to_string(), msg);
479
480 let with_previous = response.with_previous(previous);
481
482 let from_str_msg =
483 super::MappedErrors::from_str_msg(with_previous.msg());
484
485 assert_eq!(with_previous.msg(), from_str_msg.msg());
486 }
487
488 #[test]
489 fn test_has_str_code() {
490 fn error_dispatcher() -> Result<(), super::MappedErrors> {
491 Err(super::MappedErrors::new(
492 "This is a test error".to_string(),
493 Some(true),
494 None,
495 super::ErrorType::UndefinedError,
496 ))
497 }
498
499 fn error_handler() -> Result<(), super::MappedErrors> {
500 error_dispatcher()?;
501 Ok(())
502 }
503
504 let response = error_handler().unwrap_err();
505
506 assert!(!response.has_str_code("none"));
507 }
508
509 #[test]
510 fn test_is_in() {
511 fn error_dispatcher(
512 codes: Option<Vec<String>>,
513 ) -> Result<(), super::MappedErrors> {
514 if codes.is_some() {
515 let mut errors = super::MappedErrors::new(
516 "This is a test error".to_string(),
517 Some(true),
518 None,
519 super::ErrorType::UndefinedError,
520 );
521
522 for code in codes.unwrap() {
523 errors = errors.with_code(code.as_str());
524 }
525
526 return Err(errors);
527 }
528
529 Err(super::MappedErrors::new(
530 "This is a test error".to_string(),
531 Some(true),
532 None,
533 super::ErrorType::UndefinedError,
534 ))
535 }
536
537 fn error_handler(
538 codes: Option<Vec<String>>,
539 ) -> Result<(), super::MappedErrors> {
540 error_dispatcher(codes)?;
541 Ok(())
542 }
543
544 let none_response = error_handler(None).unwrap_err();
545 let some_response = error_handler(Some(vec![
546 "ID00001".to_string(),
547 "ID00005".to_string(),
548 ]))
549 .unwrap_err();
550
551 assert!(!none_response.is_in(vec!["none", "ID00001"]));
552 assert!(!some_response.is_in(vec!["none", "ID00002"]));
553 assert!(!some_response.is_in(vec!["ID00002", "ID00003"]));
554 assert!(some_response.is_in(vec!["none", "ID00001"]));
555 }
556}