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
32#[allow(clippy::should_implement_trait)]
33impl XuguDatabaseError {
34 pub fn from_str(err: &str) -> Self {
35 let mut code_range: Range<usize> = 0..0;
36 let mut message_range = 0..err.len();
37 if err.starts_with("[E") {
38 if let Some(pos) = err.find(']') {
39 code_range = 1..pos;
40 message_range = pos + 1..err.len();
41 }
42 }
43
44 XuguDatabaseError {
45 code: err[code_range].into(),
46 message: err[message_range].trim().into(),
47 }
48 }
49
50 fn get_err_code(code: &str) -> i32 {
51 let cleaned = code.trim_matches(|c| c == '[' || c == ']');
53
54 if let Some(e_pos) = cleaned.find('E') {
56 let after_e = &cleaned[e_pos + 1..];
57
58 if let Some(l_pos) = after_e.find('L') {
60 let numeric_part = &after_e[..l_pos];
62 numeric_part.parse().unwrap_or(0)
63 } else {
64 after_e.parse().unwrap_or(0)
66 }
67 } else {
68 cleaned.parse().unwrap_or(0)
70 }
71 }
72}
73
74impl StdError for XuguDatabaseError {}
75
76impl DatabaseError for XuguDatabaseError {
77 #[inline]
78 fn message(&self) -> &str {
79 self.message.as_str()
80 }
81
82 #[inline]
83 fn code(&self) -> Option<Cow<'_, str>> {
84 Some(Cow::from(&self.code))
85 }
86
87 #[doc(hidden)]
88 fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
89 self
90 }
91
92 #[doc(hidden)]
93 fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
94 self
95 }
96
97 #[doc(hidden)]
98 fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static> {
99 self
100 }
101
102 fn kind(&self) -> ErrorKind {
103 let err_code = Self::get_err_code(&self.code);
104 match err_code {
105 13001 => ErrorKind::UniqueViolation,
107 13005 => ErrorKind::ForeignKeyViolation,
109 13009 => ErrorKind::NotNullViolation,
111 13004 | 13008 => ErrorKind::CheckViolation,
114 _ => ErrorKind::Other,
115 }
116 }
117}