use crate::dao::DaoError;
#[cfg(feature = "db")]
use crate::ro::RO_CODE_WARNING_DELETE_VIOLATE_FK;
use crate::ro::{Ro, RO_CODE_WARNING_DUPLICATE_KEY, RO_CODE_WARNING_INSERT_VIOLATE_FK};
use crate::svc::SvcError;
use axum::http::header::InvalidHeaderValue;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use log::warn;
#[cfg(feature = "db")]
use sea_orm::DbErr;
use thiserror::Error;
use validator;
#[derive(Debug, Error)]
pub enum CtrlError {
#[error("{0}")]
Runtime(#[from] anyhow::Error),
#[error("参数校验错误 -> {0}")]
Validation(#[from] validator::ValidationError),
#[error("参数校验错误 -> {0}")]
Validations(#[from] validator::ValidationErrors),
#[error("IO错误: {0}")]
Io(#[from] std::io::Error),
#[error("Header值错误: {0}")]
InvalidHeaderValue(#[from] InvalidHeaderValue),
#[error("服务层错误, {0}")]
Svc(#[from] SvcError),
}
impl CtrlError {
fn to_ro(&self) -> Ro<()> {
match self {
CtrlError::Runtime(error) => {
warn!("{}", error);
Ro::warn("运行时错误".to_string()).detail(Some(error.to_string()))
}
CtrlError::Validation(error) => {
Ro::illegal_argument(format!("参数校验错误 -> {}", error.to_string()))
}
CtrlError::Validations(errors) => {
Ro::illegal_argument(format!("参数校验错误 -> {}", errors))
}
CtrlError::InvalidHeaderValue(error) => {
Ro::illegal_argument("Header值错误".to_string()).detail(Some(error.to_string()))
}
CtrlError::Io(error) => {
Ro::fail("磁盘异常".to_string()).detail(Some(error.to_string()))
}
CtrlError::Svc(error) => match error {
SvcError::Validation(error) => {
Ro::illegal_argument(format!("参数校验错误 -> {}", error.to_string()))
}
SvcError::Validations(errors) => {
Ro::illegal_argument(format!("参数校验错误 -> {}", errors))
}
SvcError::NotFound(err) => {
Ro::warn("找不到数据".to_string()).detail(Some(err.to_string()))
}
#[cfg(feature = "db")]
SvcError::Dao(error) => match error {
DaoError::DuplicateKey(unique_key, value) => Ro::warn(format!(
"{}<{}>已存在!",
unique_key.key_remark, value
))
.code(Some(RO_CODE_WARNING_DUPLICATE_KEY.to_string()))
.detail(Some(format!("{unique_key} -> value: {value}"))),
DaoError::InsertViolateFk(foreign_key) => Ro::warn(format!(
"不能插入(或更新){},设置的{}并不存在",
foreign_key.fk_table_comment, foreign_key.pk_table_comment
))
.code(Some(RO_CODE_WARNING_INSERT_VIOLATE_FK.to_string()))
.detail(Some(foreign_key.to_string())),
DaoError::DeleteViolateFk(foreign_key) => Ro::warn(format!(
"不能删除(或更新){},存在关联其的{}",
foreign_key.pk_table_comment, foreign_key.fk_table_comment
))
.code(Some(RO_CODE_WARNING_DELETE_VIOLATE_FK.to_string()))
.detail(Some(foreign_key.to_string())),
DaoError::Db(db_err) => match db_err {
DbErr::RecordNotUpdated => {
Ro::warn("未更新数据,请检查记录是否存在".to_string())
}
_ => Ro::fail("数据库错误".to_string()).detail(Some(db_err.to_string())),
},
_ => Ro::fail("数据访问层错误".to_string()).detail(Some(error.to_string())),
},
_ => Ro::fail(error.to_string()),
},
}
}
}
impl IntoResponse for CtrlError {
fn into_response(self) -> Response {
warn!("控制器层捕获错误: {}", self);
let status = match &self {
CtrlError::Runtime(_) => StatusCode::INTERNAL_SERVER_ERROR,
CtrlError::Validation(_)
| CtrlError::Validations(_)
| CtrlError::InvalidHeaderValue(_) => StatusCode::BAD_REQUEST,
CtrlError::Io(_) => StatusCode::INTERNAL_SERVER_ERROR,
CtrlError::Svc(error) => match error {
SvcError::NotFound(_) => StatusCode::NOT_FOUND,
SvcError::Validation(_)
| SvcError::Validations(_)
| SvcError::MultipartError(_) => StatusCode::BAD_REQUEST,
#[cfg(feature = "db")]
SvcError::Dao(error) => match error {
DaoError::DuplicateKey(_, _)
| DaoError::InsertViolateFk(_)
| DaoError::DeleteViolateFk(_) => StatusCode::OK,
_ => StatusCode::INTERNAL_SERVER_ERROR,
},
_ => StatusCode::INTERNAL_SERVER_ERROR,
},
};
(status, Json(&self.to_ro())).into_response()
}
}