#[cfg(feature = "crud")]
use crate::svc::svc_error::SvcError::{DeleteViolateConstraint, DuplicateKey};
use log::error;
#[cfg(feature = "crud")]
use once_cell::sync::Lazy;
#[cfg(feature = "crud")]
use regex::{Captures, Regex};
#[cfg(feature = "crud")]
use sea_orm::DbErr;
#[cfg(feature = "crud")]
use std::collections::HashMap;
use std::error;
use std::io::Error;
use thiserror::Error;
#[cfg(feature = "crud")]
static REGEX_DUPLICATE_KEY_POSTGRES: Lazy<Regex> = Lazy::new(|| {
Regex::new(r#"Key \((?P<column>[^)]+)\)=\((?P<value>[^)]*)\) already exists\."#).unwrap()
});
#[cfg(feature = "crud")]
static REGEX_DUPLICATE_KEY_MYSQL: Lazy<Regex> = Lazy::new(|| {
Regex::new(r#"Duplicate entry '(?P<value>[^']+)' for key '(?P<column>[^']*)'$"#).unwrap()
});
#[cfg(feature = "crud")]
static REGEX_DELETE_VIOLATE_CONSTRAINT_POSTGRES: Lazy<Regex> = Lazy::new(|| {
Regex::new(r#"update or delete on table \\"(?P<pk_table>[^"]+)\\" violates foreign key constraint \\"(?P<foreign_key>[^"]+)\\" on table \\"(?P<fk_table>[^"]+)\\""#).unwrap()
});
#[derive(Debug, Error)]
pub enum SvcError {
#[error("参数校验错误: {0}")]
ValidationError(#[from] validator::ValidationError),
#[error("参数校验错误: {0}")]
ValidationErrors(#[from] validator::ValidationErrors),
#[error("运行时错误: {0}")]
RuntimeError(String),
#[error("运行时错误: {0}")]
RuntimeXError(#[from] Box<dyn error::Error + Send + Sync>),
#[error("找不到数据: {0}")]
NotFound(String),
#[error("IO错误: {0}")]
IoError(#[from] Error),
#[cfg(feature = "crud")]
#[error("重复键错误: {0} {1}")]
DuplicateKey(String, String),
#[cfg(feature = "crud")]
#[error("删除操作违反了数据库约束条件: {0} {1} {2}")]
DeleteViolateConstraint(String, String, String),
#[cfg(feature = "crud")]
#[error("数据库错误: {0}")]
DatabaseError(#[from] DbErr),
}
#[cfg(feature = "crud")]
pub fn handle_db_err_to_svc_error(
db_err: DbErr,
unique_field_hashmap: &Lazy<HashMap<&'static str, &'static str>>,
) -> SvcError {
error!("数据库错误: {}", db_err);
let db_err_string = format!("{:?}", db_err);
if let Some(caps) = REGEX_DUPLICATE_KEY_POSTGRES.captures(&db_err_string) {
return to_duplicate_key(caps, unique_field_hashmap);
} else if let Some(caps) = REGEX_DUPLICATE_KEY_MYSQL.captures(&db_err_string) {
return to_duplicate_key(caps, unique_field_hashmap);
} else if let Some(caps) = REGEX_DELETE_VIOLATE_CONSTRAINT_POSTGRES.captures(&db_err_string) {
let pk_table = caps["pk_table"].to_string();
let foreign_key = caps["foreign_key"].to_string();
let fk_table = caps["fk_table"].to_string();
return DeleteViolateConstraint(pk_table, foreign_key, fk_table);
}
SvcError::DatabaseError(db_err)
}
#[cfg(feature = "crud")]
fn to_duplicate_key(
caps: Captures,
unique_field_hashmap: &Lazy<HashMap<&'static str, &'static str>>,
) -> SvcError {
let column_name = caps["column"].to_string();
let value = caps["value"].to_string();
let name = unique_field_hashmap
.get(column_name.as_str())
.unwrap()
.to_string();
DuplicateKey(name, value)
}