Skip to main content

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