Skip to main content

yang_db/
error.rs

1/// 数据库错误类型
2#[derive(Debug, thiserror::Error)]
3pub enum DbError {
4    #[error("连接错误: {0}")]
5    ConnectionError(String),
6
7    #[error("查询错误: {0}")]
8    QueryError(String),
9
10    #[error("SQL 语法错误: {0}")]
11    SqlSyntaxError(String),
12
13    #[error("约束错误: {0}")]
14    ConstraintError(String),
15
16    #[error("类型转换错误: {0}")]
17    TypeConversionError(String),
18
19    #[error("序列化错误: {0}")]
20    SerializationError(String),
21
22    #[error("反序列化错误: {0}")]
23    DeserializationError(String),
24
25    #[error("事务错误: {0}")]
26    TransactionError(String),
27
28    #[error("表不存在: {0}")]
29    TableNotFound(String),
30
31    #[error("缺少 WHERE 条件,禁止全表操作")]
32    MissingWhereClause,
33
34    #[error("未知错误: {0}")]
35    Unknown(String),
36}
37
38/// 从 sqlx::Error 转换为 DbError
39impl From<sqlx::Error> for DbError {
40    fn from(err: sqlx::Error) -> Self {
41        match err {
42            sqlx::Error::Configuration(_) => DbError::ConnectionError(format!("配置错误: {}", err)),
43            sqlx::Error::Database(db_err) => {
44                let code = db_err.code().unwrap_or_default();
45                let message = db_err.message();
46
47                // MySQL 错误码映射
48                match code.as_ref() {
49                    "23000" => DbError::ConstraintError(message.to_string()),
50                    "42S02" => DbError::TableNotFound(message.to_string()),
51                    "42000" => DbError::SqlSyntaxError(message.to_string()),
52                    _ => DbError::QueryError(format!("数据库错误 [{}]: {}", code, message)),
53                }
54            }
55            sqlx::Error::Io(_) => DbError::ConnectionError(format!("IO 错误: {}", err)),
56            sqlx::Error::Tls(_) => DbError::ConnectionError(format!("TLS 错误: {}", err)),
57            sqlx::Error::Protocol(_) => DbError::QueryError(format!("协议错误: {}", err)),
58            sqlx::Error::RowNotFound => DbError::QueryError("未找到记录".to_string()),
59            sqlx::Error::TypeNotFound { type_name } => {
60                DbError::TypeConversionError(format!("类型未找到: {}", type_name))
61            }
62            sqlx::Error::ColumnIndexOutOfBounds { index, len } => {
63                DbError::QueryError(format!("列索引越界: {} (总列数: {})", index, len))
64            }
65            sqlx::Error::ColumnNotFound(col) => DbError::QueryError(format!("列不存在: {}", col)),
66            sqlx::Error::ColumnDecode { index, source } => {
67                DbError::TypeConversionError(format!("列 {} 解码失败: {}", index, source))
68            }
69            sqlx::Error::Decode(source) => {
70                DbError::DeserializationError(format!("解码失败: {}", source))
71            }
72            sqlx::Error::PoolTimedOut => DbError::ConnectionError("连接池超时".to_string()),
73            sqlx::Error::PoolClosed => DbError::ConnectionError("连接池已关闭".to_string()),
74            sqlx::Error::WorkerCrashed => DbError::ConnectionError("工作线程崩溃".to_string()),
75            _ => DbError::Unknown(format!("未知错误: {}", err)),
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_error_display_chinese() {
86        // 测试所有错误类型的中文消息
87        let errors = vec![
88            DbError::ConnectionError("测试".to_string()),
89            DbError::QueryError("测试".to_string()),
90            DbError::SqlSyntaxError("测试".to_string()),
91            DbError::ConstraintError("测试".to_string()),
92            DbError::TypeConversionError("测试".to_string()),
93            DbError::SerializationError("测试".to_string()),
94            DbError::DeserializationError("测试".to_string()),
95            DbError::TransactionError("测试".to_string()),
96            DbError::TableNotFound("测试".to_string()),
97            DbError::MissingWhereClause,
98            DbError::Unknown("测试".to_string()),
99        ];
100
101        for error in errors {
102            let msg = format!("{}", error);
103            // 验证错误消息包含中文字符
104            let has_chinese = msg.chars().any(|c| matches!(c, '\u{4e00}'..='\u{9fff}'));
105            assert!(has_chinese, "错误消息应该包含中文: {}", msg);
106        }
107    }
108
109    #[test]
110    fn test_connection_error() {
111        let err = DbError::ConnectionError("无法连接到数据库".to_string());
112        assert_eq!(format!("{}", err), "连接错误: 无法连接到数据库");
113    }
114
115    #[test]
116    fn test_query_error() {
117        let err = DbError::QueryError("查询超时".to_string());
118        assert_eq!(format!("{}", err), "查询错误: 查询超时");
119    }
120
121    #[test]
122    fn test_sql_syntax_error() {
123        let err = DbError::SqlSyntaxError("语法错误".to_string());
124        assert_eq!(format!("{}", err), "SQL 语法错误: 语法错误");
125    }
126
127    #[test]
128    fn test_constraint_error() {
129        let err = DbError::ConstraintError("主键冲突".to_string());
130        assert_eq!(format!("{}", err), "约束错误: 主键冲突");
131    }
132
133    #[test]
134    fn test_type_conversion_error() {
135        let err = DbError::TypeConversionError("无法转换类型".to_string());
136        assert_eq!(format!("{}", err), "类型转换错误: 无法转换类型");
137    }
138
139    #[test]
140    fn test_serialization_error() {
141        let err = DbError::SerializationError("序列化失败".to_string());
142        assert_eq!(format!("{}", err), "序列化错误: 序列化失败");
143    }
144
145    #[test]
146    fn test_deserialization_error() {
147        let err = DbError::DeserializationError("反序列化失败".to_string());
148        assert_eq!(format!("{}", err), "反序列化错误: 反序列化失败");
149    }
150
151    #[test]
152    fn test_transaction_error() {
153        let err = DbError::TransactionError("事务已提交".to_string());
154        assert_eq!(format!("{}", err), "事务错误: 事务已提交");
155    }
156
157    #[test]
158    fn test_table_not_found() {
159        let err = DbError::TableNotFound("users".to_string());
160        assert_eq!(format!("{}", err), "表不存在: users");
161    }
162
163    #[test]
164    fn test_missing_where_clause() {
165        let err = DbError::MissingWhereClause;
166        assert_eq!(format!("{}", err), "缺少 WHERE 条件,禁止全表操作");
167    }
168
169    #[test]
170    fn test_unknown_error() {
171        let err = DbError::Unknown("未知问题".to_string());
172        assert_eq!(format!("{}", err), "未知错误: 未知问题");
173    }
174
175    #[test]
176    fn test_error_implements_std_error() {
177        // 验证 DbError 实现了 std::error::Error trait
178        let err = DbError::QueryError("测试".to_string());
179        let _: &dyn std::error::Error = &err;
180    }
181}