cool_core/controller/
mod.rs1use crate::entity::{DeleteParam, ListQuery, PageQuery, QueryOption};
6use crate::error::{CoolError, CoolResponse, CoolResult};
7use crate::service::BaseService;
8use salvo::prelude::*;
9use serde_json::Value;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum CrudApi {
14 Add,
15 Delete,
16 Update,
17 Page,
18 Info,
19 List,
20}
21
22impl CrudApi {
23 pub fn all() -> Vec<Self> {
24 vec![
25 Self::Add,
26 Self::Delete,
27 Self::Update,
28 Self::Page,
29 Self::Info,
30 Self::List,
31 ]
32 }
33
34 pub fn as_str(&self) -> &'static str {
35 match self {
36 Self::Add => "add",
37 Self::Delete => "delete",
38 Self::Update => "update",
39 Self::Page => "page",
40 Self::Info => "info",
41 Self::List => "list",
42 }
43 }
44}
45
46#[derive(Debug, Clone, Default)]
48pub struct ControllerOption {
49 pub prefix: Option<String>,
51 pub api: Vec<CrudApi>,
53 pub page_query_op: QueryOption,
55 pub list_query_op: QueryOption,
57 pub info_ignore_property: Vec<String>,
59}
60
61#[async_trait]
65pub trait BaseController: Send + Sync + 'static {
66 fn option(&self) -> &ControllerOption;
68
69 fn table_name(&self) -> &str;
71
72 fn db(&self) -> &sea_orm::DatabaseConnection;
74}
75
76#[allow(dead_code)]
80pub struct CrudHandler {
81 table: String,
82 db: std::sync::Arc<sea_orm::DatabaseConnection>,
83}
84
85impl CrudHandler {
86 pub fn new(table: impl Into<String>, db: std::sync::Arc<sea_orm::DatabaseConnection>) -> Self {
87 Self {
88 table: table.into(),
89 db,
90 }
91 }
92}
93
94fn get_crud_service(depot: &Depot) -> CoolResult<&dyn BaseService> {
96 if let Ok(svc) = depot.get::<&'static dyn BaseService>("crud_service") {
97 Ok(*svc)
98 } else {
99 Err(CoolError::comm(
100 "未找到 CRUD 服务实例,请先在 Depot 中注册 `crud_service`",
101 ))
102 }
103}
104
105#[handler]
107pub async fn handle_add(req: &mut Request, res: &mut Response, depot: &mut Depot) {
108 let body: Value = match req.parse_json().await {
109 Ok(v) => v,
110 Err(e) => {
111 res.render(Json(CoolResponse::<()>::fail(e.to_string())));
112 return;
113 }
114 };
115
116 let service = match get_crud_service(depot) {
117 Ok(s) => s,
118 Err(e) => {
119 res.render(Json(CoolResponse::<()>::from_error(&e)));
120 return;
121 }
122 };
123
124 match service.add(body).await {
125 Ok(result) => res.render(Json(CoolResponse::ok(result))),
126 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
127 }
128}
129
130#[handler]
132pub async fn handle_delete(req: &mut Request, res: &mut Response, depot: &mut Depot) {
133 let param: DeleteParam = match req.parse_json().await {
134 Ok(v) => v,
135 Err(e) => {
136 res.render(Json(CoolResponse::<()>::fail(e.to_string())));
137 return;
138 }
139 };
140
141 let service = match get_crud_service(depot) {
142 Ok(s) => s,
143 Err(e) => {
144 res.render(Json(CoolResponse::<()>::from_error(&e)));
145 return;
146 }
147 };
148
149 match service.delete(param).await {
150 Ok(_) => res.render(Json(CoolResponse::<()>::ok_empty())),
151 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
152 }
153}
154
155#[handler]
157pub async fn handle_update(req: &mut Request, res: &mut Response, depot: &mut Depot) {
158 let body: Value = match req.parse_json().await {
159 Ok(v) => v,
160 Err(e) => {
161 res.render(Json(CoolResponse::<()>::fail(e.to_string())));
162 return;
163 }
164 };
165
166 let service = match get_crud_service(depot) {
167 Ok(s) => s,
168 Err(e) => {
169 res.render(Json(CoolResponse::<()>::from_error(&e)));
170 return;
171 }
172 };
173
174 match service.update(body).await {
175 Ok(_) => res.render(Json(CoolResponse::<()>::ok_empty())),
176 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
177 }
178}
179
180#[handler]
182pub async fn handle_page(req: &mut Request, res: &mut Response, depot: &mut Depot) {
183 let query: PageQuery = req.parse_queries().unwrap_or_default();
184
185 let service = match get_crud_service(depot) {
186 Ok(s) => s,
187 Err(e) => {
188 res.render(Json(CoolResponse::<()>::from_error(&e)));
189 return;
190 }
191 };
192
193 let option = QueryOption::default();
195
196 match service.page(query, option).await {
197 Ok(result) => res.render(Json(CoolResponse::ok(result))),
198 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
199 }
200}
201
202#[handler]
204pub async fn handle_info(req: &mut Request, res: &mut Response, depot: &mut Depot) {
205 let id: Option<i64> = req.query("id").and_then(|s: &str| s.parse::<i64>().ok());
206
207 let id = match id {
208 Some(id) => id,
209 None => {
210 res.render(Json(CoolResponse::<()>::fail("缺少 id 参数")));
211 return;
212 }
213 };
214
215 let service = match get_crud_service(depot) {
216 Ok(s) => s,
217 Err(e) => {
218 res.render(Json(CoolResponse::<()>::from_error(&e)));
219 return;
220 }
221 };
222
223 match service.info(id, None).await {
225 Ok(data) => res.render(Json(CoolResponse::ok(data))),
226 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
227 }
228}
229
230#[handler]
232pub async fn handle_list(req: &mut Request, res: &mut Response, depot: &mut Depot) {
233 let query: ListQuery = req.parse_queries().unwrap_or_default();
234
235 let service = match get_crud_service(depot) {
236 Ok(s) => s,
237 Err(e) => {
238 res.render(Json(CoolResponse::<()>::from_error(&e)));
239 return;
240 }
241 };
242
243 let option = QueryOption::default();
245
246 match service.list(query, option).await {
247 Ok(result) => res.render(Json(CoolResponse::ok(result))),
248 Err(e) => res.render(Json(CoolResponse::<()>::from_error(&e))),
249 }
250}
251
252pub fn build_crud_router(prefix: &str, apis: &[CrudApi]) -> Router {
256 let mut router = Router::with_path(prefix);
257
258 for api in apis {
259 match api {
260 CrudApi::Add => {
261 router = router.push(Router::with_path("add").post(handle_add));
262 }
263 CrudApi::Delete => {
264 router = router.push(Router::with_path("delete").post(handle_delete));
265 }
266 CrudApi::Update => {
267 router = router.push(Router::with_path("update").post(handle_update));
268 }
269 CrudApi::Page => {
270 router = router.push(Router::with_path("page").post(handle_page));
271 }
272 CrudApi::Info => {
273 router = router.push(Router::with_path("info").get(handle_info));
274 }
275 CrudApi::List => {
276 router = router.push(Router::with_path("list").post(handle_list));
277 }
278 }
279 }
280
281 router
282}