1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use serde::Serialize;
5use tardis::basic::dto::TardisContext;
6use tardis::basic::result::TardisResult;
7use tardis::db::reldb_client::{IdResp, TardisActiveModel};
8use tardis::db::sea_orm::sea_query::*;
9use tardis::db::sea_orm::*;
10use tardis::db::sea_orm::{self, IdenStatic};
11use tardis::web::poem_openapi::types::{ParseFromJSON, ToJSON};
12use tardis::web::web_resp::TardisPage;
13use tardis::{TardisFuns, TardisFunsInst};
14
15use super::rbum_crud_serv::{IdNameResp, CREATE_TIME_FIELD, ID_FIELD, UPDATE_TIME_FIELD};
16use crate::rbum::domain::{rbum_cert, rbum_cert_conf, rbum_domain, rbum_item, rbum_item_attr, rbum_kind, rbum_kind_attr, rbum_rel, rbum_set_item};
17use crate::rbum::dto::rbum_filer_dto::{
18 RbumBasicFilterReq, RbumCertConfFilterReq, RbumCertFilterReq, RbumItemAttrFilterReq, RbumItemFilterFetcher, RbumItemRelFilterReq, RbumKindAttrFilterReq, RbumKindFilterReq,
19 RbumSetItemFilterReq, RbumSetItemRelFilterReq,
20};
21use crate::rbum::dto::rbum_item_attr_dto::{RbumItemAttrAddReq, RbumItemAttrDetailResp, RbumItemAttrModifyReq, RbumItemAttrSummaryResp, RbumItemAttrsAddOrModifyReq};
22use crate::rbum::dto::rbum_item_dto::{RbumItemAddReq, RbumItemDetailResp, RbumItemKernelAddReq, RbumItemKernelModifyReq, RbumItemSummaryResp};
23use crate::rbum::dto::rbum_kind_attr_dto::RbumKindAttrSummaryResp;
24use crate::rbum::dto::rbum_rel_dto::{RbumRelAddReq, RbumRelSimpleFindReq};
25use crate::rbum::helper::rbum_event_helper;
26#[cfg(feature = "with-mq")]
27use crate::rbum::rbum_config::RbumConfigApi;
28use crate::rbum::rbum_enumeration::{RbumCertRelKind, RbumRelFromKind, RbumScopeLevelKind};
29use crate::rbum::serv::rbum_cert_serv::{RbumCertConfServ, RbumCertServ};
30#[cfg(feature = "with-mq")]
31use crate::rbum::serv::rbum_crud_serv::ID_FIELD_NAME;
32use crate::rbum::serv::rbum_crud_serv::{RbumCrudOperation, RbumCrudQueryPackage};
33use crate::rbum::serv::rbum_domain_serv::RbumDomainServ;
34use crate::rbum::serv::rbum_kind_serv::{RbumKindAttrServ, RbumKindServ};
35use crate::rbum::serv::rbum_rel_serv::RbumRelServ;
36use crate::rbum::serv::rbum_set_serv::RbumSetItemServ;
37use lazy_static::lazy_static;
38
39lazy_static! {
40 pub static ref RBUM_ITEM_TABLE: Alias = Alias::new("rbum_item");
41}
42
43pub struct RbumItemServ;
44
45pub struct RbumItemAttrServ;
46
47#[async_trait]
48impl RbumCrudOperation<rbum_item::ActiveModel, RbumItemAddReq, RbumItemKernelModifyReq, RbumItemSummaryResp, RbumItemDetailResp, RbumBasicFilterReq> for RbumItemServ {
49 fn get_table_name() -> &'static str {
50 rbum_item::Entity.table_name()
51 }
52
53 async fn before_add_rbum(add_req: &mut RbumItemAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
54 Self::check_scope(&add_req.rel_rbum_kind_id, RbumKindServ::get_table_name(), funs, ctx).await?;
55 Self::check_scope(&add_req.rel_rbum_domain_id, RbumDomainServ::get_table_name(), funs, ctx).await?;
56 Ok(())
57 }
58
59 async fn package_add(add_req: &RbumItemAddReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_item::ActiveModel> {
60 let id = if let Some(id) = &add_req.id { id.to_string() } else { TardisFuns::field.nanoid() };
61 let code = if let Some(code) = &add_req.code {
62 if funs
63 .db()
64 .count(
65 Query::select()
66 .column((rbum_item::Entity, rbum_item::Column::Id))
67 .from(rbum_item::Entity)
68 .inner_join(
69 rbum_domain::Entity,
70 Expr::col((rbum_domain::Entity, rbum_domain::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumDomainId)),
71 )
72 .inner_join(
73 rbum_kind::Entity,
74 Expr::col((rbum_kind::Entity, rbum_kind::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumKindId)),
75 )
76 .and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Code)).eq(code.to_string())),
77 )
78 .await?
79 > 0
80 {
81 return Err(funs.err().conflict(&Self::get_obj_name(), "add", &format!("code {code} already exists"), "409-rbum-*-code-exist"));
82 }
83 code.to_string()
84 } else {
85 id.clone()
86 };
87 Ok(rbum_item::ActiveModel {
88 id: Set(id),
89 code: Set(code),
90 name: Set(add_req.name.to_string()),
91 rel_rbum_kind_id: Set(add_req.rel_rbum_kind_id.to_string()),
92 rel_rbum_domain_id: Set(add_req.rel_rbum_domain_id.to_string()),
93 scope_level: Set(add_req.scope_level.as_ref().unwrap_or(&RbumScopeLevelKind::Private).to_int()),
94 disabled: Set(add_req.disabled.unwrap_or(false)),
95 ..Default::default()
96 })
97 }
98
99 async fn package_modify(id: &str, modify_req: &RbumItemKernelModifyReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_item::ActiveModel> {
100 let mut rbum_item = rbum_item::ActiveModel {
101 id: Set(id.to_string()),
102 ..Default::default()
103 };
104 if let Some(code) = &modify_req.code {
105 if funs
106 .db()
107 .count(
108 Query::select()
109 .column((rbum_item::Entity, rbum_item::Column::Id))
110 .from(rbum_item::Entity)
111 .inner_join(
112 rbum_domain::Entity,
113 Expr::col((rbum_domain::Entity, rbum_domain::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumDomainId)),
114 )
115 .inner_join(
116 rbum_kind::Entity,
117 Expr::col((rbum_kind::Entity, rbum_kind::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumKindId)),
118 )
119 .and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Code)).eq(code.to_string()))
120 .and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Id)).ne(id)),
121 )
122 .await?
123 > 0
124 {
125 return Err(funs.err().conflict(&Self::get_obj_name(), "modify", &format!("code {code} already exists"), "409-rbum-*-code-exist"));
126 }
127 rbum_item.code = Set(code.to_string());
128 }
129 if let Some(name) = &modify_req.name {
130 rbum_item.name = Set(name.to_string());
131 }
132 if let Some(scope_level) = &modify_req.scope_level {
133 rbum_item.scope_level = Set(scope_level.to_int());
134 }
135 if let Some(disabled) = modify_req.disabled {
136 rbum_item.disabled = Set(disabled);
137 }
138 Ok(rbum_item)
139 }
140
141 async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumItemDetailResp>> {
142 Self::check_ownership(id, funs, ctx).await?;
143 Self::check_exist_before_delete(id, RbumItemAttrServ::get_table_name(), rbum_item_attr::Column::RelRbumItemId.as_str(), funs).await?;
144 Self::check_exist_with_cond_before_delete(
145 RbumRelServ::get_table_name(),
146 any![
147 all![
148 Expr::col(rbum_rel::Column::FromRbumKind).eq(RbumRelFromKind::Item.to_int()),
149 Expr::col(rbum_rel::Column::FromRbumId).eq(id)
150 ],
151 Expr::col(rbum_rel::Column::ToRbumItemId).eq(id)
152 ],
153 funs,
154 )
155 .await?;
156 Self::check_exist_before_delete(id, RbumSetItemServ::get_table_name(), rbum_set_item::Column::RelRbumItemId.as_str(), funs).await?;
157 Self::check_exist_before_delete(id, RbumCertConfServ::get_table_name(), rbum_cert_conf::Column::RelRbumItemId.as_str(), funs).await?;
158 Self::check_exist_with_cond_before_delete(
159 RbumCertServ::get_table_name(),
160 all![
161 Expr::col(rbum_cert::Column::RelRbumKind).eq(RbumCertRelKind::Item.to_int()),
162 Expr::col(rbum_cert::Column::RelRbumId).eq(id)
163 ],
164 funs,
165 )
166 .await?;
167 Ok(None)
168 }
169
170 async fn package_query(is_detail: bool, filter: &RbumBasicFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
171 let mut query = Query::select();
172 query
173 .columns(vec![
174 (rbum_item::Entity, rbum_item::Column::Id),
175 (rbum_item::Entity, rbum_item::Column::Code),
176 (rbum_item::Entity, rbum_item::Column::Name),
177 (rbum_item::Entity, rbum_item::Column::RelRbumKindId),
178 (rbum_item::Entity, rbum_item::Column::RelRbumDomainId),
179 (rbum_item::Entity, rbum_item::Column::OwnPaths),
180 (rbum_item::Entity, rbum_item::Column::Owner),
181 (rbum_item::Entity, rbum_item::Column::CreateTime),
182 (rbum_item::Entity, rbum_item::Column::UpdateTime),
183 (rbum_item::Entity, rbum_item::Column::ScopeLevel),
184 (rbum_item::Entity, rbum_item::Column::Disabled),
185 ])
186 .from(rbum_item::Entity);
187
188 if is_detail {
189 query
190 .expr_as(Expr::col((rbum_kind::Entity, rbum_kind::Column::Name)), Alias::new("rel_rbum_kind_name"))
191 .expr_as(Expr::col((rbum_domain::Entity, rbum_domain::Column::Name)), Alias::new("rel_rbum_domain_name"))
192 .inner_join(
193 rbum_kind::Entity,
194 Expr::col((rbum_kind::Entity, rbum_kind::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumKindId)),
195 )
196 .inner_join(
197 rbum_domain::Entity,
198 Expr::col((rbum_domain::Entity, rbum_domain::Column::Id)).equals((rbum_item::Entity, rbum_item::Column::RelRbumDomainId)),
199 );
200 }
201 query.with_filter(Self::get_table_name(), filter, is_detail, true, ctx);
202 Ok(query)
203 }
204}
205
206#[async_trait]
210pub trait RbumItemCrudOperation<EXT, AddReq, ModifyReq, SummaryResp, DetailResp, ItemFilterReq>
211where
212 EXT: TardisActiveModel + Sync + Send,
213 AddReq: Sync + Send,
214 ModifyReq: Sync + Send,
215 SummaryResp: FromQueryResult + ParseFromJSON + ToJSON + Serialize + Send + Sync,
216 DetailResp: FromQueryResult + ParseFromJSON + ToJSON + Serialize + Send + Sync,
217 ItemFilterReq: Sync + Send + RbumItemFilterFetcher,
218{
219 fn get_ext_table_name() -> &'static str;
223
224 fn get_obj_name() -> String {
232 Self::get_ext_table_name().to_string()
233 }
234
235 fn get_rbum_kind_id() -> Option<String>;
239
240 fn get_rbum_domain_id() -> Option<String>;
244
245 async fn before_add_item(_: &mut AddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
251 Ok(())
252 }
253
254 async fn package_item_add(add_req: &AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<RbumItemKernelAddReq>;
272
273 async fn package_ext_add(id: &str, add_req: &AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<EXT>;
291
292 async fn after_add_item(_: &str, _: &mut AddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
296 Ok(())
297 }
298
299 async fn add_item(add_req: &mut AddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
303 Self::before_add_item(add_req, funs, ctx).await?;
304 let add_kernel_req = Self::package_item_add(add_req, funs, ctx).await?;
305 let mut item_add_req = RbumItemAddReq {
306 id: add_kernel_req.id.clone(),
307 code: add_kernel_req.code.clone(),
308 name: add_kernel_req.name.clone(),
309 rel_rbum_kind_id: if let Some(rel_rbum_kind_id) = &add_kernel_req.rel_rbum_kind_id {
310 rel_rbum_kind_id.to_string()
311 } else {
312 Self::get_rbum_kind_id().ok_or_else(|| funs.err().bad_request(&Self::get_obj_name(), "add_item", "kind is required", "400-rbum-kind-require"))?
313 },
314 rel_rbum_domain_id: if let Some(rel_rbum_domain_id) = &add_kernel_req.rel_rbum_domain_id {
315 rel_rbum_domain_id.to_string()
316 } else {
317 Self::get_rbum_domain_id().ok_or_else(|| funs.err().bad_request(&Self::get_obj_name(), "add_item", "domain is required", "400-rbum-domain-require"))?
318 },
319 scope_level: add_kernel_req.scope_level.clone(),
320 disabled: add_kernel_req.disabled,
321 };
322 let id = RbumItemServ::add_rbum(&mut item_add_req, funs, ctx).await?;
323 let add_ext_req = Self::package_ext_add(&id, add_req, funs, ctx).await?;
324 funs.db().insert_one(add_ext_req, ctx).await?;
325 Self::after_add_item(&id, add_req, funs, ctx).await?;
326 rbum_event_helper::add_notify_event(Self::get_ext_table_name(), "c", id.as_str(), ctx).await?;
327 Ok(id)
328 }
329
330 async fn add_item_with_simple_rel_by_from(add_req: &mut AddReq, tag: &str, to_rbum_item_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
334 let id = Self::add_item(add_req, funs, ctx).await?;
335 RbumRelServ::add_rbum(
336 &mut RbumRelAddReq {
337 tag: tag.to_string(),
338 note: None,
339 from_rbum_kind: RbumRelFromKind::Item,
340 from_rbum_id: id.to_string(),
341 to_rbum_item_id: to_rbum_item_id.to_string(),
342 to_own_paths: ctx.own_paths.to_string(),
343 to_is_outside: false,
344 ext: None,
345 },
346 funs,
347 ctx,
348 )
349 .await?;
350 Ok(id)
351 }
352
353 async fn add_item_with_simple_rel_by_to(add_req: &mut AddReq, tag: &str, from_rbum_item_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
357 let id = Self::add_item(add_req, funs, ctx).await?;
358 RbumRelServ::add_rbum(
359 &mut RbumRelAddReq {
360 tag: tag.to_string(),
361 note: None,
362 from_rbum_kind: RbumRelFromKind::Item,
363 from_rbum_id: from_rbum_item_id.to_string(),
364 to_rbum_item_id: id.to_string(),
365 to_own_paths: ctx.own_paths.to_string(),
366 to_is_outside: false,
367 ext: None,
368 },
369 funs,
370 ctx,
371 )
372 .await?;
373 Ok(id)
374 }
375
376 async fn before_modify_item(_: &str, _: &mut ModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
382 Ok(())
383 }
384
385 async fn package_item_modify(id: &str, modify_req: &ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumItemKernelModifyReq>>;
405
406 async fn package_ext_modify(id: &str, modify_req: &ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<EXT>>;
434
435 async fn after_modify_item(_: &str, _: &mut ModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
439 Ok(())
440 }
441
442 async fn modify_item(id: &str, modify_req: &mut ModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
446 Self::before_modify_item(id, modify_req, funs, ctx).await?;
447 let modify_kernel_req = Self::package_item_modify(id, modify_req, funs, ctx).await?;
448 if let Some(mut item_modify_req) = modify_kernel_req {
449 RbumItemServ::modify_rbum(id, &mut item_modify_req, funs, ctx).await?;
450 } else {
451 RbumItemServ::check_ownership(id, funs, ctx).await?;
452 }
453 let modify_ext_req = Self::package_ext_modify(id, modify_req, funs, ctx).await?;
454 if let Some(ext_domain) = modify_ext_req {
455 funs.db().update_one(ext_domain, ctx).await?;
456 }
457 Self::after_modify_item(id, modify_req, funs, ctx).await?;
458 rbum_event_helper::add_notify_event(Self::get_ext_table_name(), "u", id, ctx).await?;
459 Ok(())
460 }
461
462 async fn before_delete_item(_: &str, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<Option<DetailResp>> {
468 Ok(None)
469 }
470
471 async fn after_delete_item(_: &str, _: &Option<DetailResp>, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
475 Ok(())
476 }
477
478 async fn delete_item(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
484 let deleted_item = Self::before_delete_item(id, funs, ctx).await?;
485 let item_select_req = <EXT::Entity as EntityTrait>::find().filter(Expr::col(ID_FIELD.clone()).eq(id));
486 #[cfg(feature = "with-mq")]
487 {
488 let deleted_ext_records = funs.db().soft_delete_custom(item_select_req, ID_FIELD_NAME).await?;
489 RbumItemServ::delete_rbum(id, funs, ctx).await?;
490 let mq_topic_entity_deleted = &funs.rbum_conf_mq_topic_entity_deleted();
491 let mq_header = std::collections::HashMap::from([(funs.rbum_conf_mq_header_name_operator(), ctx.owner.clone())]);
492 for delete_record in &deleted_ext_records {
493 funs.mq().publish(mq_topic_entity_deleted, TardisFuns::json.obj_to_string(delete_record)?, &mq_header).await?;
494 }
495 Self::after_delete_item(id, &deleted_item, funs, ctx).await?;
496 rbum_event_helper::add_notify_event(Self::get_ext_table_name(), "d", id, ctx).await?;
497 Ok(deleted_ext_records.len() as u64)
498 }
499 #[cfg(not(feature = "with-mq"))]
500 {
501 let deleted_ext_records = funs.db().soft_delete(item_select_req, &ctx.owner).await?;
502 RbumItemServ::delete_rbum(id, funs, ctx).await?;
503 Self::after_delete_item(id, &deleted_item, funs, ctx).await?;
504 rbum_event_helper::add_notify_event(Self::get_ext_table_name(), "d", id, ctx).await?;
505 Ok(deleted_ext_records)
506 }
507 }
508
509 async fn delete_item_with_all_rels(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
513 let rel_ids = RbumRelServ::find_rel_ids(
515 &RbumRelSimpleFindReq {
516 tag: None,
517 from_rbum_kind: Some(RbumRelFromKind::Item),
518 from_rbum_id: Some(id.to_string()),
519 to_rbum_item_id: None,
520 ..Default::default()
521 },
522 funs,
523 ctx,
524 )
525 .await?;
526 for rel_id in rel_ids {
527 RbumRelServ::delete_rel_with_ext(&rel_id, funs, ctx).await?;
528 }
529 let rel_ids = RbumRelServ::find_rel_ids(
530 &RbumRelSimpleFindReq {
531 tag: None,
532 from_rbum_kind: None,
533 from_rbum_id: None,
534 to_rbum_item_id: Some(id.to_string()),
535 ..Default::default()
536 },
537 funs,
538 ctx,
539 )
540 .await?;
541 for rel_id in rel_ids {
542 RbumRelServ::delete_rel_with_ext(&rel_id, funs, ctx).await?;
543 }
544
545 let set_item_ids = RbumSetItemServ::find_id_rbums(
547 &RbumSetItemFilterReq {
548 basic: RbumBasicFilterReq {
549 with_sub_own_paths: true,
550 ..Default::default()
551 },
552 rel_rbum_item_ids: Some(vec![id.to_string()]),
553 ..Default::default()
554 },
555 None,
556 None,
557 funs,
558 ctx,
559 )
560 .await?;
561 for set_item_id in set_item_ids {
562 RbumSetItemServ::delete_rbum(&set_item_id, funs, ctx).await?;
563 }
564
565 let cert_ids = RbumCertServ::find_id_rbums(
567 &RbumCertFilterReq {
568 basic: RbumBasicFilterReq {
569 with_sub_own_paths: true,
570 ..Default::default()
571 },
572 rel_rbum_kind: Some(RbumCertRelKind::Item),
573 rel_rbum_id: Some(id.to_string()),
574 ..Default::default()
575 },
576 None,
577 None,
578 funs,
579 ctx,
580 )
581 .await?;
582 for cert_id in cert_ids {
583 RbumCertServ::delete_rbum(&cert_id, funs, ctx).await?;
584 }
585
586 let cert_conf_ids = RbumCertConfServ::find_id_rbums(
588 &RbumCertConfFilterReq {
589 basic: RbumBasicFilterReq {
590 with_sub_own_paths: true,
591 ..Default::default()
592 },
593 rel_rbum_item_id: Some(id.to_string()),
594 ..Default::default()
595 },
596 None,
597 None,
598 funs,
599 ctx,
600 )
601 .await?;
602 for cert_conf_id in cert_conf_ids {
603 RbumCertConfServ::delete_rbum(&cert_conf_id, funs, ctx).await?;
604 }
605
606 Self::delete_item(id, funs, ctx).await
607 }
608
609 async fn package_item_query(is_detail: bool, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
615 let mut query = RbumItemServ::package_query(
616 is_detail,
617 &RbumBasicFilterReq {
618 ignore_scope: filter.basic().ignore_scope,
619 rel_ctx_owner: filter.basic().rel_ctx_owner,
620 own_paths: filter.basic().own_paths.clone(),
621 with_sub_own_paths: filter.basic().with_sub_own_paths,
622 ids: filter.basic().ids.clone(),
623 scope_level: filter.basic().scope_level.clone(),
624 enabled: filter.basic().enabled,
625 name: filter.basic().name.clone(),
626 names: filter.basic().names.clone(),
627 code: filter.basic().code.clone(),
628 codes: filter.basic().codes.clone(),
629 rbum_kind_id: if filter.basic().rbum_kind_id.is_some() {
630 filter.basic().rbum_kind_id.clone()
631 } else {
632 Self::get_rbum_kind_id()
633 },
634 rbum_domain_id: if filter.basic().rbum_domain_id.is_some() {
635 filter.basic().rbum_domain_id.clone()
636 } else {
637 Self::get_rbum_domain_id()
638 },
639 },
640 funs,
641 ctx,
642 )
643 .await?;
644
645 if let Some(rbum_item_rel_filter_req) = &filter.rel() {
646 Self::package_rel(&mut query, Alias::new("rbum_rel1"), rbum_item_rel_filter_req);
647 }
648 if let Some(rbum_item_rel_filter_req) = &filter.rel2() {
649 Self::package_rel(&mut query, Alias::new("rbum_rel2"), rbum_item_rel_filter_req);
650 }
651 Ok(query)
652 }
653
654 fn package_rel(query: &mut SelectStatement, rel_table: Alias, rbum_item_rel_filter_req: &RbumItemRelFilterReq) {
658 let mut binding = Query::select();
659 let sub_query = binding.from(rbum_rel::Entity);
660 if let Some(tag) = &rbum_item_rel_filter_req.tag {
661 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Tag)).eq(tag.to_string()));
662 }
663 if let Some(from_rbum_kind) = &rbum_item_rel_filter_req.from_rbum_kind {
664 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(from_rbum_kind.to_int()));
665 }
666 if let Some(ext_eq) = &rbum_item_rel_filter_req.ext_eq {
667 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Ext)).eq(ext_eq.to_string()));
668 }
669 if let Some(ext_like) = &rbum_item_rel_filter_req.ext_like {
670 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Ext)).like(format!("%{ext_like}%").as_str()));
671 }
672 if let Some(own_paths) = &rbum_item_rel_filter_req.own_paths {
673 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::OwnPaths)).eq(own_paths.to_string()));
674 }
675 if rbum_item_rel_filter_req.rel_by_from {
676 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
677 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(rel_item_id.to_string()));
678 }
679 if let Some(rel_item_ids) = &rbum_item_rel_filter_req.rel_item_ids {
680 if rel_item_ids.len() == 1 {
681 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(rel_item_ids.first().expect("ignore").to_string()));
682 } else if !rel_item_ids.is_empty() {
683 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).is_in(rel_item_ids));
684 }
685 }
686 sub_query.column((rbum_rel::Entity, rbum_rel::Column::FromRbumId));
687 sub_query.group_by_col((rbum_rel::Entity, rbum_rel::Column::FromRbumId));
688
689 if rbum_item_rel_filter_req.optional {
690 query.join_subquery(
691 JoinType::LeftJoin,
692 sub_query.take(),
693 rel_table,
694 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).equals((rbum_item::Entity, rbum_item::Column::Id)),
695 );
696 } else {
697 query.join_subquery(
698 JoinType::InnerJoin,
699 sub_query.take(),
700 rel_table.clone(),
701 Expr::col((rel_table, rbum_rel::Column::FromRbumId)).equals((rbum_item::Entity, rbum_item::Column::Id)),
702 );
703 }
704 } else {
705 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
706 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).eq(rel_item_id.to_string()));
707 }
708 if let Some(rel_item_ids) = &rbum_item_rel_filter_req.rel_item_ids {
709 if rel_item_ids.len() == 1 {
710 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).eq(rel_item_ids.first().expect("ignore").to_string()));
711 } else if !rel_item_ids.is_empty() {
712 sub_query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).is_in(rel_item_ids));
713 }
714 }
715 sub_query.column((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId));
716 sub_query.group_by_col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId));
717
718 if rbum_item_rel_filter_req.optional {
719 query.join_subquery(
720 JoinType::LeftJoin,
721 sub_query.take(),
722 rel_table.clone(),
723 Expr::col((rel_table, rbum_rel::Column::ToRbumItemId)).equals((rbum_item::Entity, rbum_item::Column::Id)),
724 );
725 } else {
726 query.join_subquery(
727 JoinType::InnerJoin,
728 sub_query.take(),
729 rel_table.clone(),
730 Expr::col((rel_table, rbum_rel::Column::ToRbumItemId)).equals((rbum_item::Entity, rbum_item::Column::Id)),
731 );
732 }
733 }
734 }
735
736 fn package_set_rel(query: &mut SelectStatement, rel_table: Alias, rbum_set_rel_filter_req: &RbumSetItemRelFilterReq) {
740 let mut binding = Query::select();
741 let sub_query = binding.from(rbum_set_item::Entity);
742 if let Some(set_ids_and_cate_codes) = rbum_set_rel_filter_req.set_ids_and_cate_codes.clone() {
743 let mut cond_by_sets = Condition::any();
744 for set_id in set_ids_and_cate_codes.keys() {
745 let mut cond_by_a_set = Condition::all();
746 cond_by_a_set = cond_by_a_set.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetId)).eq(set_id));
747 if rbum_set_rel_filter_req.with_sub_set_cate_codes {
748 if let Some(cate_codes) = set_ids_and_cate_codes.get(set_id) {
749 let mut cond = Condition::any();
750 for cate_code in cate_codes {
751 cond = cond.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).like(format!("{}%", cate_code)));
752 }
753 cond_by_a_set = cond_by_a_set.add(Cond::all().add(cond));
754 } else {
755 }
757 } else {
758 cond_by_a_set = cond_by_a_set.add(
759 Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).is_in(set_ids_and_cate_codes.get(set_id).unwrap_or(&Vec::<String>::new())),
760 );
761 }
762 cond_by_sets = cond_by_sets.add(cond_by_a_set);
763 }
764 sub_query.cond_where(cond_by_sets);
765 }
766 sub_query.column((rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId));
767 sub_query.group_by_col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId));
768
769 query.join_subquery(
770 JoinType::InnerJoin,
771 sub_query.take(),
772 rel_table.clone(),
773 Expr::col((rel_table, rbum_set_item::Column::RelRbumItemId)).equals((rbum_item::Entity, rbum_item::Column::Id)),
774 );
775 }
776
777 async fn package_ext_query(query: &mut SelectStatement, is_detail: bool, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()>;
794
795 async fn peek_item(id: &str, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SummaryResp> {
799 Self::do_peek_item(id, filter, funs, ctx).await
800 }
801
802 async fn do_peek_item(id: &str, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SummaryResp> {
810 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
811 query.inner_join(
812 Alias::new(Self::get_ext_table_name()),
813 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
814 );
815 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
816 query.and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Id)).eq(id));
817 let query = funs.db().get_dto(&query).await?;
818 match query {
819 Some(resp) => Ok(resp),
820 None => Err(funs.err().not_found(
821 &Self::get_obj_name(),
822 "peek",
823 &format!("not found {}.{} by {}", Self::get_obj_name(), id, ctx.owner),
824 "404-rbum-*-obj-not-exist",
825 )),
826 }
827 }
828
829 async fn get_item(id: &str, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<DetailResp> {
833 Self::do_get_item(id, filter, funs, ctx).await
834 }
835
836 async fn do_get_item(id: &str, filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<DetailResp> {
844 let mut query = Self::package_item_query(true, filter, funs, ctx).await?;
845 query.inner_join(
846 Alias::new(Self::get_ext_table_name()),
847 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
848 );
849 Self::package_ext_query(&mut query, true, filter, funs, ctx).await?;
850 query.and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Id)).eq(id));
851 let query = funs.db().get_dto(&query).await?;
852 match query {
853 Some(resp) => Ok(resp),
854 None => Err(funs.err().not_found(
855 &Self::get_obj_name(),
856 "get",
857 &format!("not found {}.{} by {}", Self::get_obj_name(), id, ctx.owner),
858 "404-rbum-*-obj-not-exist",
859 )),
860 }
861 }
862
863 async fn paginate_id_items(
867 filter: &ItemFilterReq,
868 page_number: u32,
869 page_size: u32,
870 desc_sort_by_create: Option<bool>,
871 desc_sort_by_update: Option<bool>,
872 funs: &TardisFunsInst,
873 ctx: &TardisContext,
874 ) -> TardisResult<TardisPage<String>> {
875 Self::do_paginate_id_items(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
876 }
877
878 async fn do_paginate_id_items(
886 filter: &ItemFilterReq,
887 page_number: u32,
888 page_size: u32,
889 desc_sort_by_create: Option<bool>,
890 desc_sort_by_update: Option<bool>,
891 funs: &TardisFunsInst,
892 ctx: &TardisContext,
893 ) -> TardisResult<TardisPage<String>> {
894 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
895 query.inner_join(
896 Alias::new(Self::get_ext_table_name()),
897 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
898 );
899 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
900 query.clear_selects();
901 query.column((rbum_item::Entity, rbum_item::Column::Id));
902 if let Some(sort) = desc_sort_by_create {
903 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
904 }
905 if let Some(sort) = desc_sort_by_update {
906 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
907 }
908 let (records, total_size) = funs.db().paginate_dtos::<IdResp>(&query, page_number as u64, page_size as u64).await?;
909 Ok(TardisPage {
910 page_size: page_size as u64,
911 page_number: page_number as u64,
912 total_size,
913 records: records.into_iter().map(|resp| resp.id).collect(),
914 })
915 }
916
917 async fn paginate_id_name_items(
921 filter: &ItemFilterReq,
922 page_number: u32,
923 page_size: u32,
924 desc_sort_by_create: Option<bool>,
925 desc_sort_by_update: Option<bool>,
926 funs: &TardisFunsInst,
927 ctx: &TardisContext,
928 ) -> TardisResult<TardisPage<IdNameResp>> {
929 Self::do_paginate_id_name_items(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
930 }
931
932 async fn do_paginate_id_name_items(
940 filter: &ItemFilterReq,
941 page_number: u32,
942 page_size: u32,
943 desc_sort_by_create: Option<bool>,
944 desc_sort_by_update: Option<bool>,
945 funs: &TardisFunsInst,
946 ctx: &TardisContext,
947 ) -> TardisResult<TardisPage<IdNameResp>> {
948 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
949 query.inner_join(
950 Alias::new(Self::get_ext_table_name()),
951 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
952 );
953 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
954 query.clear_selects();
955 query.columns([(rbum_item::Entity, rbum_item::Column::Id), (rbum_item::Entity, rbum_item::Column::Name)]);
956 if let Some(sort) = desc_sort_by_create {
957 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
958 }
959 if let Some(sort) = desc_sort_by_update {
960 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
961 }
962 let (records, total_size) = funs.db().paginate_dtos::<IdNameResp>(&query, page_number as u64, page_size as u64).await?;
963 Ok(TardisPage {
964 page_size: page_size as u64,
965 page_number: page_number as u64,
966 total_size,
967 records,
968 })
969 }
970
971 async fn paginate_items(
975 filter: &ItemFilterReq,
976 page_number: u32,
977 page_size: u32,
978 desc_sort_by_create: Option<bool>,
979 desc_sort_by_update: Option<bool>,
980 funs: &TardisFunsInst,
981 ctx: &TardisContext,
982 ) -> TardisResult<TardisPage<SummaryResp>> {
983 Self::do_paginate_items(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
984 }
985
986 async fn do_paginate_items(
994 filter: &ItemFilterReq,
995 page_number: u32,
996 page_size: u32,
997 desc_sort_by_create: Option<bool>,
998 desc_sort_by_update: Option<bool>,
999 funs: &TardisFunsInst,
1000 ctx: &TardisContext,
1001 ) -> TardisResult<TardisPage<SummaryResp>> {
1002 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
1003 query.inner_join(
1004 Alias::new(Self::get_ext_table_name()),
1005 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1006 );
1007 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
1008 if let Some(sort) = desc_sort_by_create {
1009 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1010 }
1011 if let Some(sort) = desc_sort_by_update {
1012 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1013 }
1014 let (records, total_size) = funs.db().paginate_dtos(&query, page_number as u64, page_size as u64).await?;
1015 Ok(TardisPage {
1016 page_size: page_size as u64,
1017 page_number: page_number as u64,
1018 total_size,
1019 records,
1020 })
1021 }
1022
1023 async fn paginate_detail_items(
1027 filter: &ItemFilterReq,
1028 page_number: u32,
1029 page_size: u32,
1030 desc_sort_by_create: Option<bool>,
1031 desc_sort_by_update: Option<bool>,
1032 funs: &TardisFunsInst,
1033 ctx: &TardisContext,
1034 ) -> TardisResult<TardisPage<DetailResp>> {
1035 Self::do_paginate_detail_items(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
1036 }
1037
1038 async fn do_paginate_detail_items(
1046 filter: &ItemFilterReq,
1047 page_number: u32,
1048 page_size: u32,
1049 desc_sort_by_create: Option<bool>,
1050 desc_sort_by_update: Option<bool>,
1051 funs: &TardisFunsInst,
1052 ctx: &TardisContext,
1053 ) -> TardisResult<TardisPage<DetailResp>> {
1054 let mut query = Self::package_item_query(true, filter, funs, ctx).await?;
1055 query.inner_join(
1056 Alias::new(Self::get_ext_table_name()),
1057 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1058 );
1059 Self::package_ext_query(&mut query, true, filter, funs, ctx).await?;
1060 if let Some(sort) = desc_sort_by_create {
1061 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1062 }
1063 if let Some(sort) = desc_sort_by_update {
1064 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1065 }
1066 let (records, total_size) = funs.db().paginate_dtos(&query, page_number as u64, page_size as u64).await?;
1067 Ok(TardisPage {
1068 page_size: page_size as u64,
1069 page_number: page_number as u64,
1070 total_size,
1071 records,
1072 })
1073 }
1074
1075 async fn find_one_item(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<SummaryResp>> {
1079 Self::do_find_one_item(filter, funs, ctx).await
1080 }
1081
1082 async fn do_find_one_item(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<SummaryResp>> {
1090 let result = Self::find_items(filter, None, None, funs, ctx).await?;
1091 if result.len() > 1 {
1092 Err(funs.err().conflict(&Self::get_obj_name(), "find_one", "found multiple records", "409-rbum-*-obj-multi-exist"))
1093 } else {
1094 Ok(result.into_iter().next())
1095 }
1096 }
1097
1098 async fn find_id_items(
1102 filter: &ItemFilterReq,
1103 desc_sort_by_create: Option<bool>,
1104 desc_sort_by_update: Option<bool>,
1105 funs: &TardisFunsInst,
1106 ctx: &TardisContext,
1107 ) -> TardisResult<Vec<String>> {
1108 Self::do_find_id_items(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
1109 }
1110
1111 async fn do_find_id_items(
1119 filter: &ItemFilterReq,
1120 desc_sort_by_create: Option<bool>,
1121 desc_sort_by_update: Option<bool>,
1122 funs: &TardisFunsInst,
1123 ctx: &TardisContext,
1124 ) -> TardisResult<Vec<String>> {
1125 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
1126 query.inner_join(
1127 Alias::new(Self::get_ext_table_name()),
1128 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1129 );
1130 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
1131 query.clear_selects();
1132 query.column((rbum_item::Entity, rbum_item::Column::Id));
1133 if let Some(sort) = desc_sort_by_create {
1134 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1135 }
1136 if let Some(sort) = desc_sort_by_update {
1137 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1138 }
1139 Ok(funs.db().find_dtos::<IdResp>(&query).await?.into_iter().map(|resp| resp.id).collect())
1140 }
1141
1142 async fn find_id_name_items(
1146 filter: &ItemFilterReq,
1147 desc_sort_by_create: Option<bool>,
1148 desc_sort_by_update: Option<bool>,
1149 funs: &TardisFunsInst,
1150 ctx: &TardisContext,
1151 ) -> TardisResult<HashMap<String, String>> {
1152 Self::do_find_id_name_items(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
1153 }
1154
1155 async fn do_find_id_name_items(
1163 filter: &ItemFilterReq,
1164 desc_sort_by_create: Option<bool>,
1165 desc_sort_by_update: Option<bool>,
1166 funs: &TardisFunsInst,
1167 ctx: &TardisContext,
1168 ) -> TardisResult<HashMap<String, String>> {
1169 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
1170 query.inner_join(
1171 Alias::new(Self::get_ext_table_name()),
1172 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1173 );
1174 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
1175 query.clear_selects();
1176 query.columns([(rbum_item::Entity, rbum_item::Column::Id), (rbum_item::Entity, rbum_item::Column::Name)]);
1177 if let Some(sort) = desc_sort_by_create {
1178 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1179 }
1180 if let Some(sort) = desc_sort_by_update {
1181 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1182 }
1183 Ok(funs.db().find_dtos::<IdNameResp>(&query).await?.into_iter().map(|resp| (resp.id, resp.name)).collect())
1184 }
1185
1186 async fn find_items(
1190 filter: &ItemFilterReq,
1191 desc_sort_by_create: Option<bool>,
1192 desc_sort_by_update: Option<bool>,
1193 funs: &TardisFunsInst,
1194 ctx: &TardisContext,
1195 ) -> TardisResult<Vec<SummaryResp>> {
1196 Self::do_find_items(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
1197 }
1198
1199 async fn do_find_items(
1207 filter: &ItemFilterReq,
1208 desc_sort_by_create: Option<bool>,
1209 desc_sort_by_update: Option<bool>,
1210 funs: &TardisFunsInst,
1211 ctx: &TardisContext,
1212 ) -> TardisResult<Vec<SummaryResp>> {
1213 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
1214 query.inner_join(
1215 Alias::new(Self::get_ext_table_name()),
1216 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1217 );
1218 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
1219 if let Some(sort) = desc_sort_by_create {
1220 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1221 }
1222 if let Some(sort) = desc_sort_by_update {
1223 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1224 }
1225 Ok(funs.db().find_dtos(&query).await?)
1226 }
1227
1228 async fn find_one_detail_item(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<DetailResp>> {
1232 Self::do_find_one_detail_item(filter, funs, ctx).await
1233 }
1234
1235 async fn do_find_one_detail_item(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<DetailResp>> {
1243 let result = Self::find_detail_items(filter, None, None, funs, ctx).await?;
1244 if result.len() > 1 {
1245 Err(funs.err().conflict(&Self::get_obj_name(), "find_one_detail", "found multiple records", "409-rbum-*-obj-multi-exist"))
1246 } else {
1247 Ok(result.into_iter().next())
1248 }
1249 }
1250
1251 async fn find_detail_items(
1255 filter: &ItemFilterReq,
1256 desc_sort_by_create: Option<bool>,
1257 desc_sort_by_update: Option<bool>,
1258 funs: &TardisFunsInst,
1259 ctx: &TardisContext,
1260 ) -> TardisResult<Vec<DetailResp>> {
1261 Self::do_find_detail_items(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await
1262 }
1263
1264 async fn do_find_detail_items(
1272 filter: &ItemFilterReq,
1273 desc_sort_by_create: Option<bool>,
1274 desc_sort_by_update: Option<bool>,
1275 funs: &TardisFunsInst,
1276 ctx: &TardisContext,
1277 ) -> TardisResult<Vec<DetailResp>> {
1278 let mut query = Self::package_item_query(true, filter, funs, ctx).await?;
1279 query.inner_join(
1280 Alias::new(Self::get_ext_table_name()),
1281 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1282 );
1283 Self::package_ext_query(&mut query, true, filter, funs, ctx).await?;
1284 if let Some(sort) = desc_sort_by_create {
1285 query.order_by((rbum_item::Entity, CREATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1286 }
1287 if let Some(sort) = desc_sort_by_update {
1288 query.order_by((rbum_item::Entity, UPDATE_TIME_FIELD.clone()), if sort { Order::Desc } else { Order::Asc });
1289 }
1290 Ok(funs.db().find_dtos(&query).await?)
1291 }
1292
1293 async fn count_items(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
1297 Self::do_count_items(filter, funs, ctx).await
1298 }
1299
1300 async fn do_count_items(filter: &ItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
1308 let mut query = Self::package_item_query(false, filter, funs, ctx).await?;
1309 query.inner_join(
1310 Alias::new(Self::get_ext_table_name()),
1311 Expr::col((Alias::new(Self::get_ext_table_name()), ID_FIELD.clone())).equals((rbum_item::Entity, rbum_item::Column::Id)),
1312 );
1313 Self::package_ext_query(&mut query, false, filter, funs, ctx).await?;
1314 funs.db().count(&query).await
1315 }
1316
1317 async fn is_disabled(id: &str, funs: &TardisFunsInst) -> TardisResult<bool> {
1321 #[derive(Debug, sea_orm::FromQueryResult)]
1322 pub struct StatusResp {
1323 pub disabled: bool,
1324 }
1325 let result =
1326 funs.db().get_dto::<StatusResp>(Query::select().column(rbum_item::Column::Disabled).from(rbum_item::Entity).and_where(Expr::col(rbum_item::Column::Id).eq(id))).await?;
1327 if let Some(result) = result {
1328 Ok(result.disabled)
1329 } else {
1330 Err(funs.err().not_found(
1331 &Self::get_obj_name(),
1332 "is_disabled",
1333 &format!("not found {}.{}", Self::get_obj_name(), id),
1334 "404-rbum-*-obj-not-exist",
1335 ))
1336 }
1337 }
1338}
1339
1340#[async_trait]
1341impl RbumCrudOperation<rbum_item_attr::ActiveModel, RbumItemAttrAddReq, RbumItemAttrModifyReq, RbumItemAttrSummaryResp, RbumItemAttrDetailResp, RbumItemAttrFilterReq>
1342 for RbumItemAttrServ
1343{
1344 fn get_table_name() -> &'static str {
1345 rbum_item_attr::Entity.table_name()
1346 }
1347
1348 async fn before_add_rbum(add_req: &mut RbumItemAttrAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
1349 Self::check_scope(&add_req.rel_rbum_item_id, RbumItemServ::get_table_name(), funs, ctx).await?;
1350 Self::check_scope(&add_req.rel_rbum_kind_attr_id, RbumKindAttrServ::get_table_name(), funs, ctx).await?;
1351 let rbum_kind_attr = RbumKindAttrServ::peek_rbum(&add_req.rel_rbum_kind_attr_id, &RbumKindAttrFilterReq::default(), funs, ctx).await?;
1352 if rbum_kind_attr.main_column {
1353 return Err(funs.err().bad_request(
1354 &Self::get_obj_name(),
1355 "add",
1356 "extension fields located in main table cannot be added using this function",
1357 "400-rbum-kind-attr-main-illegal",
1358 ));
1359 }
1360 if rbum_kind_attr.idx {
1361 return Err(funs.err().bad_request(
1362 &Self::get_obj_name(),
1363 "add",
1364 "index extension fields cannot be added using this function",
1365 "400-rbum-kind-attr-idx-illegal",
1366 ));
1367 }
1368 Ok(())
1369 }
1370
1371 async fn package_add(add_req: &RbumItemAttrAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_item_attr::ActiveModel> {
1372 Ok(rbum_item_attr::ActiveModel {
1373 id: Set(TardisFuns::field.nanoid()),
1374 value: Set(add_req.value.to_string()),
1375 rel_rbum_item_id: Set(add_req.rel_rbum_item_id.to_string()),
1376 rel_rbum_kind_attr_id: Set(add_req.rel_rbum_kind_attr_id.to_string()),
1377 ..Default::default()
1378 })
1379 }
1380
1381 async fn package_modify(id: &str, modify_req: &RbumItemAttrModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_item_attr::ActiveModel> {
1382 Ok(rbum_item_attr::ActiveModel {
1383 id: Set(id.to_string()),
1384 value: Set(modify_req.value.to_string()),
1385 ..Default::default()
1386 })
1387 }
1388
1389 async fn package_query(is_detail: bool, filter: &RbumItemAttrFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
1390 let mut query = Query::select();
1391 query
1392 .columns(vec![
1393 (rbum_item_attr::Entity, rbum_item_attr::Column::Id),
1394 (rbum_item_attr::Entity, rbum_item_attr::Column::Value),
1395 (rbum_item_attr::Entity, rbum_item_attr::Column::RelRbumItemId),
1396 (rbum_item_attr::Entity, rbum_item_attr::Column::RelRbumKindAttrId),
1397 (rbum_item_attr::Entity, rbum_item_attr::Column::OwnPaths),
1398 (rbum_item_attr::Entity, rbum_item_attr::Column::Owner),
1399 (rbum_item_attr::Entity, rbum_item_attr::Column::CreateTime),
1400 (rbum_item_attr::Entity, rbum_item_attr::Column::UpdateTime),
1401 ])
1402 .expr_as(Expr::col((rbum_kind_attr::Entity, rbum_kind_attr::Column::Name)), Alias::new("rel_rbum_kind_attr_name"))
1403 .from(rbum_item_attr::Entity)
1404 .inner_join(
1405 rbum_kind_attr::Entity,
1406 Expr::col((rbum_kind_attr::Entity, rbum_kind_attr::Column::Id)).equals((rbum_item_attr::Entity, rbum_item_attr::Column::RelRbumKindAttrId)),
1407 );
1408 if let Some(rel_rbum_item_id) = &filter.rel_rbum_item_id {
1409 query.and_where(Expr::col((rbum_item_attr::Entity, rbum_item_attr::Column::RelRbumItemId)).eq(rel_rbum_item_id.to_string()));
1410 }
1411 if let Some(rel_rbum_kind_attr_id) = &filter.rel_rbum_kind_attr_id {
1412 query.and_where(Expr::col((rbum_item_attr::Entity, rbum_item_attr::Column::RelRbumKindAttrId)).eq(rel_rbum_kind_attr_id.to_string()));
1413 }
1414 query.with_filter(Self::get_table_name(), &filter.basic, is_detail, false, ctx);
1415 Ok(query)
1416 }
1417}
1418
1419impl RbumItemAttrServ {
1420 async fn find_res_kind_id_and_res_kind_attrs_by_item_id(
1424 rbum_item_id: &str,
1425 secret: Option<bool>,
1426 funs: &TardisFunsInst,
1427 ctx: &TardisContext,
1428 ) -> TardisResult<(String, Vec<RbumKindAttrSummaryResp>)> {
1429 let rel_rbum_kind_id = RbumItemServ::peek_rbum(
1430 rbum_item_id,
1431 &RbumBasicFilterReq {
1432 with_sub_own_paths: true,
1433 ..Default::default()
1434 },
1435 funs,
1436 ctx,
1437 )
1438 .await?
1439 .rel_rbum_kind_id;
1440 let rbum_kind_attrs = RbumKindAttrServ::find_rbums(
1441 &RbumKindAttrFilterReq {
1442 basic: RbumBasicFilterReq {
1443 rbum_kind_id: Some(rel_rbum_kind_id.clone()),
1444 ..Default::default()
1445 },
1446 secret,
1447 ..Default::default()
1448 },
1449 None,
1450 None,
1451 funs,
1452 ctx,
1453 )
1454 .await?;
1455 Ok((rel_rbum_kind_id, rbum_kind_attrs))
1456 }
1457
1458 pub async fn add_or_modify_item_attrs(add_req: &RbumItemAttrsAddOrModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
1462 let (rel_rbum_kind_id, rbum_kind_attrs) = Self::find_res_kind_id_and_res_kind_attrs_by_item_id(&add_req.rel_rbum_item_id, None, funs, ctx).await?;
1464 let in_main_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
1465 let in_ext_table_attrs = rbum_kind_attrs.iter().filter(|i| add_req.values.contains_key(&i.name) && !i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
1466 if !in_main_table_attrs.is_empty() {
1467 let main_table_name = RbumKindServ::peek_rbum(&rel_rbum_kind_id, &RbumKindFilterReq::default(), funs, ctx).await?.ext_table_name;
1469
1470 let mut update_statement = Query::update();
1471 update_statement.table(Alias::new(&main_table_name));
1472
1473 for in_main_table_attr in in_main_table_attrs {
1474 let column_val = if in_main_table_attr.secret && !in_main_table_attr.dyn_default_value.is_empty() {
1475 Self::replace_url_placeholder(&in_main_table_attr.dyn_default_value, &add_req.values, funs).await?
1476 } else if in_main_table_attr.secret {
1477 in_main_table_attr.default_value.clone()
1478 } else {
1479 add_req.values.get(&in_main_table_attr.name).expect("ignore").clone()
1480 };
1481
1482 let column_name = Alias::new(&in_main_table_attr.name);
1483 update_statement.value(column_name, Value::from(column_val));
1484 }
1485 update_statement.and_where(Expr::col(ID_FIELD.clone()).eq(add_req.rel_rbum_item_id.as_str()));
1486 funs.db().execute(&update_statement).await?;
1487 }
1488
1489 if !in_ext_table_attrs.is_empty() {
1490 for in_ext_table_attr in in_ext_table_attrs {
1491 let column_val = if in_ext_table_attr.secret && !in_ext_table_attr.dyn_default_value.is_empty() {
1492 Self::replace_url_placeholder(&in_ext_table_attr.dyn_default_value, &add_req.values, funs).await?
1493 } else if in_ext_table_attr.secret {
1494 in_ext_table_attr.default_value.clone()
1495 } else {
1496 add_req.values.get(&in_ext_table_attr.name).expect("ignore").clone()
1497 };
1498
1499 let exist_item_attr_ids = Self::find_id_rbums(
1500 &RbumItemAttrFilterReq {
1501 basic: Default::default(),
1502 rel_rbum_item_id: Some(add_req.rel_rbum_item_id.to_string()),
1503 rel_rbum_kind_attr_id: Some(in_ext_table_attr.id.to_string()),
1504 },
1505 None,
1506 None,
1507 funs,
1508 ctx,
1509 )
1510 .await?;
1511 if exist_item_attr_ids.is_empty() {
1512 Self::add_rbum(
1513 &mut RbumItemAttrAddReq {
1514 value: column_val,
1515 rel_rbum_item_id: add_req.rel_rbum_item_id.to_string(),
1516 rel_rbum_kind_attr_id: in_ext_table_attr.id.to_string(),
1517 },
1518 funs,
1519 ctx,
1520 )
1521 .await?;
1522 } else {
1523 Self::modify_rbum(exist_item_attr_ids.first().expect("ignore"), &mut RbumItemAttrModifyReq { value: column_val }, funs, ctx).await?;
1524 }
1525 }
1526 }
1527
1528 Ok(())
1529 }
1530
1531 pub async fn find_item_attr_values(rbum_item_id: &str, secret: Option<bool>, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<HashMap<String, String>> {
1539 let (rel_rbum_kind_id, rbum_kind_attrs) = Self::find_res_kind_id_and_res_kind_attrs_by_item_id(rbum_item_id, secret, funs, ctx).await?;
1540 let in_main_table_attrs = rbum_kind_attrs.iter().filter(|i| i.main_column).collect::<Vec<&RbumKindAttrSummaryResp>>();
1541 let has_in_ext_table_attrs = rbum_kind_attrs.iter().any(|i| !i.main_column);
1542
1543 let mut values: HashMap<String, String> = HashMap::new();
1544 if !in_main_table_attrs.is_empty() {
1545 let ext_table_name = RbumKindServ::peek_rbum(&rel_rbum_kind_id, &RbumKindFilterReq::default(), funs, ctx).await?.ext_table_name;
1546
1547 let mut select_statement = Query::select();
1548 select_statement.from(Alias::new(&ext_table_name));
1549 for in_main_table_attr in &in_main_table_attrs {
1550 let column_name = Alias::new(&in_main_table_attr.name);
1551 select_statement.column(column_name);
1552 }
1553 select_statement.and_where(Expr::col(ID_FIELD.clone()).eq(rbum_item_id));
1554 let select_statement = funs.db().raw_conn().get_database_backend().build(&select_statement);
1555 if let Some(row) = funs.db().raw_conn().query_one(select_statement).await? {
1556 for in_main_table_attr in &in_main_table_attrs {
1557 let value: String = row.try_get("", &in_main_table_attr.name)?;
1558 values.insert(in_main_table_attr.name.clone(), value);
1559 }
1560 }
1561 }
1562
1563 if has_in_ext_table_attrs {
1564 let attr_values = Self::find_rbums(
1565 &RbumItemAttrFilterReq {
1566 rel_rbum_item_id: Some(rbum_item_id.to_string()),
1567 ..Default::default()
1568 },
1569 None,
1570 None,
1571 funs,
1572 ctx,
1573 )
1574 .await?;
1575 for attr_value in attr_values {
1576 values.insert(attr_value.rel_rbum_kind_attr_name, attr_value.value);
1577 }
1578 }
1579 Ok(values)
1580 }
1581
1582 async fn replace_url_placeholder(url: &str, values: &HashMap<String, String>, funs: &TardisFunsInst) -> TardisResult<String> {
1583 let resp = if RbumKindAttrServ::url_has_placeholder(url)? {
1584 let url: String = RbumKindAttrServ::url_replace(url, values)?;
1585 if RbumKindAttrServ::url_has_placeholder(&url)? {
1586 return Err(funs.err().bad_request(
1587 &Self::get_obj_name(),
1588 "replace_url_placeholder",
1589 "url processing failure",
1590 "400-rbum-kind-attr-dyn-url-illegal",
1591 ));
1592 }
1593 funs.web_client().get_to_str(&url, None).await
1594 } else {
1595 funs.web_client().get_to_str(url, None).await
1596 };
1597 match resp {
1598 Ok(resp) => Ok(resp.body.unwrap_or_else(|| "".to_string())),
1599 Err(e) => {
1600 return Err(funs.err().bad_request(
1601 &Self::get_obj_name(),
1602 "replace_url_placeholder",
1603 &format!("url processing failure: {}", e),
1604 "400-rbum-kind-attr-dyn-url-illegal",
1605 ));
1606 }
1607 }
1608 }
1609}
1610
1611#[derive(Debug, sea_orm::FromQueryResult)]
1612pub struct CodeResp {
1613 pub code: String,
1614}