1use std::collections::{HashMap, HashSet};
2use std::time::Duration;
3
4use crate::rbum::domain::{rbum_cert, rbum_item, rbum_rel, rbum_set, rbum_set_cate, rbum_set_item};
5use crate::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumKindFilterReq, RbumSetCateFilterReq, RbumSetFilterReq, RbumSetItemFilterReq, RbumSetTreeFilterReq};
6use crate::rbum::dto::rbum_set_cate_dto::{RbumSetCateAddReq, RbumSetCateDetailResp, RbumSetCateModifyReq, RbumSetCateSummaryResp};
7use crate::rbum::dto::rbum_set_dto::{
8 RbumSetAddReq, RbumSetDetailResp, RbumSetModifyReq, RbumSetPathResp, RbumSetSummaryResp, RbumSetTreeExtResp, RbumSetTreeNodeResp, RbumSetTreeResp,
9};
10use crate::rbum::dto::rbum_set_item_dto::{RbumSetItemAddReq, RbumSetItemDetailResp, RbumSetItemModifyReq, RbumSetItemRelInfoResp, RbumSetItemSummaryResp};
11use crate::rbum::rbum_config::RbumConfigApi;
12use crate::rbum::rbum_enumeration::{RbumCertRelKind, RbumRelFromKind, RbumScopeLevelKind, RbumSetCateLevelQueryKind};
13use crate::rbum::serv::rbum_cert_serv::RbumCertServ;
14use crate::rbum::serv::rbum_crud_serv::{RbumCrudOperation, RbumCrudQueryPackage};
15use crate::rbum::serv::rbum_domain_serv::RbumDomainServ;
16use crate::rbum::serv::rbum_item_serv::RbumItemServ;
17use crate::rbum::serv::rbum_kind_serv::RbumKindServ;
18use crate::rbum::serv::rbum_rel_serv::RbumRelServ;
19use async_recursion::async_recursion;
20use async_trait::async_trait;
21use itertools::Itertools;
22use tardis::basic::dto::TardisContext;
23use tardis::basic::result::TardisResult;
24use tardis::db::sea_orm::sea_query::*;
25use tardis::db::sea_orm::*;
26use tardis::db::sea_orm::{self, IdenStatic};
27use tardis::tokio::time::sleep;
28use tardis::{TardisFuns, TardisFunsInst};
29
30pub struct RbumSetServ;
31
32pub struct RbumSetCateServ;
33
34pub struct RbumSetItemServ;
35
36#[async_trait]
37impl RbumCrudOperation<rbum_set::ActiveModel, RbumSetAddReq, RbumSetModifyReq, RbumSetSummaryResp, RbumSetDetailResp, RbumSetFilterReq> for RbumSetServ {
38 fn get_table_name() -> &'static str {
39 rbum_set::Entity.table_name()
40 }
41
42 async fn package_add(add_req: &RbumSetAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_set::ActiveModel> {
43 Ok(rbum_set::ActiveModel {
44 id: Set(TardisFuns::field.nanoid()),
45 code: Set(add_req.code.to_string()),
46 kind: Set(add_req.kind.to_string()),
47 name: Set(add_req.name.to_string()),
48 note: Set(add_req.note.as_ref().unwrap_or(&"".to_string()).to_string()),
49 icon: Set(add_req.icon.as_ref().unwrap_or(&"".to_string()).to_string()),
50 sort: Set(add_req.sort.unwrap_or(0)),
51 ext: Set(add_req.ext.as_ref().unwrap_or(&"".to_string()).to_string()),
52 scope_level: Set(add_req.scope_level.as_ref().unwrap_or(&RbumScopeLevelKind::Private).to_int()),
53 disabled: Set(add_req.disabled.unwrap_or(false)),
54 ..Default::default()
55 })
56 }
57
58 async fn package_modify(id: &str, modify_req: &RbumSetModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_set::ActiveModel> {
59 let mut rbum_set = rbum_set::ActiveModel {
60 id: Set(id.to_string()),
61 ..Default::default()
62 };
63 if let Some(name) = &modify_req.name {
64 rbum_set.name = Set(name.to_string());
65 }
66 if let Some(note) = &modify_req.note {
67 rbum_set.note = Set(note.to_string());
68 }
69 if let Some(icon) = &modify_req.icon {
70 rbum_set.icon = Set(icon.to_string());
71 }
72 if let Some(sort) = modify_req.sort {
73 rbum_set.sort = Set(sort);
74 }
75 if let Some(ext) = &modify_req.ext {
76 rbum_set.ext = Set(ext.to_string());
77 }
78 if let Some(scope_level) = &modify_req.scope_level {
79 rbum_set.scope_level = Set(scope_level.to_int());
80 }
81 if let Some(disabled) = modify_req.disabled {
82 rbum_set.disabled = Set(disabled);
83 }
84 Ok(rbum_set)
85 }
86
87 async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumSetDetailResp>> {
88 Self::check_ownership(id, funs, ctx).await?;
89 Self::check_exist_before_delete(id, RbumSetCateServ::get_table_name(), rbum_set_cate::Column::RelRbumSetId.as_str(), funs).await?;
93 Self::check_exist_before_delete(id, RbumSetItemServ::get_table_name(), rbum_set_item::Column::RelRbumSetId.as_str(), funs).await?;
94 Self::check_exist_with_cond_before_delete(
95 RbumRelServ::get_table_name(),
96 any![
97 all![
98 Expr::col(rbum_rel::Column::FromRbumKind).eq(RbumRelFromKind::Set.to_int()),
99 Expr::col(rbum_rel::Column::FromRbumId).eq(id)
100 ],
101 Expr::col(rbum_rel::Column::ToRbumItemId).eq(id)
102 ],
103 funs,
104 )
105 .await?;
106 Self::check_exist_with_cond_before_delete(
107 RbumCertServ::get_table_name(),
108 all![
109 Expr::col(rbum_cert::Column::RelRbumKind).eq(RbumCertRelKind::Set.to_int()),
110 Expr::col(rbum_cert::Column::RelRbumId).eq(id)
111 ],
112 funs,
113 )
114 .await?;
115 let result = Self::peek_rbum(
117 id,
118 &RbumSetFilterReq {
119 basic: RbumBasicFilterReq {
120 with_sub_own_paths: true,
121 ..Default::default()
122 },
123 ..Default::default()
124 },
125 funs,
126 ctx,
127 )
128 .await?;
129 let key = &format!("{}{}", funs.rbum_conf_cache_key_set_code_(), result.code);
130 funs.cache().del(key).await?;
131 Ok(None)
132 }
133
134 async fn package_query(is_detail: bool, filter: &RbumSetFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
135 let mut query = Query::select();
136 query
137 .columns(vec![
138 (rbum_set::Entity, rbum_set::Column::Id),
139 (rbum_set::Entity, rbum_set::Column::Code),
140 (rbum_set::Entity, rbum_set::Column::Kind),
141 (rbum_set::Entity, rbum_set::Column::Name),
142 (rbum_set::Entity, rbum_set::Column::Note),
143 (rbum_set::Entity, rbum_set::Column::Icon),
144 (rbum_set::Entity, rbum_set::Column::Sort),
145 (rbum_set::Entity, rbum_set::Column::Ext),
146 (rbum_set::Entity, rbum_set::Column::Disabled),
147 (rbum_set::Entity, rbum_set::Column::OwnPaths),
148 (rbum_set::Entity, rbum_set::Column::Owner),
149 (rbum_set::Entity, rbum_set::Column::CreateTime),
150 (rbum_set::Entity, rbum_set::Column::UpdateTime),
151 (rbum_set::Entity, rbum_set::Column::ScopeLevel),
152 ])
153 .from(rbum_set::Entity);
154 if let Some(kind) = &filter.kind {
155 query.and_where(Expr::col((rbum_set::Entity, rbum_set::Column::Kind)).eq(kind.to_string()));
156 }
157 if let Some(rbum_item_rel_filter_req) = &filter.rel {
158 if rbum_item_rel_filter_req.rel_by_from {
159 query.inner_join(
160 rbum_rel::Entity,
161 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).equals((rbum_set::Entity, rbum_set::Column::Id)),
162 );
163 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
164 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(rel_item_id.to_string()));
165 }
166 } else {
167 query.inner_join(
168 rbum_rel::Entity,
169 Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).equals((rbum_set::Entity, rbum_set::Column::Id)),
170 );
171 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
172 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).eq(rel_item_id.to_string()));
173 }
174 }
175 if let Some(tag) = &rbum_item_rel_filter_req.tag {
176 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Tag)).eq(tag.to_string()));
177 }
178 if let Some(from_rbum_kind) = &rbum_item_rel_filter_req.from_rbum_kind {
179 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(from_rbum_kind.to_int()));
180 }
181 }
182 query.with_filter(Self::get_table_name(), &filter.basic, is_detail, true, ctx);
183 Ok(query)
184 }
185}
186
187impl RbumSetServ {
188 pub async fn get_tree(rbum_set_id: &str, filter: &RbumSetTreeFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<RbumSetTreeResp> {
192 Self::check_scope(rbum_set_id, RbumSetServ::get_table_name(), funs, ctx).await?;
193 if let Some(sys_codes) = &filter.sys_codes {
195 let sys_code_vec: Vec<String> = sys_codes.iter().filter(|sys_code| !sys_code.is_empty()).map(|sys_code| sys_code.to_string()).collect();
196 if !sys_code_vec.is_empty() {
197 let tmp_set_ids = vec![rbum_set_id.to_string()];
198 let values = HashMap::from([("rel_rbum_set_id".to_string(), &tmp_set_ids), ("sys_code".to_string(), &sys_code_vec)]);
199 Self::check_scopes(values, sys_code_vec.len() as u64, RbumSetCateServ::get_table_name(), funs, ctx).await?;
200 }
201 }
202 let set_cate_sys_code_node_len = funs.rbum_conf_set_cate_sys_code_node_len();
203 let mut rbum_set_cates = RbumSetCateServ::find_rbums(
204 &RbumSetCateFilterReq {
205 basic: RbumBasicFilterReq {
206 with_sub_own_paths: true,
207 ..Default::default()
208 },
209 rel_rbum_set_id: Some(rbum_set_id.to_string()),
210 sys_codes: filter.sys_codes.clone(),
211 sys_code_query_kind: filter.sys_code_query_kind.clone(),
212 sys_code_query_depth: filter.sys_code_query_depth,
213 cate_exts: filter.cate_exts.clone(),
214 ..Default::default()
215 },
216 None,
217 None,
218 funs,
219 ctx,
220 )
221 .await?;
222 rbum_set_cates.sort_by(|a, b| a.sys_code.cmp(&b.sys_code));
223 rbum_set_cates.sort_by(|a, b| a.sort.cmp(&b.sort));
224 let mut tree_main = rbum_set_cates
225 .iter()
226 .map(|r| RbumSetTreeNodeResp {
227 id: r.id.to_string(),
228 sys_code: r.sys_code.to_string(),
229 bus_code: r.bus_code.to_string(),
230 name: r.name.to_string(),
231 icon: r.icon.to_string(),
232 sort: r.sort,
233 ext: r.ext.to_string(),
234 own_paths: r.own_paths.to_string(),
235 owner: r.owner.to_string(),
236 scope_level: r.scope_level.clone(),
237 pid: rbum_set_cates.iter().find(|i| i.sys_code == r.sys_code[..r.sys_code.len() - set_cate_sys_code_node_len]).map(|i| i.id.to_string()),
238 rel: None,
239 create_time: r.create_time,
240 update_time: r.update_time,
241 })
242 .collect();
243 if !filter.fetch_cate_item {
244 return Ok(RbumSetTreeResp { main: tree_main, ext: None });
245 }
246 let rel_rbum_item_disabled = if filter.hide_item_with_disabled { Some(false) } else { None };
247 let rbum_set_items = RbumSetItemServ::find_detail_rbums(
248 &RbumSetItemFilterReq {
249 basic: RbumBasicFilterReq {
250 own_paths: Some("".to_string()),
257 with_sub_own_paths: true,
258 ..Default::default()
259 },
260 rel_rbum_set_id: Some(rbum_set_id.to_string()),
261 rel_rbum_item_can_not_exist: Some(true),
262 sys_code_query_kind: filter.sys_code_query_kind.clone(),
263 sys_code_query_depth: filter.sys_code_query_depth,
264 rel_rbum_set_cate_sys_codes: filter.sys_codes.clone(),
265 rel_rbum_item_ids: filter.rel_rbum_item_ids.clone(),
266 rel_rbum_item_kind_ids: filter.rel_rbum_item_kind_ids.clone(),
267 rel_rbum_item_domain_ids: filter.rel_rbum_item_domain_ids.clone(),
268 rel_rbum_item_disabled,
269 ..Default::default()
270 },
271 None,
272 None,
273 funs,
274 ctx,
275 )
276 .await?;
277 if filter.hide_cate_with_empty_item {
278 let cate_ids_has_item =
282 tree_main.iter().filter(|cate| cate.pid.is_none()).flat_map(|cate| Self::filter_exist_items(&tree_main, &cate.id, &rbum_set_items)).collect::<Vec<String>>();
283 tree_main.retain(|cate| cate_ids_has_item.contains(&cate.id));
284 }
285 let mut items = tree_main
286 .iter()
287 .map(|cate| {
288 (
289 cate.id.clone(),
290 rbum_set_items
291 .iter()
292 .filter(|i| i.rel_rbum_set_cate_id.clone().unwrap_or_default() == cate.id)
293 .map(|i| RbumSetItemRelInfoResp {
294 id: i.id.to_string(),
295 sort: i.sort,
296 rel_rbum_item_id: i.rel_rbum_item_id.to_string(),
297 rel_rbum_item_code: i.rel_rbum_item_code.to_string(),
298 rel_rbum_item_name: i.rel_rbum_item_name.to_string(),
299 rel_rbum_item_kind_id: i.rel_rbum_item_kind_id.to_string(),
300 rel_rbum_item_domain_id: i.rel_rbum_item_domain_id.to_string(),
301 rel_rbum_item_owner: i.rel_rbum_item_owner.to_string(),
302 rel_rbum_item_create_time: i.rel_rbum_item_create_time,
303 rel_rbum_item_update_time: i.rel_rbum_item_update_time,
304 rel_rbum_item_disabled: i.rel_rbum_item_disabled,
305 rel_rbum_item_scope_level: i.rel_rbum_item_scope_level.clone(),
306 own_paths: i.own_paths.to_string(),
307 owner: i.owner.to_string(),
308 })
309 .collect(),
310 )
311 })
312 .collect::<HashMap<String, Vec<RbumSetItemRelInfoResp>>>();
313 items.insert(
314 "".to_string(),
315 rbum_set_items
316 .iter()
317 .filter(|i| i.rel_rbum_set_cate_id.is_none())
318 .map(|i| RbumSetItemRelInfoResp {
319 id: i.id.to_string(),
320 sort: i.sort,
321 rel_rbum_item_id: i.rel_rbum_item_id.to_string(),
322 rel_rbum_item_code: i.rel_rbum_item_code.to_string(),
323 rel_rbum_item_name: i.rel_rbum_item_name.to_string(),
324 rel_rbum_item_kind_id: i.rel_rbum_item_kind_id.to_string(),
325 rel_rbum_item_domain_id: i.rel_rbum_item_domain_id.to_string(),
326 rel_rbum_item_owner: i.rel_rbum_item_owner.to_string(),
327 rel_rbum_item_create_time: i.rel_rbum_item_create_time,
328 rel_rbum_item_update_time: i.rel_rbum_item_update_time,
329 rel_rbum_item_disabled: i.rel_rbum_item_disabled,
330 rel_rbum_item_scope_level: i.rel_rbum_item_scope_level.clone(),
331 own_paths: i.own_paths.to_string(),
332 owner: i.owner.to_string(),
333 })
334 .collect(),
335 );
336 let mut item_number_agg = tree_main
337 .iter()
338 .map(|cate| {
339 (
340 cate.id.to_string(),
341 tree_main
342 .iter()
343 .filter(|c| c.sys_code.starts_with(&cate.sys_code))
344 .flat_map(|c| items.get(&c.id).expect("ignore"))
345 .chunk_by(|c| c.rel_rbum_item_kind_id.clone())
346 .into_iter()
347 .map(|(g, c)| (g, c.map(|i| i.rel_rbum_item_id.clone()).collect::<HashSet<String>>().len() as u64))
348 .collect::<HashMap<String, u64>>(),
349 )
350 })
351 .collect::<HashMap<String, HashMap<String, u64>>>();
352 item_number_agg.insert(
354 "".to_string(),
355 items
356 .values()
357 .flat_map(|item| item.iter())
358 .chunk_by(|c| c.rel_rbum_item_kind_id.clone())
359 .into_iter()
360 .map(|(g, c)| (g, c.map(|i| i.rel_rbum_item_id.clone()).collect::<HashSet<String>>().len() as u64))
361 .collect::<HashMap<String, u64>>(),
362 );
363 let kind_ids = Vec::from_iter(items.values().flat_map(|items| items.iter().map(|item| item.rel_rbum_item_kind_id.clone())).collect::<HashSet<String>>());
364 let item_kinds = RbumKindServ::find_rbums(
365 &RbumKindFilterReq {
366 basic: RbumBasicFilterReq {
367 ids: Some(kind_ids),
368 ..Default::default()
369 },
370 ..Default::default()
371 },
372 None,
373 None,
374 funs,
375 ctx,
376 )
377 .await?
378 .into_iter()
379 .map(|kind| (kind.id.clone(), kind))
380 .collect();
381
382 let domain_ids: Vec<String> = Vec::from_iter(items.values().flat_map(|items| items.iter().map(|item| item.rel_rbum_item_domain_id.clone())).collect::<HashSet<String>>());
383 let item_domains = RbumDomainServ::find_rbums(
384 &RbumBasicFilterReq {
385 ids: Some(domain_ids),
386 ..Default::default()
387 },
388 None,
389 None,
390 funs,
391 ctx,
392 )
393 .await?
394 .into_iter()
395 .map(|domain| (domain.id.clone(), domain))
396 .collect();
397
398 Ok(RbumSetTreeResp {
399 main: tree_main,
400 ext: Some(RbumSetTreeExtResp {
401 items,
402 item_number_agg,
403 item_kinds,
404 item_domains,
405 }),
406 })
407 }
408
409 fn filter_exist_items(tree_main: &Vec<RbumSetTreeNodeResp>, cate_id: &str, rbum_set_items: &Vec<RbumSetItemDetailResp>) -> Vec<String> {
414 let mut sub_cates = tree_main
415 .iter()
416 .filter(|cate| cate.pid == Some(cate_id.to_string()))
417 .flat_map(|cate| Self::filter_exist_items(tree_main, &cate.id, rbum_set_items))
418 .collect::<Vec<String>>();
419 let cate = tree_main.iter().find(|cate| cate.id == cate_id).expect("ignore");
420 if sub_cates.is_empty() {
421 if !rbum_set_items.iter().any(|item| item.rel_rbum_set_cate_id.clone().unwrap_or_default() == cate.id) {
423 vec![]
424 } else {
425 vec![cate.id.to_string()]
426 }
427 } else {
428 sub_cates.insert(0, cate.id.to_string());
429 sub_cates
430 }
431 }
432
433 pub async fn get_rbum_set_id_by_code(code: &str, with_sub: bool, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<String>> {
437 let key = &format!("{}{}", funs.rbum_conf_cache_key_set_code_(), code);
438 if let Some(cached_id) = funs.cache().get(key).await? {
439 Ok(Some(cached_id))
440 } else if let Some(rbum_set) = Self::find_one_rbum(
441 &RbumSetFilterReq {
442 basic: RbumBasicFilterReq {
443 code: Some(code.to_string()),
444 with_sub_own_paths: with_sub,
445 ..Default::default()
446 },
447 ..Default::default()
448 },
449 funs,
450 ctx,
451 )
452 .await?
453 {
454 funs.cache().set_ex(key, &rbum_set.id, funs.rbum_conf_cache_key_set_code_expire_sec() as u64).await?;
455 Ok(Some(rbum_set.id))
456 } else {
457 Ok(None)
458 }
459 }
460}
461
462#[async_trait]
463impl RbumCrudOperation<rbum_set_cate::ActiveModel, RbumSetCateAddReq, RbumSetCateModifyReq, RbumSetCateSummaryResp, RbumSetCateDetailResp, RbumSetCateFilterReq>
464 for RbumSetCateServ
465{
466 fn get_table_name() -> &'static str {
467 rbum_set_cate::Entity.table_name()
468 }
469
470 async fn before_add_rbum(add_req: &mut RbumSetCateAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
471 Self::check_scope(&add_req.rel_rbum_set_id, RbumSetServ::get_table_name(), funs, ctx).await?;
472 if let Some(rbum_parent_cate_id) = &add_req.rbum_parent_cate_id {
473 Self::check_scope(rbum_parent_cate_id, RbumSetCateServ::get_table_name(), funs, ctx).await?;
474 }
475 Ok(())
476 }
477
478 async fn package_add(add_req: &RbumSetCateAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<rbum_set_cate::ActiveModel> {
479 let sys_code = Self::package_sys_code(&add_req.rel_rbum_set_id, add_req.rbum_parent_cate_id.as_deref(), funs, ctx).await?;
480 Ok(rbum_set_cate::ActiveModel {
481 id: Set(TardisFuns::field.nanoid()),
482 sys_code: Set(sys_code),
483 bus_code: Set(add_req.bus_code.to_string()),
484 name: Set(add_req.name.to_string()),
485 icon: Set(add_req.icon.as_ref().unwrap_or(&"".to_string()).to_string()),
486 sort: Set(add_req.sort.unwrap_or(0)),
487 ext: Set(add_req.ext.as_ref().unwrap_or(&"".to_string()).to_string()),
488 rel_rbum_set_id: Set(add_req.rel_rbum_set_id.to_string()),
489 scope_level: Set(add_req.scope_level.as_ref().unwrap_or(&RbumScopeLevelKind::Private).to_int()),
490 ..Default::default()
491 })
492 }
493
494 async fn package_modify(id: &str, modify_req: &RbumSetCateModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<rbum_set_cate::ActiveModel> {
495 let mut rbum_set_cate = rbum_set_cate::ActiveModel {
496 id: Set(id.to_string()),
497 ..Default::default()
498 };
499 if let Some(rbum_parent_cate_id) = &modify_req.rbum_parent_cate_id {
500 if let Some(detail) = Self::find_one_detail_rbum(
501 &RbumSetCateFilterReq {
502 basic: RbumBasicFilterReq {
503 ids: Some(vec![rbum_parent_cate_id.to_string()]),
504 ..Default::default()
505 },
506 ..Default::default()
507 },
508 funs,
509 ctx,
510 )
511 .await?
512 {
513 let sys_code = Self::package_sys_code(&detail.rel_rbum_set_id, Some(rbum_parent_cate_id.as_str()), funs, ctx).await?;
514 rbum_set_cate.sys_code = Set(sys_code.to_string());
515 }
516 }
517 if let Some(bus_code) = &modify_req.bus_code {
518 rbum_set_cate.bus_code = Set(bus_code.to_string());
519 }
520 if let Some(name) = &modify_req.name {
521 rbum_set_cate.name = Set(name.to_string());
522 }
523 if let Some(icon) = &modify_req.icon {
524 rbum_set_cate.icon = Set(icon.to_string());
525 }
526 if let Some(sort) = modify_req.sort {
527 rbum_set_cate.sort = Set(sort);
528 }
529 if let Some(ext) = &modify_req.ext {
530 rbum_set_cate.ext = Set(ext.to_string());
531 }
532 if let Some(scope_level) = &modify_req.scope_level {
533 rbum_set_cate.scope_level = Set(scope_level.to_int());
534 }
535 Ok(rbum_set_cate)
536 }
537
538 async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumSetCateDetailResp>> {
539 Self::check_ownership(id, funs, ctx).await?;
540 if funs
541 .db()
542 .count(
543 Query::select()
544 .column((rbum_set_item::Entity, rbum_set_item::Column::Id))
545 .from(rbum_set_item::Entity)
546 .inner_join(
547 rbum_set_cate::Entity,
548 Condition::all()
549 .add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)))
550 .add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::RelRbumSetId)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetId))),
551 )
552 .inner_join(
553 rbum_item::Entity,
554 Expr::col((rbum_item::Entity, rbum_item::Column::Id)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId)),
555 )
556 .and_where(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Id)).eq(id))
557 .and_where(Expr::col((rbum_item::Entity, rbum_item::Column::Disabled)).eq(false)),
558 )
559 .await?
560 > 0
561 {
562 return Err(funs.err().conflict(
563 &Self::get_obj_name(),
564 "delete",
565 &format!("can not delete {}.{} when there are associated by set_item", Self::get_obj_name(), id),
566 "409-rbum-*-delete-conflict",
567 ));
568 }
569 let set_cate = Self::peek_rbum(
570 id,
571 &RbumSetCateFilterReq {
572 basic: RbumBasicFilterReq {
573 with_sub_own_paths: true,
574 ..Default::default()
575 },
576 ..Default::default()
577 },
578 funs,
579 ctx,
580 )
581 .await?;
582 if funs
583 .db()
584 .count(
585 Query::select()
586 .column(rbum_set_cate::Column::Id)
587 .from(rbum_set_cate::Entity)
588 .and_where(Expr::col(rbum_set_cate::Column::Id).ne(id))
589 .and_where(Expr::col(rbum_set_cate::Column::RelRbumSetId).eq(set_cate.rel_rbum_set_id.as_str()))
590 .and_where(Expr::col(rbum_set_cate::Column::SysCode).like(format!("{}%", set_cate.sys_code.as_str()).as_str())),
591 )
592 .await?
593 > 0
594 {
595 return Err(funs.err().conflict(
596 &Self::get_obj_name(),
597 "delete",
598 &format!("can not delete {}.{} when there are associated by sub set_cate", Self::get_obj_name(), id),
599 "409-rbum-*-delete-conflict",
600 ));
601 }
602 Ok(None)
603 }
604
605 async fn package_query(is_detail: bool, filter: &RbumSetCateFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
606 let mut query = Query::select();
607 query
608 .columns(vec![
609 (rbum_set_cate::Entity, rbum_set_cate::Column::Id),
610 (rbum_set_cate::Entity, rbum_set_cate::Column::SysCode),
611 (rbum_set_cate::Entity, rbum_set_cate::Column::BusCode),
612 (rbum_set_cate::Entity, rbum_set_cate::Column::Name),
613 (rbum_set_cate::Entity, rbum_set_cate::Column::Icon),
614 (rbum_set_cate::Entity, rbum_set_cate::Column::Sort),
615 (rbum_set_cate::Entity, rbum_set_cate::Column::Ext),
616 (rbum_set_cate::Entity, rbum_set_cate::Column::RelRbumSetId),
617 (rbum_set_cate::Entity, rbum_set_cate::Column::OwnPaths),
618 (rbum_set_cate::Entity, rbum_set_cate::Column::Owner),
619 (rbum_set_cate::Entity, rbum_set_cate::Column::CreateTime),
620 (rbum_set_cate::Entity, rbum_set_cate::Column::UpdateTime),
621 (rbum_set_cate::Entity, rbum_set_cate::Column::ScopeLevel),
622 ])
623 .from(rbum_set_cate::Entity);
624 if let Some(rel_rbum_set_id) = &filter.rel_rbum_set_id {
625 query.and_where(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::RelRbumSetId)).eq(rel_rbum_set_id.to_string()));
626 }
627 if let Some(sys_codes) = &filter.sys_codes {
628 let query_kind = filter.sys_code_query_kind.clone().unwrap_or(RbumSetCateLevelQueryKind::Current);
629 if sys_codes.is_empty() {
630 if query_kind == RbumSetCateLevelQueryKind::Current {
631 query.and_where(Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode))).eq(funs.rbum_conf_set_cate_sys_code_node_len() as i32));
633 }
634 } else {
635 let mut cond = Cond::any();
636 match query_kind {
637 RbumSetCateLevelQueryKind::CurrentAndSub => {
638 if let Some(depth) = filter.sys_code_query_depth {
639 for sys_code in sys_codes {
640 cond = cond.add(all![
641 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).like(format!("{sys_code}%").as_str()),
642 Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode)))
643 .lte((sys_code.len() + funs.rbum_conf_set_cate_sys_code_node_len() * depth as usize) as i32),
644 ]);
645 }
646 } else {
647 for sys_code in sys_codes {
648 cond = cond.add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).like(format!("{sys_code}%").as_str()));
649 }
650 }
651 }
652 RbumSetCateLevelQueryKind::Sub => {
653 if let Some(depth) = filter.sys_code_query_depth {
654 for sys_code in sys_codes {
655 cond = cond.add(all![
656 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).like(format!("{sys_code}%").as_str()),
657 Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode))).gt(sys_code.len() as i32),
658 Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode)))
659 .lte((sys_code.len() + funs.rbum_conf_set_cate_sys_code_node_len() * depth as usize) as i32),
660 ]);
661 }
662 } else {
663 for sys_code in sys_codes {
664 cond = cond.add(all![
665 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).like(format!("{sys_code}%").as_str()),
666 Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode))).gt(sys_code.len() as i32)
667 ]);
668 }
669 }
670 }
671 RbumSetCateLevelQueryKind::CurrentAndParent => {
672 for sys_code in sys_codes {
673 let mut sys_codes = Self::get_parent_sys_codes(sys_code, funs)?;
674 sys_codes.insert(0, sys_code.to_string());
675 cond = cond.add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).is_in(sys_codes));
676 }
677 }
678 RbumSetCateLevelQueryKind::Parent => {
679 for sys_code in sys_codes {
680 let parent_sys_codes = Self::get_parent_sys_codes(sys_code, funs)?;
681 cond = cond.add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).is_in(parent_sys_codes));
682 }
683 }
684 RbumSetCateLevelQueryKind::Current => {
685 for sys_code in sys_codes {
686 cond = cond.add(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).eq(sys_code.as_str()));
687 }
688 }
689 }
690 query.cond_where(all![cond]);
691 }
692 }
693 if let Some(cate_exts) = &filter.cate_exts {
694 query.and_where(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Ext)).is_in(cate_exts.clone()));
695 }
696 if let Some(rbum_item_rel_filter_req) = &filter.rel {
697 if rbum_item_rel_filter_req.rel_by_from {
698 query.inner_join(
699 rbum_rel::Entity,
700 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).equals((rbum_set_cate::Entity, rbum_set_cate::Column::Id)),
701 );
702 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
703 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(rel_item_id.to_string()));
704 }
705 } else {
706 query.inner_join(
707 rbum_rel::Entity,
708 Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).equals((rbum_set_cate::Entity, rbum_set_cate::Column::Id)),
709 );
710 if let Some(rel_item_id) = &rbum_item_rel_filter_req.rel_item_id {
711 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).eq(rel_item_id.to_string()));
712 }
713 }
714 if let Some(tag) = &rbum_item_rel_filter_req.tag {
715 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Tag)).eq(tag.to_string()));
716 }
717 if let Some(from_rbum_kind) = &rbum_item_rel_filter_req.from_rbum_kind {
718 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(from_rbum_kind.to_int()));
719 }
720 }
721 query.with_filter(Self::get_table_name(), &filter.basic, is_detail, true, ctx);
722 query.order_by(rbum_set_cate::Column::Sort, Order::Asc);
723 Ok(query)
724 }
725}
726
727impl RbumSetCateServ {
728 fn get_parent_sys_codes(sys_code: &str, funs: &TardisFunsInst) -> TardisResult<Vec<String>> {
732 let set_cate_sys_code_node_len = funs.rbum_conf_set_cate_sys_code_node_len();
733 let mut level = sys_code.len() / set_cate_sys_code_node_len - 1;
734 if level == 0 {
735 return Ok(vec![]);
736 }
737 let mut sys_code_item = Vec::with_capacity(level);
738 while level != 0 {
739 sys_code_item.push(sys_code[..set_cate_sys_code_node_len * level].to_string());
740 level -= 1;
741 }
742 Ok(sys_code_item)
743 }
744
745 async fn package_sys_code(rbum_set_id: &str, rbum_set_parent_cate_id: Option<&str>, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
749 let lock_key = format!("rbum_set_cate_sys_code_{rbum_set_id}");
750 while !funs.cache().set_nx(&lock_key, "waiting").await? {
751 sleep(Duration::from_millis(100)).await;
752 }
753 funs.cache().expire(&lock_key, 10).await?;
754 let sys_code = if let Some(rbum_set_parent_cate_id) = rbum_set_parent_cate_id {
755 let rel_parent_sys_code = Self::get_sys_code(rbum_set_parent_cate_id, funs, ctx).await?;
756 Self::get_max_sys_code_by_level(rbum_set_id, Some(&rel_parent_sys_code), funs, ctx).await
757 } else {
758 Self::get_max_sys_code_by_level(rbum_set_id, None, funs, ctx).await
759 };
760 funs.cache().del(&lock_key).await?;
761 sys_code
762 }
763
764 async fn get_max_sys_code_by_level(rbum_set_id: &str, parent_sys_code: Option<&str>, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult<String> {
768 let set_cate_sys_code_node_len = funs.rbum_conf_set_cate_sys_code_node_len();
769 let mut query = Query::select();
770 query.columns(vec![(rbum_set_cate::Column::SysCode)]).from(rbum_set_cate::Entity).and_where(Expr::col(rbum_set_cate::Column::RelRbumSetId).eq(rbum_set_id));
771
772 if let Some(parent_sys_code) = parent_sys_code {
773 query.and_where(Expr::col(rbum_set_cate::Column::SysCode).like(format!("{parent_sys_code}%").as_str()));
774 query.and_where(Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode))).eq((parent_sys_code.len() + set_cate_sys_code_node_len) as i32));
775 } else {
776 query.and_where(Expr::expr(Func::char_length(Expr::col(rbum_set_cate::Column::SysCode))).eq(set_cate_sys_code_node_len as i32));
778 }
779 query.order_by(rbum_set_cate::Column::SysCode, Order::Desc);
780 let current_max_sys_code = funs.db().get_dto::<SysCodeResp>(&query).await?.map(|r| r.sys_code);
781 if let Some(current_max_sys_code) = current_max_sys_code {
782 if current_max_sys_code.len() != set_cate_sys_code_node_len {
783 let current_level_sys_code = current_max_sys_code[current_max_sys_code.len() - set_cate_sys_code_node_len..].to_string();
785 let parent_sys_code = current_max_sys_code[..current_max_sys_code.len() - set_cate_sys_code_node_len].to_string();
786 let current_level_sys_code = TardisFuns::field.incr_by_base36(¤t_level_sys_code).ok_or_else(|| {
787 funs.err().bad_request(
788 &Self::get_obj_name(),
789 "get_sys_code",
790 "current number of nodes is saturated",
791 "400-rbum-set-sys-code-saturated",
792 )
793 })?;
794 Ok(format!("{parent_sys_code}{current_level_sys_code}"))
795 } else {
796 Ok(TardisFuns::field.incr_by_base36(¤t_max_sys_code).ok_or_else(|| {
798 funs.err().bad_request(
799 &Self::get_obj_name(),
800 "get_sys_code",
801 "current number of nodes is saturated",
802 "400-rbum-set-sys-code-saturated",
803 )
804 })?)
805 }
806 } else if let Some(parent_sys_code) = parent_sys_code {
807 Ok(format!("{}{}", parent_sys_code, String::from_utf8(vec![b'0'; set_cate_sys_code_node_len])?))
809 } else {
810 Ok(String::from_utf8(vec![b'0'; set_cate_sys_code_node_len])?)
812 }
813 }
814
815 async fn get_sys_code(rbum_set_cate_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
819 Self::check_scope(rbum_set_cate_id, RbumSetCateServ::get_table_name(), funs, ctx).await?;
820 let sys_code = funs
821 .db()
822 .get_dto::<SysCodeResp>(
823 Query::select().column(rbum_set_cate::Column::SysCode).from(rbum_set_cate::Entity).and_where(Expr::col(rbum_set_cate::Column::Id).eq(rbum_set_cate_id)),
824 )
825 .await?
826 .ok_or_else(|| {
827 funs.err().not_found(
828 &Self::get_obj_name(),
829 "get_sys_code",
830 &format!("not found set cate {rbum_set_cate_id}"),
831 "404-rbum-set-cate-not-exist",
832 )
833 })?
834 .sys_code;
835 Ok(sys_code)
836 }
837
838 #[async_recursion]
839 pub async fn move_set_cate(set_cate_id: &str, parent_set_cate_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
840 let set_cate_detail = Self::get_rbum(
841 set_cate_id,
842 &RbumSetCateFilterReq {
843 basic: RbumBasicFilterReq {
844 with_sub_own_paths: true,
845 ..Default::default()
846 },
847 ..Default::default()
848 },
849 funs,
850 ctx,
851 )
852 .await?;
853 let set_item_ids = RbumSetItemServ::find_id_rbums(
854 &RbumSetItemFilterReq {
855 sys_code_query_kind: Some(RbumSetCateLevelQueryKind::Current),
856 rel_rbum_set_cate_sys_codes: Some(vec![set_cate_detail.sys_code.clone()]),
857 ..Default::default()
858 },
859 None,
860 None,
861 funs,
862 ctx,
863 )
864 .await?;
865 let result = Self::modify_rbum(
866 set_cate_id,
867 &mut RbumSetCateModifyReq {
868 bus_code: None,
869 name: None,
870 icon: None,
871 sort: None,
872 ext: None,
873 rbum_parent_cate_id: Some(parent_set_cate_id.to_string()),
874 scope_level: None,
875 },
876 funs,
877 ctx,
878 )
879 .await;
880 for set_item_id in set_item_ids {
881 RbumSetItemServ::modify_rbum(
882 &set_item_id,
883 &mut RbumSetItemModifyReq {
884 rel_rbum_set_cate_id: Some(set_cate_id.to_string()),
885 sort: None,
886 },
887 funs,
888 ctx,
889 )
890 .await?;
891 }
892
893 let child_set_cates = Self::find_rbums(
894 &RbumSetCateFilterReq {
895 basic: RbumBasicFilterReq {
896 with_sub_own_paths: true,
897 ..Default::default()
898 },
899 rel_rbum_set_id: Some(set_cate_detail.rel_rbum_set_id.clone()),
900 sys_codes: Some(vec![set_cate_detail.sys_code.clone()]),
901 sys_code_query_kind: Some(RbumSetCateLevelQueryKind::Sub),
902 sys_code_query_depth: Some(1),
903 cate_exts: None,
904 ..Default::default()
905 },
906 None,
907 None,
908 funs,
909 ctx,
910 )
911 .await?;
912 for child_set_cate in child_set_cates {
913 Self::move_set_cate(&child_set_cate.id, &set_cate_detail.id, funs, ctx).await?;
914 }
915
916 result
917 }
918}
919
920#[async_trait]
921impl RbumCrudOperation<rbum_set_item::ActiveModel, RbumSetItemAddReq, RbumSetItemModifyReq, RbumSetItemSummaryResp, RbumSetItemDetailResp, RbumSetItemFilterReq>
922 for RbumSetItemServ
923{
924 fn get_table_name() -> &'static str {
925 rbum_set_item::Entity.table_name()
926 }
927
928 async fn before_add_rbum(add_req: &mut RbumSetItemAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
929 Self::check_scope(&add_req.rel_rbum_set_id, RbumSetServ::get_table_name(), funs, ctx).await?;
930 Self::check_scope(&add_req.rel_rbum_item_id, RbumItemServ::get_table_name(), funs, ctx).await?;
931 let rel_sys_code = if add_req.rel_rbum_set_cate_id.is_empty() {
932 "".to_string()
933 } else {
934 Self::check_scope(&add_req.rel_rbum_set_cate_id, RbumSetCateServ::get_table_name(), funs, ctx).await?;
935 RbumSetCateServ::get_sys_code(add_req.rel_rbum_set_cate_id.as_str(), funs, ctx).await?
936 };
937 if funs
938 .db()
939 .count(
940 Query::select()
941 .column(rbum_set_item::Column::Id)
942 .from(rbum_set_item::Entity)
943 .and_where(Expr::col(rbum_set_item::Column::RelRbumSetId).eq(add_req.rel_rbum_set_id.as_str()))
944 .and_where(Expr::col(rbum_set_item::Column::RelRbumItemId).eq(add_req.rel_rbum_item_id.as_str()))
945 .and_where(Expr::col(rbum_set_item::Column::RelRbumSetCateCode).eq(rel_sys_code.as_str())),
946 )
947 .await?
948 > 0
949 {
950 return Err(funs.err().conflict(&Self::get_obj_name(), "add", "item already exists", "409-rbum-set-item-exist"));
951 }
952 Ok(())
953 }
954
955 async fn package_add(add_req: &RbumSetItemAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<rbum_set_item::ActiveModel> {
956 let rel_sys_code = if add_req.rel_rbum_set_cate_id.is_empty() {
957 "".to_string()
958 } else {
959 RbumSetCateServ::get_sys_code(add_req.rel_rbum_set_cate_id.as_str(), funs, ctx).await?
960 };
961 Ok(rbum_set_item::ActiveModel {
962 id: Set(TardisFuns::field.nanoid()),
963 rel_rbum_set_id: Set(add_req.rel_rbum_set_id.to_string()),
964 rel_rbum_set_cate_code: Set(rel_sys_code),
965 rel_rbum_item_id: Set(add_req.rel_rbum_item_id.to_string()),
966 sort: Set(add_req.sort),
967 ..Default::default()
968 })
969 }
970
971 async fn package_modify(id: &str, modify_req: &RbumSetItemModifyReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<rbum_set_item::ActiveModel> {
972 let mut rbum_set_item = rbum_set_item::ActiveModel {
973 id: Set(id.to_string()),
974 ..Default::default()
975 };
976 if let Some(sort) = modify_req.sort {
977 rbum_set_item.sort = Set(sort);
978 }
979 if let Some(rel_rbum_set_cate_id) = &modify_req.rel_rbum_set_cate_id {
980 rbum_set_item.rel_rbum_set_cate_code = Set(RbumSetCateServ::get_sys_code(rel_rbum_set_cate_id.as_str(), funs, ctx).await?);
981 }
982
983 Ok(rbum_set_item)
984 }
985
986 async fn package_query(is_detail: bool, filter: &RbumSetItemFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
987 let rel_item_table = Alias::new("relItem");
988 let rbum_set_cate_join_type = if let Some(true) = filter.rel_rbum_item_can_not_exist {
989 JoinType::LeftJoin
990 } else {
991 JoinType::InnerJoin
992 };
993 let mut query = Query::select();
994 query
995 .columns(vec![
996 (rbum_set_item::Entity, rbum_set_item::Column::Id),
997 (rbum_set_item::Entity, rbum_set_item::Column::Sort),
998 (rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetId),
999 (rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId),
1000 (rbum_set_item::Entity, rbum_set_item::Column::OwnPaths),
1001 (rbum_set_item::Entity, rbum_set_item::Column::Owner),
1002 (rbum_set_item::Entity, rbum_set_item::Column::CreateTime),
1003 (rbum_set_item::Entity, rbum_set_item::Column::UpdateTime),
1004 ])
1005 .expr_as(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Id)), Alias::new("rel_rbum_set_cate_id"))
1006 .expr_as(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)), Alias::new("rel_rbum_set_cate_sys_code"))
1007 .expr_as(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Name)), Alias::new("rel_rbum_set_cate_name"))
1008 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::Name)), Alias::new("rel_rbum_item_name"))
1009 .from(rbum_set_item::Entity)
1010 .join(
1011 rbum_set_cate_join_type,
1012 rbum_set_cate::Entity,
1013 all![
1014 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::SysCode)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)),
1015 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::RelRbumSetId)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetId))
1016 ],
1017 )
1018 .join_as(
1019 JoinType::InnerJoin,
1020 rbum_item::Entity,
1021 rel_item_table.clone(),
1022 Expr::col((rel_item_table.clone(), rbum_item::Column::Id)).equals((rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId)),
1023 );
1024 if is_detail {
1025 query
1026 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::Code)), Alias::new("rel_rbum_item_code"))
1027 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::RelRbumKindId)), Alias::new("rel_rbum_item_kind_id"))
1028 .expr_as(
1029 Expr::col((rel_item_table.clone(), rbum_item::Column::RelRbumDomainId)),
1030 Alias::new("rel_rbum_item_domain_id"),
1031 )
1032 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::Owner)), Alias::new("rel_rbum_item_owner"))
1033 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::CreateTime)), Alias::new("rel_rbum_item_create_time"))
1034 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::UpdateTime)), Alias::new("rel_rbum_item_update_time"))
1035 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::Disabled)), Alias::new("rel_rbum_item_disabled"))
1036 .expr_as(Expr::col((rel_item_table.clone(), rbum_item::Column::ScopeLevel)), Alias::new("rel_rbum_item_scope_level"));
1037 }
1038 if let Some(rel_rbum_set_id) = &filter.rel_rbum_set_id {
1039 query.and_where(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetId)).eq(rel_rbum_set_id.to_string()));
1040 }
1041 if let Some(rel_rbum_set_cate_ids) = &filter.rel_rbum_set_cate_ids {
1042 query.and_where(Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Id)).is_in(rel_rbum_set_cate_ids.clone()));
1043 }
1044 if let Some(rel_rbum_item_ids) = &filter.rel_rbum_item_ids {
1045 query.and_where(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumItemId)).is_in(rel_rbum_item_ids.clone()));
1046 }
1047 if let Some(rel_rbum_item_scope_level) = &filter.rel_rbum_item_scope_level {
1048 query.and_where(Expr::col((rel_item_table.clone(), rbum_item::Column::ScopeLevel)).eq(rel_rbum_item_scope_level.to_int()));
1049 }
1050 if let Some(rel_rbum_item_disabled) = &filter.rel_rbum_item_disabled {
1051 query.and_where(Expr::col((rel_item_table.clone(), rbum_item::Column::Disabled)).eq(*rel_rbum_item_disabled));
1052 }
1053 if let Some(rel_rbum_item_domain_ids) = &filter.rel_rbum_item_domain_ids {
1054 query.and_where(Expr::col((rel_item_table.clone(), rbum_item::Column::RelRbumDomainId)).is_in(rel_rbum_item_domain_ids.clone()));
1055 }
1056 if let Some(rel_rbum_item_kind_ids) = &filter.rel_rbum_item_kind_ids {
1057 query.and_where(Expr::col((rel_item_table, rbum_item::Column::RelRbumKindId)).is_in(rel_rbum_item_kind_ids.clone()));
1058 }
1059 if let Some(sys_codes) = &filter.rel_rbum_set_cate_sys_codes {
1060 let query_kind = filter.sys_code_query_kind.clone().unwrap_or(RbumSetCateLevelQueryKind::Current);
1061 if sys_codes.is_empty() {
1062 if query_kind == RbumSetCateLevelQueryKind::Current {
1063 query.and_where(Expr::expr(Func::char_length(Expr::col(rbum_set_item::Column::RelRbumSetCateCode))).eq(funs.rbum_conf_set_cate_sys_code_node_len() as i32));
1065 }
1066 } else {
1067 let mut cond = Cond::any();
1068 match query_kind {
1069 RbumSetCateLevelQueryKind::CurrentAndSub => {
1070 if let Some(depth) = filter.sys_code_query_depth {
1071 for sys_code in sys_codes {
1072 cond = cond.add(all![
1073 Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).like(format!("{sys_code}%").as_str()),
1074 Expr::expr(Func::char_length(Expr::col(rbum_set_item::Column::RelRbumSetCateCode)))
1075 .lte((sys_code.len() + funs.rbum_conf_set_cate_sys_code_node_len() * depth as usize) as i32),
1076 ]);
1077 }
1078 } else {
1079 for sys_code in sys_codes {
1080 cond = cond.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).like(format!("{sys_code}%").as_str()));
1081 }
1082 }
1083 }
1084 RbumSetCateLevelQueryKind::Sub => {
1085 if let Some(depth) = filter.sys_code_query_depth {
1086 for sys_code in sys_codes {
1087 cond = cond.add(all![
1088 Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).like(format!("{sys_code}%").as_str()),
1089 Expr::expr(Func::char_length(Expr::col(rbum_set_item::Column::RelRbumSetCateCode))).gt(sys_code.len() as i32),
1090 Expr::expr(Func::char_length(Expr::col(rbum_set_item::Column::RelRbumSetCateCode)))
1091 .lte((sys_code.len() + funs.rbum_conf_set_cate_sys_code_node_len() * depth as usize) as i32),
1092 ]);
1093 }
1094 } else {
1095 for sys_code in sys_codes {
1096 cond = cond.add(all![
1097 Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).like(format!("{sys_code}%").as_str()),
1098 Expr::expr(Func::char_length(Expr::col(rbum_set_item::Column::RelRbumSetCateCode))).gt(sys_code.len() as i32)
1099 ]);
1100 }
1101 }
1102 }
1103 RbumSetCateLevelQueryKind::CurrentAndParent => {
1104 for sys_code in sys_codes {
1105 let mut sys_codes = RbumSetCateServ::get_parent_sys_codes(sys_code, funs)?;
1106 sys_codes.insert(0, sys_code.to_string());
1107 cond = cond.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).is_in(sys_codes));
1108 }
1109 }
1110 RbumSetCateLevelQueryKind::Parent => {
1111 for sys_code in sys_codes {
1112 let parent_sys_codes = RbumSetCateServ::get_parent_sys_codes(sys_code, funs)?;
1113 cond = cond.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).is_in(parent_sys_codes));
1114 }
1115 }
1116 RbumSetCateLevelQueryKind::Current => {
1117 for sys_code in sys_codes {
1118 cond = cond.add(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).eq(sys_code.as_str()));
1119 }
1120 }
1121 }
1122 query.cond_where(all![cond]);
1123 }
1124 }
1125 if let Some(rbum_set_item_cate_code) = &filter.rel_rbum_set_item_cate_code {
1126 query.and_where(Expr::col((rbum_set_item::Entity, rbum_set_item::Column::RelRbumSetCateCode)).eq(rbum_set_item_cate_code.as_str()));
1127 }
1128 query.with_filter(Self::get_table_name(), &filter.basic, is_detail, false, ctx);
1129 Ok(query)
1130 }
1131}
1132
1133impl RbumSetItemServ {
1134 pub async fn find_set_paths(rbum_item_id: &str, rbum_set_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Vec<Vec<RbumSetPathResp>>> {
1157 let rbum_set_cate_sys_codes: Vec<String> = Self::find_rbums(
1158 &RbumSetItemFilterReq {
1159 rel_rbum_item_can_not_exist: Some(true),
1160 rel_rbum_set_id: Some(rbum_set_id.to_string()),
1161 rel_rbum_item_ids: Some(vec![rbum_item_id.to_string()]),
1162 ..Default::default()
1163 },
1164 None,
1165 None,
1166 funs,
1167 ctx,
1168 )
1169 .await?
1170 .into_iter()
1171 .map(|item| item.rel_rbum_set_cate_sys_code.unwrap_or_default())
1172 .collect();
1173 let mut result: Vec<Vec<RbumSetPathResp>> = Vec::with_capacity(rbum_set_cate_sys_codes.len());
1174 for rbum_set_cate_sys_code in rbum_set_cate_sys_codes {
1175 if rbum_set_cate_sys_code.is_empty() {
1176 result.push(vec![]);
1178 continue;
1179 }
1180 let rbum_set_paths = RbumSetCateServ::find_rbums(
1181 &RbumSetCateFilterReq {
1182 rel_rbum_set_id: Some(rbum_set_id.to_string()),
1183 sys_codes: Some(vec![rbum_set_cate_sys_code]),
1184 sys_code_query_kind: Some(RbumSetCateLevelQueryKind::CurrentAndParent),
1185 ..Default::default()
1186 },
1187 None,
1188 None,
1189 funs,
1190 ctx,
1191 )
1192 .await?
1193 .into_iter()
1194 .sorted_by(|a, b| Ord::cmp(&a.sys_code, &b.sys_code))
1195 .map(|item| RbumSetPathResp {
1196 id: item.id,
1197 name: item.name,
1198 own_paths: item.own_paths,
1199 })
1200 .collect();
1201 result.push(rbum_set_paths);
1202 }
1203 Ok(result)
1204 }
1205
1206 pub async fn check_a_is_parent_of_b(rbum_item_a_id: &str, rbum_item_b_id: &str, rbum_set_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<bool> {
1210 Self::check_a_and_b(rbum_item_a_id, rbum_item_b_id, true, false, rbum_set_id, funs, ctx).await
1211 }
1212
1213 pub async fn check_a_is_sibling_of_b(rbum_item_a_id: &str, rbum_item_b_id: &str, rbum_set_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<bool> {
1217 Self::check_a_and_b(rbum_item_a_id, rbum_item_b_id, false, true, rbum_set_id, funs, ctx).await
1218 }
1219
1220 pub async fn check_a_is_parent_or_sibling_of_b(
1224 rbum_item_a_id: &str,
1225 rbum_item_b_id: &str,
1226 rbum_set_id: &str,
1227 funs: &TardisFunsInst,
1228 ctx: &TardisContext,
1229 ) -> TardisResult<bool> {
1230 Self::check_a_and_b(rbum_item_a_id, rbum_item_b_id, true, true, rbum_set_id, funs, ctx).await
1231 }
1232
1233 async fn check_a_and_b(
1234 rbum_item_a_id: &str,
1235 rbum_item_b_id: &str,
1236 is_parent: bool,
1237 is_sibling: bool,
1238 rbum_set_id: &str,
1239 funs: &TardisFunsInst,
1240 ctx: &TardisContext,
1241 ) -> TardisResult<bool> {
1242 let set_items: Vec<RbumSetItemSummaryResp> = Self::find_rbums(
1243 &RbumSetItemFilterReq {
1244 rel_rbum_set_id: Some(rbum_set_id.to_string()),
1245 rel_rbum_item_ids: Some(vec![rbum_item_a_id.to_string(), rbum_item_b_id.to_string()]),
1246 ..Default::default()
1247 },
1248 None,
1249 None,
1250 funs,
1251 ctx,
1252 )
1253 .await?;
1254 let set_item_a_sys_codes = set_items
1255 .iter()
1256 .filter(|item| item.rel_rbum_item_id == rbum_item_a_id)
1257 .map(|item| item.rel_rbum_set_cate_sys_code.clone().unwrap_or_default())
1258 .collect::<Vec<String>>();
1259 let set_item_b_sys_codes = set_items
1260 .iter()
1261 .filter(|item| item.rel_rbum_item_id == rbum_item_b_id)
1262 .map(|item| item.rel_rbum_set_cate_sys_code.clone().unwrap_or_default())
1263 .collect::<Vec<String>>();
1264
1265 Ok(set_item_a_sys_codes.iter().any(|sys_code_a| {
1266 set_item_b_sys_codes.iter().any(|sys_code_b| {
1267 if is_parent && is_sibling {
1268 sys_code_b.starts_with(sys_code_a)
1269 } else if is_parent {
1270 sys_code_b.starts_with(sys_code_a) && sys_code_a != sys_code_b
1271 } else if is_sibling {
1272 sys_code_a == sys_code_b
1273 } else {
1274 sys_code_a != sys_code_b && !sys_code_b.starts_with(sys_code_a)
1276 }
1277 })
1278 }))
1279 }
1280}
1281
1282#[derive(Debug, sea_orm::FromQueryResult)]
1283struct SysCodeResp {
1284 pub sys_code: String,
1285}