1use std::error::Error as StdError;
2use std::fmt::{self, Debug, Display, Formatter};
3
4pub(crate) use sqlx_core::error::*;
5use std::borrow::Cow;
6use std::ops::Range;
7
8pub struct XuguDatabaseError {
9 code: String,
10 message: String,
11}
12
13impl Debug for XuguDatabaseError {
14 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
15 f.debug_struct("XuguDatabaseError")
16 .field("code", &self.code)
17 .field("message", &self.message)
18 .finish()
19 }
20}
21
22impl Display for XuguDatabaseError {
23 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
24 if let Some(code) = &self.code() {
25 write!(f, "({}): {}", code, self.message())
26 } else {
27 write!(f, "{}", self.message())
28 }
29 }
30}
31
32impl XuguDatabaseError {
33 pub fn from_str(err: &str) -> Self {
34 let mut code_range: Range<usize> = 0..0;
35 let mut message_range = 0..err.len();
36 if err.starts_with("[E") {
37 if let Some(pos) = err.find(']') {
38 code_range = 1..pos;
39 message_range = pos + 1..err.len();
40 }
41 }
42
43 XuguDatabaseError {
44 code: err[code_range].into(),
45 message: err[message_range].trim().into(),
46 }
47 }
48
49 fn get_err_code(code: &str) -> i32 {
50 let cleaned = code.trim_matches(|c| c == '[' || c == ']');
52
53 if let Some(e_pos) = cleaned.find('E') {
55 let after_e = &cleaned[e_pos + 1..];
56
57 if let Some(l_pos) = after_e.find('L') {
59 let numeric_part = &after_e[..l_pos];
61 numeric_part.parse().unwrap_or(0)
62 } else {
63 after_e.parse().unwrap_or(0)
65 }
66 } else {
67 cleaned.parse().unwrap_or(0)
69 }
70 }
71}
72
73impl StdError for XuguDatabaseError {}
74
75impl DatabaseError for XuguDatabaseError {
76 #[inline]
77 fn message(&self) -> &str {
78 self.message.as_str()
79 }
80
81 #[inline]
82 fn code(&self) -> Option<Cow<'_, str>> {
83 Some(Cow::from(&self.code))
84 }
85
86 #[doc(hidden)]
87 fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
88 self
89 }
90
91 #[doc(hidden)]
92 fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
93 self
94 }
95
96 #[doc(hidden)]
97 fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static> {
98 self
99 }
100
101 fn kind(&self) -> ErrorKind {
102 let err_code = Self::get_err_code(&self.code);
103 match err_code {
104 13001 => ErrorKind::UniqueViolation,
106 13005 => ErrorKind::ForeignKeyViolation,
108 13009 => ErrorKind::NotNullViolation,
110 13004 | 13008 => ErrorKind::CheckViolation,
113 _ => ErrorKind::Other,
114 }
115 }
116}