1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use itertools::Itertools;
5use lazy_static::lazy_static;
6use serde::{Deserialize, Serialize};
7use tardis::basic::dto::TardisContext;
8use tardis::basic::result::TardisResult;
9use tardis::db::reldb_client::{IdResp, TardisActiveModel};
10use tardis::db::sea_orm::sea_query::{Alias, Cond, Expr, Func, IntoValueTuple, JoinType, Order, Query, SelectStatement, Value, ValueTuple};
11use tardis::db::sea_orm::{self, Condition, EntityTrait, FromQueryResult, QueryFilter};
12use tardis::regex::Regex;
13
14use tardis::web::poem_openapi;
15use tardis::web::poem_openapi::types::{ParseFromJSON, ToJSON};
16use tardis::web::web_resp::TardisPage;
17use tardis::TardisFunsInst;
18
19use crate::rbum::domain::rbum_item;
20use crate::rbum::dto::rbum_filer_dto::RbumBasicFilterReq;
21use crate::rbum::helper::{rbum_event_helper, rbum_scope_helper};
22#[cfg(feature = "with-mq")]
23use crate::rbum::rbum_config::RbumConfigApi;
24
25pub const ID_FIELD_NAME: &str = "id";
26
27lazy_static! {
28 pub static ref OWNER_TABLE: Alias = Alias::new("t_owner");
29 pub static ref ID_FIELD: Alias = Alias::new(ID_FIELD_NAME);
30 pub static ref OWNER_FIELD: Alias = Alias::new("owner");
31 pub static ref OWN_PATHS_FIELD: Alias = Alias::new("own_paths");
32 pub static ref CREATE_TIME_FIELD: Alias = Alias::new("create_time");
33 pub static ref UPDATE_TIME_FIELD: Alias = Alias::new("update_time");
34 pub static ref CODE_FIELD: Alias = Alias::new("code");
35 pub static ref NAME_FIELD: Alias = Alias::new("name");
36 pub static ref SORT_FIELD: Alias = Alias::new("sort");
37 pub static ref SCOPE_LEVEL_FIELD: Alias = Alias::new("scope_level");
38 pub static ref REL_KIND_ID_FIELD: Alias = Alias::new("rel_rbum_kind_id");
39 pub static ref REL_DOMAIN_ID_FIELD: Alias = Alias::new("rel_rbum_domain_id");
40 pub static ref DISABLED_FIELD: Alias = Alias::new("disabled");
41 pub static ref R_URL_PART_CODE: Regex = Regex::new(r"^[a-z0-9-.]+$").expect("Regular parsing error");
42}
43
44#[async_trait]
48pub trait RbumCrudOperation<E, AddReq, ModifyReq, SummaryResp, DetailResp, FilterReq>
49where
50 E: TardisActiveModel + Sync + Send,
51 AddReq: Sync + Send,
52 ModifyReq: Sync + Send,
53 SummaryResp: FromQueryResult + ParseFromJSON + ToJSON + Serialize + Send + Sync,
54 DetailResp: FromQueryResult + ParseFromJSON + ToJSON + Serialize + Send + Sync,
55 FilterReq: Sync + Send,
56{
57 fn get_table_name() -> &'static str;
61
62 fn get_obj_name() -> String {
70 Self::get_obj_name_from(Self::get_table_name())
71 }
72
73 fn get_obj_name_from(table_name: &str) -> String {
77 table_name.replace("rbum_", "")
78 }
79
80 async fn check_ownership(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
91 Self::check_ownership_with_table_name(id, Self::get_table_name(), funs, ctx).await
92 }
93
94 async fn check_ownership_with_table_name(id: &str, table_name: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
103 if funs.db().count(&Self::package_ownership_query_with_table_name(id, table_name, ctx)).await? == 0 {
104 return Err(funs.err().not_found(
105 &Self::get_obj_name_from(table_name),
106 "check",
107 &format!("ownership {}.{} is illegal by {}", Self::get_obj_name_from(table_name), id, ctx.owner),
108 "404-rbum-*-ownership-illegal",
109 ));
110 }
111 Ok(())
112 }
113
114 fn package_ownership_query(id: &str, ctx: &TardisContext) -> SelectStatement {
123 Self::package_ownership_query_with_table_name(id, Self::get_table_name(), ctx)
124 }
125
126 fn package_ownership_query_with_table_name(id: &str, table_name: &str, ctx: &TardisContext) -> SelectStatement {
133 let mut query = Query::select();
134 query
135 .column(ID_FIELD.clone())
136 .from(Alias::new(table_name))
137 .and_where(Expr::col(ID_FIELD.clone()).eq(id))
138 .and_where(Expr::col(OWN_PATHS_FIELD.clone()).like(format!("{}%", ctx.own_paths).as_str()));
139 query
140 }
141
142 async fn check_scope(id: &str, table_name: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
148 if funs
149 .db()
150 .count(
151 Query::select()
152 .column((Alias::new(table_name), ID_FIELD.clone()))
153 .from(Alias::new(table_name))
154 .and_where(Expr::col((Alias::new(table_name), ID_FIELD.clone())).eq(id))
155 .with_scope(table_name, &ctx.own_paths, false),
156 )
157 .await?
158 == 0
159 {
160 return Err(funs.err().not_found(
161 &Self::get_obj_name_from(table_name),
162 "check",
163 &format!("scope {}.{} is illegal by {}", Self::get_obj_name_from(table_name), id, ctx.owner),
164 "404-rbum-*-scope-illegal",
165 ));
166 }
167 Ok(())
168 }
169
170 async fn check_scopes(values: HashMap<String, &Vec<String>>, expect_number: u64, table_name: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
183 let mut query = Query::select();
184 let msg = values.iter().map(|(k, v)| format!("{k}={v:?}")).join(",");
185 query.column((Alias::new(table_name), ID_FIELD.clone())).from(Alias::new(table_name)).with_scope(table_name, &ctx.own_paths, false);
186 for (k, v) in values {
187 query.and_where(Expr::col((Alias::new(table_name), Alias::new(&k))).is_in(v.clone()));
188 }
189 if funs.db().count(&query).await? != expect_number {
190 return Err(funs.err().not_found(
191 &Self::get_obj_name_from(table_name),
192 "check",
193 &format!("scopes {}.{} is illegal by {}", Self::get_obj_name_from(table_name), msg, ctx.owner),
194 "404-rbum-*-scope-illegal",
195 ));
196 }
197 Ok(())
198 }
199
200 async fn check_exist_before_delete(id: &str, rel_table_name: &str, rel_field_name: &str, funs: &TardisFunsInst) -> TardisResult<()> {
207 if funs
208 .db()
209 .count(
210 Query::select()
211 .column((Alias::new(rel_table_name), ID_FIELD.clone()))
212 .from(Alias::new(rel_table_name))
213 .and_where(Expr::col((Alias::new(rel_table_name), Alias::new(rel_field_name))).eq(id)),
214 )
215 .await?
216 > 0
217 {
218 return Err(funs.err().conflict(
219 &Self::get_obj_name(),
220 "delete",
221 &format!(
222 "can not delete {}.{} when there are associated by {}.{}",
223 Self::get_obj_name(),
224 id,
225 Self::get_obj_name_from(rel_table_name),
226 rel_field_name
227 ),
228 "409-rbum-*-delete-conflict",
229 ));
230 }
231 Ok(())
232 }
233
234 async fn check_exist_with_cond_before_delete(rel_table_name: &str, condition: Condition, funs: &TardisFunsInst) -> TardisResult<()> {
238 if funs.db().count(Query::select().column((Alias::new(rel_table_name), ID_FIELD.clone())).from(Alias::new(rel_table_name)).cond_where(condition)).await? > 0 {
239 return Err(funs.err().conflict(
240 &Self::get_obj_name(),
241 "delete",
242 &format!(
243 "can not delete {} when there are associated by {}",
244 Self::get_obj_name(),
245 Self::get_obj_name_from(rel_table_name)
246 ),
247 "409-rbum-*-delete-conflict",
248 ));
249 }
250 Ok(())
251 }
252
253 async fn before_add_rbum(_: &mut AddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
259 Ok(())
260 }
261
262 async fn package_add(add_req: &AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<E>;
286
287 async fn after_add_rbum(_: &str, _: &AddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
291 Ok(())
292 }
293
294 async fn add_rbum(add_req: &mut AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
298 Self::before_add_rbum(add_req, funs, ctx).await?;
299 let domain = Self::package_add(add_req, funs, ctx).await?;
300 let insert_result = funs.db().insert_one(domain, ctx).await?;
301 let id_value = insert_result.last_insert_id.into_value_tuple();
302 let id = match id_value {
303 ValueTuple::One(v) => {
304 if let Value::String(s) = v {
305 s.map(|id| id.to_string())
306 } else {
307 None
308 }
309 }
310 _ => None,
311 };
312 if let Some(id) = id {
313 Self::after_add_rbum(&id, add_req, funs, ctx).await?;
314 rbum_event_helper::add_notify_event(Self::get_table_name(), "c", id.as_str(), ctx).await?;
315 Ok(id.to_string())
317 } else {
318 return Err(funs.err().internal_error(
319 &Self::get_obj_name(),
320 "add",
321 "id data type is invalid, currently only the string is supported",
322 "500-rbum-crud-id-type",
323 ));
324 }
325 }
326
327 async fn before_modify_rbum(id: &str, _: &mut ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
333 Self::check_ownership(id, funs, ctx).await
334 }
335
336 async fn package_modify(id: &str, modify_req: &ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<E>;
373
374 async fn after_modify_rbum(_: &str, _: &mut ModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
378 Ok(())
379 }
380
381 async fn modify_rbum(id: &str, modify_req: &mut ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
385 Self::before_modify_rbum(id, modify_req, funs, ctx).await?;
386 let domain = Self::package_modify(id, modify_req, funs, ctx).await?;
387 funs.db().update_one(domain, ctx).await?;
388 Self::after_modify_rbum(id, modify_req, funs, ctx).await?;
389 rbum_event_helper::add_notify_event(Self::get_table_name(), "u", id, ctx).await?;
390 Ok(())
391 }
392
393 async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<DetailResp>> {
399 Self::check_ownership(id, funs, ctx).await?;
400 Ok(None)
401 }
402
403 async fn after_delete_rbum(_: &str, _: &Option<DetailResp>, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
407 Ok(())
408 }
409
410 async fn delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
414 let deleted_rbum = Self::before_delete_rbum(id, funs, ctx).await?;
415 let res_select_req = <E::Entity as EntityTrait>::find().filter(Expr::col(ID_FIELD.clone()).eq(id));
416 #[cfg(feature = "with-mq")]
417 {
418 let delete_records = funs.db().soft_delete_custom(res_select_req, "id").await?;
419 let mq_topic_entity_deleted = &funs.rbum_conf_mq_topic_entity_deleted();
420 let mq_header = std::collections::HashMap::from([(funs.rbum_conf_mq_header_name_operator(), ctx.owner.clone())]);
421 for delete_record in &delete_records {
422 funs.mq().publish(mq_topic_entity_deleted, tardis::TardisFuns::json.obj_to_string(delete_record)?, &mq_header).await?;
423 }
424 Self::after_delete_rbum(id, &deleted_rbum, funs, ctx).await?;
425 rbum_event_helper::add_notify_event(Self::get_table_name(), "d", id, ctx).await?;
426 Ok(delete_records.len() as u64)
427 }
428 #[cfg(not(feature = "with-mq"))]
429 {
430 let delete_records = funs.db().soft_delete(res_select_req, &ctx.owner).await?;
431 Self::after_delete_rbum(id, &deleted_rbum, funs, ctx).await?;
432 rbum_event_helper::add_notify_event(Self::get_table_name(), "d", id, ctx).await?;
433 Ok(delete_records)
434 }
435 }
436
437 async fn package_query(is_detail: bool, filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement>;
480
481 async fn peek_rbum(id: &str, filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SummaryResp> {
485 Self::do_peek_rbum(id, filter, funs, ctx).await
486 }
487
488 async fn do_peek_rbum(id: &str, filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SummaryResp> {
496 let mut query = Self::package_query(false, filter, funs, ctx).await?;
497 query.and_where(Expr::col((Alias::new(Self::get_table_name()), ID_FIELD.clone())).eq(id));
498 let query = funs.db().get_dto(&query).await?;
499 match query {
500 Some(resp) => Ok(resp),
501 None => Err(funs.err().not_found(
502 &Self::get_obj_name(),
503 "peek",
504 &format!("not found {}.{} by {}", Self::get_obj_name(), id, ctx.owner),
505 "404-rbum-*-obj-not-exist",
506 )),
507 }
508 }
509
510 async fn get_rbum(id: &str, filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<DetailResp> {
514 Self::do_get_rbum(id, filter, funs, ctx).await
515 }
516
517 async fn do_get_rbum(id: &str, filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<DetailResp> {
525 let mut query = Self::package_query(true, filter, funs, ctx).await?;
526 query.and_where(Expr::col((Alias::new(Self::get_table_name()), ID_FIELD.clone())).eq(id));
527 let query = funs.db().get_dto(&query).await?;
528 match query {
529 Some(resp) => Ok(resp),
530 None => Err(funs.err().not_found(
531 &Self::get_obj_name(),
532 "get",
533 &format!("not found {}.{} by {}", Self::get_obj_name(), id, ctx.owner),
534 "404-rbum-*-obj-not-exist",
535 )),
536 }
537 }
538
539 async fn paginate_id_rbums(
543 filter: &FilterReq,
544 page_number: u32,
545 page_size: u32,
546 desc_sort_by_create: Option<bool>,
547 desc_sort_by_update: Option<bool>,
548 funs: &TardisFunsInst,
549 ctx: &TardisContext,
550 ) -> TardisResult<TardisPage<String>> {
551 Self::do_paginate_id_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
552 }
553
554 async fn do_paginate_id_rbums(
562 filter: &FilterReq,
563 page_number: u32,
564 page_size: u32,
565 desc_sort_by_create: Option<bool>,
566 desc_sort_by_update: Option<bool>,
567 funs: &TardisFunsInst,
568 ctx: &TardisContext,
569 ) -> TardisResult<TardisPage<String>> {
570 let mut query = Self::package_query(false, filter, funs, ctx).await?;
571 query.clear_selects();
572 query.column((Alias::new(Self::get_table_name()), ID_FIELD.clone()));
573 if let Some(sort) = desc_sort_by_create {
574 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
575 }
576 if let Some(sort) = desc_sort_by_update {
577 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
578 }
579 let (records, total_size) = funs.db().paginate_dtos::<IdResp>(&query, page_number as u64, page_size as u64).await?;
580 Ok(TardisPage {
581 page_size: page_size as u64,
582 page_number: page_number as u64,
583 total_size,
584 records: records.into_iter().map(|resp| resp.id).collect(),
585 })
586 }
587
588 async fn paginate_id_name_rbums(
592 filter: &FilterReq,
593 page_number: u32,
594 page_size: u32,
595 desc_sort_by_create: Option<bool>,
596 desc_sort_by_update: Option<bool>,
597 funs: &TardisFunsInst,
598 ctx: &TardisContext,
599 ) -> TardisResult<TardisPage<IdNameResp>> {
600 Self::do_paginate_id_name_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
601 }
602
603 async fn do_paginate_id_name_rbums(
611 filter: &FilterReq,
612 page_number: u32,
613 page_size: u32,
614 desc_sort_by_create: Option<bool>,
615 desc_sort_by_update: Option<bool>,
616 funs: &TardisFunsInst,
617 ctx: &TardisContext,
618 ) -> TardisResult<TardisPage<IdNameResp>> {
619 let mut query = Self::package_query(false, filter, funs, ctx).await?;
620 query.clear_selects();
621 query.columns([
622 (Alias::new(Self::get_table_name()), ID_FIELD.clone()),
623 (Alias::new(Self::get_table_name()), NAME_FIELD.clone()),
624 ]);
625 if let Some(sort) = desc_sort_by_create {
626 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
627 }
628 if let Some(sort) = desc_sort_by_update {
629 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
630 }
631 let (records, total_size) = funs.db().paginate_dtos::<IdNameResp>(&query, page_number as u64, page_size as u64).await?;
632 Ok(TardisPage {
633 page_size: page_size as u64,
634 page_number: page_number as u64,
635 total_size,
636 records,
637 })
638 }
639
640 async fn paginate_rbums(
644 filter: &FilterReq,
645 page_number: u32,
646 page_size: u32,
647 desc_sort_by_create: Option<bool>,
648 desc_sort_by_update: Option<bool>,
649 funs: &TardisFunsInst,
650 ctx: &TardisContext,
651 ) -> TardisResult<TardisPage<SummaryResp>> {
652 Self::do_paginate_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
653 }
654
655 async fn do_paginate_rbums(
663 filter: &FilterReq,
664 page_number: u32,
665 page_size: u32,
666 desc_sort_by_create: Option<bool>,
667 desc_sort_by_update: Option<bool>,
668 funs: &TardisFunsInst,
669 ctx: &TardisContext,
670 ) -> TardisResult<TardisPage<SummaryResp>> {
671 let mut query = Self::package_query(false, filter, funs, ctx).await?;
672 if let Some(sort) = desc_sort_by_create {
673 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
674 }
675 if let Some(sort) = desc_sort_by_update {
676 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
677 }
678 let (records, total_size) = funs.db().paginate_dtos(&query, page_number as u64, page_size as u64).await?;
679 Ok(TardisPage {
680 page_size: page_size as u64,
681 page_number: page_number as u64,
682 total_size,
683 records,
684 })
685 }
686
687 async fn paginate_detail_rbums(
691 filter: &FilterReq,
692 page_number: u32,
693 page_size: u32,
694 desc_sort_by_create: Option<bool>,
695 desc_sort_by_update: Option<bool>,
696 funs: &TardisFunsInst,
697 ctx: &TardisContext,
698 ) -> TardisResult<TardisPage<DetailResp>> {
699 Self::do_paginate_detail_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
700 }
701
702 async fn do_paginate_detail_rbums(
710 filter: &FilterReq,
711 page_number: u32,
712 page_size: u32,
713 desc_sort_by_create: Option<bool>,
714 desc_sort_by_update: Option<bool>,
715 funs: &TardisFunsInst,
716 ctx: &TardisContext,
717 ) -> TardisResult<TardisPage<DetailResp>> {
718 let mut query = Self::package_query(true, filter, funs, ctx).await?;
719 if let Some(sort) = desc_sort_by_create {
720 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
721 }
722 if let Some(sort) = desc_sort_by_update {
723 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
724 }
725 let (records, total_size) = funs.db().paginate_dtos(&query, page_number as u64, page_size as u64).await?;
726 Ok(TardisPage {
727 page_size: page_size as u64,
728 page_number: page_number as u64,
729 total_size,
730 records,
731 })
732 }
733
734 async fn find_one_rbum(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<SummaryResp>> {
738 Self::do_find_one_rbum(filter, funs, ctx).await
739 }
740
741 async fn do_find_one_rbum(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<SummaryResp>> {
749 let result = Self::find_rbums(filter, None, None, funs, ctx).await?;
750 if result.len() > 1 {
751 Err(funs.err().conflict(&Self::get_obj_name(), "find_one", "found multiple records", "409-rbum-*-obj-multi-exist"))
752 } else {
753 Ok(result.into_iter().next())
754 }
755 }
756
757 async fn find_id_rbums(
761 filter: &FilterReq,
762 desc_sort_by_create: Option<bool>,
763 desc_sort_by_update: Option<bool>,
764 funs: &TardisFunsInst,
765 ctx: &TardisContext,
766 ) -> TardisResult<Vec<String>> {
767 Self::do_find_id_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
768 }
769
770 async fn do_find_id_rbums(
778 filter: &FilterReq,
779 desc_sort_by_create: Option<bool>,
780 desc_sort_by_update: Option<bool>,
781 funs: &TardisFunsInst,
782 ctx: &TardisContext,
783 ) -> TardisResult<Vec<String>> {
784 let mut query = Self::package_query(false, filter, funs, ctx).await?;
785 query.clear_selects();
786 query.column((Alias::new(Self::get_table_name()), ID_FIELD.clone()));
787 if let Some(sort) = desc_sort_by_create {
788 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
789 }
790 if let Some(sort) = desc_sort_by_update {
791 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
792 }
793 Ok(funs.db().find_dtos::<IdResp>(&query).await?.into_iter().map(|resp| resp.id).collect())
794 }
795
796 async fn find_id_name_rbums(
800 filter: &FilterReq,
801 desc_sort_by_create: Option<bool>,
802 desc_sort_by_update: Option<bool>,
803 funs: &TardisFunsInst,
804 ctx: &TardisContext,
805 ) -> TardisResult<HashMap<String, String>> {
806 Self::do_find_id_name_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
807 }
808
809 async fn do_find_id_name_rbums(
817 filter: &FilterReq,
818 desc_sort_by_create: Option<bool>,
819 desc_sort_by_update: Option<bool>,
820 funs: &TardisFunsInst,
821 ctx: &TardisContext,
822 ) -> TardisResult<HashMap<String, String>> {
823 let mut query = Self::package_query(false, filter, funs, ctx).await?;
824 query.clear_selects();
825 query.columns([
826 (Alias::new(Self::get_table_name()), ID_FIELD.clone()),
827 (Alias::new(Self::get_table_name()), NAME_FIELD.clone()),
828 ]);
829 if let Some(sort) = desc_sort_by_create {
830 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
831 }
832 if let Some(sort) = desc_sort_by_update {
833 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
834 }
835 Ok(funs.db().find_dtos::<IdNameResp>(&query).await?.into_iter().map(|resp| (resp.id, resp.name)).collect())
836 }
837
838 async fn find_rbums(
842 filter: &FilterReq,
843 desc_sort_by_create: Option<bool>,
844 desc_sort_by_update: Option<bool>,
845 funs: &TardisFunsInst,
846 ctx: &TardisContext,
847 ) -> TardisResult<Vec<SummaryResp>> {
848 Self::do_find_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
849 }
850
851 async fn do_find_rbums(
859 filter: &FilterReq,
860 desc_sort_by_create: Option<bool>,
861 desc_sort_by_update: Option<bool>,
862 funs: &TardisFunsInst,
863 ctx: &TardisContext,
864 ) -> TardisResult<Vec<SummaryResp>> {
865 let mut query = Self::package_query(false, filter, funs, ctx).await?;
866 if let Some(sort) = desc_sort_by_create {
867 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
868 }
869 if let Some(sort) = desc_sort_by_update {
870 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
871 }
872 Ok(funs.db().find_dtos(&query).await?)
873 }
874
875 async fn find_one_detail_rbum(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<DetailResp>> {
879 Self::do_find_one_detail_rbum(filter, funs, ctx).await
880 }
881
882 async fn do_find_one_detail_rbum(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<DetailResp>> {
890 let result = Self::find_detail_rbums(filter, None, None, funs, ctx).await?;
891 if result.len() > 1 {
892 Err(funs.err().conflict(&Self::get_obj_name(), "find_one_detail", "found multiple records", "409-rbum-*-obj-multi-exist"))
893 } else {
894 Ok(result.into_iter().next())
895 }
896 }
897
898 async fn find_detail_rbums(
902 filter: &FilterReq,
903 desc_sort_by_create: Option<bool>,
904 desc_sort_by_update: Option<bool>,
905 funs: &TardisFunsInst,
906 ctx: &TardisContext,
907 ) -> TardisResult<Vec<DetailResp>> {
908 Self::do_find_detail_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
909 }
910
911 async fn do_find_detail_rbums(
919 filter: &FilterReq,
920 desc_sort_by_create: Option<bool>,
921 desc_sort_by_update: Option<bool>,
922 funs: &TardisFunsInst,
923 ctx: &TardisContext,
924 ) -> TardisResult<Vec<DetailResp>> {
925 let mut query = Self::package_query(true, filter, funs, ctx).await?;
926 if let Some(sort) = desc_sort_by_create {
927 query.order_by((Alias::new(Self::get_table_name()), CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
928 }
929 if let Some(sort) = desc_sort_by_update {
930 query.order_by((Alias::new(Self::get_table_name()), UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
931 }
932 Ok(funs.db().find_dtos(&query).await?)
933 }
934
935 async fn count_rbums(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
939 Self::do_count_rbums(filter, funs, ctx).await
940 }
941
942 async fn do_count_rbums(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
950 let query = Self::package_query(false, filter, funs, ctx).await?;
951 funs.db().count(&query).await
952 }
953
954 async fn exist_rbum(filter: &FilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<bool> {
958 let query = Self::count_rbums(filter, funs, ctx).await?;
959 Ok(query > 0)
960 }
961}
962
963pub trait RbumCrudQueryPackage {
965 fn with_filter(&mut self, table_name: &str, filter: &RbumBasicFilterReq, ignore_owner: bool, has_scope: bool, ctx: &TardisContext) -> &mut Self;
969 fn with_scope(&mut self, table_name: &str, filter_own_paths: &str, with_sub_own_paths: bool) -> &mut Self;
973}
974
975impl RbumCrudQueryPackage for SelectStatement {
976 fn with_filter(&mut self, table_name: &str, filter: &RbumBasicFilterReq, with_owner: bool, has_scope: bool, ctx: &TardisContext) -> &mut Self {
977 if filter.rel_ctx_owner {
978 self.and_where(Expr::col((Alias::new(table_name), OWNER_FIELD.clone())).eq(ctx.owner.as_str()));
979 }
980 if let Some(ids) = &filter.ids {
981 self.and_where(Expr::col((Alias::new(table_name), ID_FIELD.clone())).is_in(ids.clone()));
982 }
983
984 if let Some(scope_level) = &filter.scope_level {
985 self.and_where(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(scope_level.to_int()));
986 }
987 if let Some(enabled) = filter.enabled {
988 self.and_where(Expr::col((Alias::new(table_name), DISABLED_FIELD.clone())).eq(!enabled));
989 }
990
991 if let Some(name) = &filter.name {
992 self.and_where(Expr::col((Alias::new(table_name), NAME_FIELD.clone())).like(format!("%{name}%").as_str()));
993 }
994 if let Some(names) = &filter.names {
995 self.and_where(Expr::col((Alias::new(table_name), NAME_FIELD.clone())).is_in(names.clone()));
996 }
997 if let Some(code) = &filter.code {
998 self.and_where(Expr::col((Alias::new(table_name), CODE_FIELD.clone())).like(format!("{code}%").as_str()));
999 }
1000 if let Some(codes) = &filter.codes {
1001 self.and_where(Expr::col((Alias::new(table_name), CODE_FIELD.clone())).is_in(codes.clone()));
1002 }
1003
1004 if let Some(rbum_kind_id) = &filter.rbum_kind_id {
1005 self.and_where(Expr::col((Alias::new(table_name), REL_KIND_ID_FIELD.clone())).eq(rbum_kind_id.to_string()));
1006 }
1007 if let Some(rbum_domain_id) = &filter.rbum_domain_id {
1008 self.and_where(Expr::col((Alias::new(table_name), REL_DOMAIN_ID_FIELD.clone())).eq(rbum_domain_id.to_string()));
1009 }
1010 if with_owner {
1011 self.expr_as(Expr::col((OWNER_TABLE.clone(), NAME_FIELD.clone())), Alias::new("owner_name")).join_as(
1012 JoinType::LeftJoin,
1013 rbum_item::Entity,
1014 OWNER_TABLE.clone(),
1015 Expr::col((OWNER_TABLE.clone(), ID_FIELD.clone())).equals((Alias::new(table_name), OWNER_FIELD.clone())),
1016 );
1017 }
1018 let filter_own_paths = if let Some(own_paths) = &filter.own_paths { own_paths.as_str() } else { &ctx.own_paths };
1019 if has_scope && !filter.ignore_scope {
1020 self.with_scope(table_name, filter_own_paths, filter.with_sub_own_paths);
1021 } else if filter.with_sub_own_paths {
1022 self.and_where(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{filter_own_paths}%").as_str()));
1023 } else {
1024 self.and_where(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(filter_own_paths));
1025 }
1026 self
1027 }
1028
1029 fn with_scope(&mut self, table_name: &str, filter_own_paths: &str, with_sub_own_paths: bool) -> &mut Self {
1030 let mut cond = Cond::any().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(0));
1031
1032 let own_cond = if with_sub_own_paths {
1033 Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{filter_own_paths}%"))
1034 } else {
1035 Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(filter_own_paths)
1036 };
1037 cond = cond.add(own_cond);
1038
1039 if let Some(p1) = rbum_scope_helper::get_pre_paths(1, filter_own_paths) {
1040 cond = cond.add(
1041 Cond::all().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(1)).add(
1042 Cond::any()
1043 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(""))
1044 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p1}%"))),
1045 ),
1046 );
1047 if let Some(p2) = rbum_scope_helper::get_pre_paths(2, filter_own_paths) {
1048 let node_len = (p2.len() - p1.len() - 1) as u8;
1049 cond = cond.add(
1050 Cond::all().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(2)).add(
1051 Cond::any()
1052 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(""))
1053 .add(
1054 Cond::all()
1055 .add(Expr::expr(Func::char_length(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())))).eq(node_len))
1056 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p1}%"))),
1057 )
1058 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p2}%"))),
1059 ),
1060 );
1061 if let Some(p3) = rbum_scope_helper::get_pre_paths(3, filter_own_paths) {
1062 cond = cond.add(
1063 Cond::all().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(3)).add(
1064 Cond::any()
1065 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(""))
1066 .add(
1067 Cond::all()
1068 .add(Expr::expr(Func::char_length(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())))).eq(node_len))
1069 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p1}%"))),
1070 )
1071 .add(
1072 Cond::all()
1073 .add(Expr::expr(Func::char_length(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())))).eq(node_len * 2 + 1))
1074 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p2}%"))),
1075 )
1076 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p3}%"))),
1077 ),
1078 );
1079 } else if with_sub_own_paths {
1080 cond = cond.add(
1091 Cond::all().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(3)).add(
1092 Cond::any()
1093 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(""))
1094 .add(
1095 Cond::all()
1096 .add(Expr::expr(Func::char_length(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())))).eq(node_len))
1097 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p1}%"))),
1098 )
1099 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p2}%"))),
1100 ),
1101 );
1102 }
1103 } else if with_sub_own_paths {
1104 cond = cond.add(
1105 Cond::all().add(Expr::col((Alias::new(table_name), SCOPE_LEVEL_FIELD.clone())).eq(2)).add(
1106 Cond::any()
1107 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).eq(""))
1108 .add(Expr::col((Alias::new(table_name), OWN_PATHS_FIELD.clone())).like(format!("{p1}%"))),
1109 ),
1110 );
1111 }
1112 };
1113
1114 self.cond_where(Cond::all().add(cond));
1115 self
1116 }
1117}
1118
1119#[derive(Debug, sea_orm::FromQueryResult)]
1120pub struct NameResp {
1121 pub name: String,
1122}
1123
1124#[derive(Debug, Serialize, Deserialize, sea_orm::FromQueryResult, poem_openapi::Object)]
1125pub struct IdNameResp {
1126 pub id: String,
1127 pub name: String,
1128}