#[cfg(feature = "crud")]
use crate::ro::ro_code::RO_CODE_WARNING_DELETE_VIOLATE_CONSTRAINT;
use crate::ro::Ro;
use crate::svc::svc_error::SvcError;
use actix_web::http::StatusCode;
use actix_web::{HttpResponse, ResponseError};
use log::error;
#[cfg(feature = "crud")]
use sea_orm::DbErr;
use thiserror::Error;
use validator;
#[derive(Debug, Error)]
pub enum CtrlError {
#[error("参数校验错误: {0}")]
ValidationError(#[from] validator::ValidationError),
#[error("参数校验错误: {0}")]
ValidationErrors(#[from] validator::ValidationErrors),
#[error("IO错误: {0}")]
IoError(#[from] std::io::Error),
#[error("服务层错误")]
SvcError(#[from] SvcError),
}
impl CtrlError {
fn to_ro(&self) -> Ro<()> {
match self {
CtrlError::ValidationError(error) => {
Ro::illegal_argument(format!("参数校验错误: {}", error.code))
}
CtrlError::ValidationErrors(errors) => {
Ro::illegal_argument(format!("参数校验错误: {}", errors))
}
CtrlError::IoError(error) => {
Ro::fail("磁盘异常".to_string()).detail(Some(error.to_string()))
}
CtrlError::SvcError(error) => match error {
SvcError::NotFound(err) => {
Ro::warn("找不到数据".to_string()).detail(Some(err.to_string()))
}
#[cfg(feature = "crud")]
SvcError::DuplicateKey(field_name, field_value) => {
Ro::warn(format!("{}<{}>已存在!", field_name, field_value))
}
#[cfg(feature = "crud")]
SvcError::DeleteViolateConstraint(pk_table, foreign_key, fk_table) => {
Ro::warn("删除失败,有其它数据依赖于本数据".to_string())
.code(Some(RO_CODE_WARNING_DELETE_VIOLATE_CONSTRAINT.to_string()))
.detail(Some(format!(
"{} <- {} <- {}>",
pk_table, foreign_key, fk_table
)))
}
#[cfg(feature = "crud")]
SvcError::DatabaseError(db_err) => match db_err {
DbErr::RecordNotUpdated => {
Ro::warn("未更新数据,请检查记录是否存在".to_string())
}
_ => Ro::fail("数据库错误".to_string()).detail(Some(db_err.to_string())),
},
_ => Ro::fail(error.to_string()),
},
}
}
}
impl ResponseError for CtrlError {
fn status_code(&self) -> StatusCode {
match self {
CtrlError::ValidationError(_) | CtrlError::ValidationErrors(_) => {
StatusCode::BAD_REQUEST
}
CtrlError::IoError(_) => StatusCode::INTERNAL_SERVER_ERROR,
CtrlError::SvcError(error) => match error {
SvcError::NotFound(_) => StatusCode::NOT_FOUND,
#[cfg(feature = "crud")]
SvcError::DuplicateKey(_, _) | SvcError::DeleteViolateConstraint(_, _, _) => {
StatusCode::OK
}
_ => StatusCode::INTERNAL_SERVER_ERROR,
},
}
}
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status_code()).json(self.to_ro())
}
}