use std::fmt;
#[derive(Debug)]
pub enum SqliteError {
OpenFailed(String),
DatabaseClosed,
MigrationFailed(String),
QueryFailed(String),
TransactionFailed(String),
TypeConversion(String),
InvalidParameter(String),
TableNotFound(String),
ConstraintViolation(String),
IoError(String),
SerdeError(String),
Internal(String),
}
impl fmt::Display for SqliteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OpenFailed(msg) => write!(f, "数据库打开失败: {}", msg),
Self::DatabaseClosed => write!(f, "数据库已关闭"),
Self::MigrationFailed(msg) => write!(f, "迁移失败: {}", msg),
Self::QueryFailed(msg) => write!(f, "查询失败: {}", msg),
Self::TransactionFailed(msg) => write!(f, "事务失败: {}", msg),
Self::TypeConversion(msg) => write!(f, "类型转换失败: {}", msg),
Self::InvalidParameter(msg) => write!(f, "参数错误: {}", msg),
Self::TableNotFound(table) => write!(f, "表不存在: {}", table),
Self::ConstraintViolation(msg) => write!(f, "约束违反: {}", msg),
Self::IoError(msg) => write!(f, "IO 错误: {}", msg),
Self::SerdeError(msg) => write!(f, "序列化错误: {}", msg),
Self::Internal(msg) => write!(f, "内部错误: {}", msg),
}
}
}
impl std::error::Error for SqliteError {}
impl From<std::io::Error> for SqliteError {
fn from(err: std::io::Error) -> Self {
Self::IoError(err.to_string())
}
}
impl From<serde_json::Error> for SqliteError {
fn from(err: serde_json::Error) -> Self {
Self::SerdeError(err.to_string())
}
}
impl From<rusqlite::Error> for SqliteError {
fn from(err: rusqlite::Error) -> Self {
use rusqlite::Error;
match &err {
Error::SqliteFailure(e, msg) => {
let detail = msg.as_deref().unwrap_or("unknown");
if e.extended_code == 2067 || e.extended_code == 1555 {
Self::ConstraintViolation(detail.to_string())
} else if e.extended_code == 787 {
Self::ConstraintViolation(format!("外键约束: {}", detail))
} else {
Self::QueryFailed(format!("{:?}: {}", e.code, detail))
}
}
Error::QueryReturnedNoRows => Self::QueryFailed("查询无结果".to_string()),
Error::InvalidColumnType(idx, name, _) => {
Self::TypeConversion(format!("列 {}({}) 类型不匹配", name, idx))
}
_ => Self::QueryFailed(err.to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = SqliteError::OpenFailed("permission denied".into());
assert!(err.to_string().contains("数据库打开失败"));
let err = SqliteError::TableNotFound("users".into());
assert!(err.to_string().contains("users"));
}
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let sqlite_err: SqliteError = io_err.into();
assert!(matches!(sqlite_err, SqliteError::IoError(_)));
}
}