sqlx_xugu/
error.rs

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        // 去除可能的方括号
51        let cleaned = code.trim_matches(|c| c == '[' || c == ']');
52
53        // 查找 E 的位置
54        if let Some(e_pos) = cleaned.find('E') {
55            let after_e = &cleaned[e_pos + 1..];
56
57            // 检查是否有 L
58            if let Some(l_pos) = after_e.find('L') {
59                // 有 L 的情况:提取 E 和 L 之间的数字
60                let numeric_part = &after_e[..l_pos];
61                numeric_part.parse().unwrap_or(0)
62            } else {
63                // 没有 L 的情况:提取 E 之后的所有数字
64                after_e.parse().unwrap_or(0)
65            }
66        } else {
67            // 没有找到 E,尝试直接解析整个字符串为数字
68            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            // E13001:违反唯一值约束
105            13001 => ErrorKind::UniqueViolation,
106            // E13005:违反外键约束
107            13005 => ErrorKind::ForeignKeyViolation,
108            // E13009:非空约束作用字段为主键或唯一值字段,故不允许删除
109            13009 => ErrorKind::NotNullViolation,
110            // E13004:违反约束
111            // E13008:违反值检查约束
112            13004 | 13008 => ErrorKind::CheckViolation,
113            _ => ErrorKind::Other,
114        }
115    }
116}