use crate::entity::{DeleteParam, ListQuery, PageQuery, QueryOption};
use crate::error::{CoolError, CoolResponse, CoolResult};
use crate::service::BaseService;
use salvo::prelude::*;
use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CrudApi {
Add,
Delete,
Update,
Page,
Info,
List,
}
impl CrudApi {
pub fn all() -> Vec<Self> {
vec![
Self::Add,
Self::Delete,
Self::Update,
Self::Page,
Self::Info,
Self::List,
]
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Add => "add",
Self::Delete => "delete",
Self::Update => "update",
Self::Page => "page",
Self::Info => "info",
Self::List => "list",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ControllerOption {
pub prefix: Option<String>,
pub api: Vec<CrudApi>,
pub page_query_op: QueryOption,
pub list_query_op: QueryOption,
pub info_ignore_property: Vec<String>,
}
#[async_trait]
pub trait BaseController: Send + Sync + 'static {
fn option(&self) -> &ControllerOption;
fn table_name(&self) -> &str;
fn db(&self) -> &sea_orm::DatabaseConnection;
}
#[allow(dead_code)]
pub struct CrudHandler {
table: String,
db: std::sync::Arc<sea_orm::DatabaseConnection>,
}
impl CrudHandler {
pub fn new(table: impl Into<String>, db: std::sync::Arc<sea_orm::DatabaseConnection>) -> Self {
Self {
table: table.into(),
db,
}
}
}
fn get_crud_service(depot: &Depot) -> CoolResult<&dyn BaseService> {
if let Ok(svc) = depot.get::<&'static dyn BaseService>("crud_service") {
Ok(*svc)
} else {
Err(CoolError::comm(
"未找到 CRUD 服务实例,请先在 Depot 中注册 `crud_service`",
))
}
}
#[handler]
pub async fn handle_add(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let body: Value = match req.parse_json().await {
Ok(v) => v,
Err(e) => {
res.render(Json(CoolResponse::<()>::fail(e.to_string())));
return;
}
};
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
match service.add(body).await {
Ok(result) => res.render(Json(CoolResponse::ok(result))),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
#[handler]
pub async fn handle_delete(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let param: DeleteParam = match req.parse_json().await {
Ok(v) => v,
Err(e) => {
res.render(Json(CoolResponse::<()>::fail(e.to_string())));
return;
}
};
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
match service.delete(param).await {
Ok(_) => res.render(Json(CoolResponse::<()>::ok_empty())),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
#[handler]
pub async fn handle_update(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let body: Value = match req.parse_json().await {
Ok(v) => v,
Err(e) => {
res.render(Json(CoolResponse::<()>::fail(e.to_string())));
return;
}
};
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
match service.update(body).await {
Ok(_) => res.render(Json(CoolResponse::<()>::ok_empty())),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
#[handler]
pub async fn handle_page(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let query: PageQuery = req.parse_queries().unwrap_or_default();
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
let option = QueryOption::default();
match service.page(query, option).await {
Ok(result) => res.render(Json(CoolResponse::ok(result))),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
#[handler]
pub async fn handle_info(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let id: Option<i64> = req.query("id").and_then(|s: &str| s.parse::<i64>().ok());
let id = match id {
Some(id) => id,
None => {
res.render(Json(CoolResponse::<()>::fail("缺少 id 参数")));
return;
}
};
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
match service.info(id, None).await {
Ok(data) => res.render(Json(CoolResponse::ok(data))),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
#[handler]
pub async fn handle_list(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let query: ListQuery = req.parse_queries().unwrap_or_default();
let service = match get_crud_service(depot) {
Ok(s) => s,
Err(e) => {
res.render(Json(CoolResponse::<()>::from_error(&e)));
return;
}
};
let option = QueryOption::default();
match service.list(query, option).await {
Ok(result) => res.render(Json(CoolResponse::ok(result))),
Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
}
}
pub fn build_crud_router(prefix: &str, apis: &[CrudApi]) -> Router {
let mut router = Router::with_path(prefix);
for api in apis {
match api {
CrudApi::Add => {
router = router.push(Router::with_path("add").post(handle_add));
}
CrudApi::Delete => {
router = router.push(Router::with_path("delete").post(handle_delete));
}
CrudApi::Update => {
router = router.push(Router::with_path("update").post(handle_update));
}
CrudApi::Page => {
router = router.push(Router::with_path("page").post(handle_page));
}
CrudApi::Info => {
router = router.push(Router::with_path("info").get(handle_info));
}
CrudApi::List => {
router = router.push(Router::with_path("list").post(handle_list));
}
}
}
router
}