1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use itertools::Itertools;
5use tardis::basic::dto::TardisContext;
6use tardis::basic::result::TardisResult;
7use tardis::db::reldb_client::IdResp;
8use tardis::db::sea_orm::sea_query::*;
9use tardis::db::sea_orm::IdenStatic;
10use tardis::db::sea_orm::*;
11use tardis::web::web_resp::TardisPage;
12use tardis::TardisFuns;
13use tardis::TardisFunsInst;
14
15use crate::rbum::domain::{rbum_item, rbum_kind_attr, rbum_rel, rbum_rel_attr, rbum_rel_env, rbum_set, rbum_set_cate};
16use crate::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumRelExtFilterReq, RbumRelFilterReq, RbumSetCateFilterReq, RbumSetItemFilterReq};
17use crate::rbum::dto::rbum_rel_agg_dto::{RbumRelAggAddReq, RbumRelAggResp};
18use crate::rbum::dto::rbum_rel_attr_dto::{RbumRelAttrAddReq, RbumRelAttrDetailResp, RbumRelAttrModifyReq};
19use crate::rbum::dto::rbum_rel_dto::RbumRelEnvCheckReq;
20use crate::rbum::dto::rbum_rel_dto::{RbumRelAddReq, RbumRelBoneResp, RbumRelCheckReq, RbumRelDetailResp, RbumRelModifyReq, RbumRelSimpleFindReq};
21use crate::rbum::dto::rbum_rel_env_dto::{RbumRelEnvAddReq, RbumRelEnvDetailResp, RbumRelEnvModifyReq};
22use crate::rbum::rbum_enumeration::{RbumRelEnvKind, RbumRelFromKind, RbumSetCateLevelQueryKind};
23use crate::rbum::serv::rbum_crud_serv::{NameResp, RbumCrudOperation, RbumCrudQueryPackage};
24use crate::rbum::serv::rbum_item_serv::RbumItemServ;
25use crate::rbum::serv::rbum_kind_serv::RbumKindAttrServ;
26use crate::rbum::serv::rbum_set_serv::{RbumSetCateServ, RbumSetItemServ, RbumSetServ};
27
28use super::rbum_cert_serv::RbumCertServ;
29
30pub struct RbumRelServ;
31
32pub struct RbumRelAttrServ;
33
34pub struct RbumRelEnvServ;
35
36#[async_trait]
37impl RbumCrudOperation<rbum_rel::ActiveModel, RbumRelAddReq, RbumRelModifyReq, RbumRelDetailResp, RbumRelDetailResp, RbumRelFilterReq> for RbumRelServ {
38 fn get_table_name() -> &'static str {
39 rbum_rel::Entity.table_name()
40 }
41
42 async fn before_add_rbum(add_req: &mut RbumRelAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
43 let rel_rbum_table_name = match add_req.from_rbum_kind {
44 RbumRelFromKind::Item => RbumItemServ::get_table_name(),
45 RbumRelFromKind::Set => RbumSetServ::get_table_name(),
46 RbumRelFromKind::SetCate => RbumSetCateServ::get_table_name(),
47 RbumRelFromKind::Cert => RbumCertServ::get_table_name(),
48 };
49 if RbumRelFromKind::Cert == add_req.from_rbum_kind {
50 RbumCertServ::check_ownership(&add_req.from_rbum_id, funs, ctx).await?;
51 } else {
52 Self::check_scope(&add_req.from_rbum_id, rel_rbum_table_name, funs, ctx).await?;
59 }
60
61 if add_req.to_rbum_item_id.trim().is_empty() {
62 return Err(funs.err().bad_request(&Self::get_obj_name(), "add", "to_rbum_item_id can not be empty", "400-rbum-rel-not-empty-item"));
63 }
64 if !add_req.to_is_outside {
68 Self::check_scope(&add_req.to_rbum_item_id, RbumItemServ::get_table_name(), funs, ctx).await?;
69 }
70 Ok(())
71 }
72
73 async fn package_add(add_req: &RbumRelAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel::ActiveModel> {
74 Ok(rbum_rel::ActiveModel {
75 id: Set(TardisFuns::field.nanoid()),
76 tag: Set(add_req.tag.to_string()),
77 note: Set(add_req.note.as_ref().unwrap_or(&"".to_string()).to_string()),
78 from_rbum_kind: Set(add_req.from_rbum_kind.to_int()),
79 from_rbum_id: Set(add_req.from_rbum_id.to_string()),
80 to_rbum_item_id: Set(add_req.to_rbum_item_id.to_string()),
81 to_own_paths: Set(add_req.to_own_paths.to_string()),
82 ext: Set(add_req.ext.as_ref().unwrap_or(&"".to_string()).to_string()),
83 ..Default::default()
84 })
85 }
86
87 async fn package_modify(id: &str, modify_req: &RbumRelModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel::ActiveModel> {
88 let mut rbum_rel = rbum_rel::ActiveModel {
89 id: Set(id.to_string()),
90 ..Default::default()
91 };
92 if let Some(tag) = &modify_req.tag {
93 rbum_rel.tag = Set(tag.to_string());
94 }
95 if let Some(note) = &modify_req.note {
96 rbum_rel.note = Set(note.to_string());
97 }
98 if let Some(ext) = &modify_req.ext {
99 rbum_rel.ext = Set(ext.to_string());
100 }
101 Ok(rbum_rel)
102 }
103
104 async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumRelDetailResp>> {
105 let mut query = Query::select();
106 query.column(rbum_rel::Column::Id).from(rbum_rel::Entity).and_where(Expr::col(rbum_rel::Column::Id).eq(id)).cond_where(all![any![
107 Expr::col(rbum_rel::Column::OwnPaths).like(format!("{}%", ctx.own_paths).as_str()),
108 Expr::col(rbum_rel::Column::ToOwnPaths).like(format!("{}%", ctx.own_paths).as_str())
109 ]]);
110 if funs.db().count(&query).await? == 0 {
111 return Err(funs.err().not_found(
112 &Self::get_obj_name(),
113 "delete",
114 &format!("ownership {}.{} is illegal by {}", Self::get_obj_name(), id, ctx.owner),
115 "404-rbum-*-ownership-illegal",
116 ));
117 }
118 Self::check_exist_before_delete(id, RbumRelAttrServ::get_table_name(), rbum_rel_attr::Column::RelRbumRelId.as_str(), funs).await?;
119 Self::check_exist_before_delete(id, RbumRelEnvServ::get_table_name(), rbum_rel_env::Column::RelRbumRelId.as_str(), funs).await?;
120 Ok(None)
121 }
122
123 async fn package_query(_: bool, filter: &RbumRelFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
124 let from_rbum_item_table = Alias::new("fromRbumItem");
125 let to_rbum_item_table = Alias::new("toRbumItem");
126 let mut query = Query::select();
127 query
128 .columns(vec![
129 (rbum_rel::Entity, rbum_rel::Column::Id),
130 (rbum_rel::Entity, rbum_rel::Column::Tag),
131 (rbum_rel::Entity, rbum_rel::Column::Note),
132 (rbum_rel::Entity, rbum_rel::Column::FromRbumKind),
133 (rbum_rel::Entity, rbum_rel::Column::FromRbumId),
134 (rbum_rel::Entity, rbum_rel::Column::ToRbumItemId),
135 (rbum_rel::Entity, rbum_rel::Column::ToOwnPaths),
136 (rbum_rel::Entity, rbum_rel::Column::Ext),
137 (rbum_rel::Entity, rbum_rel::Column::OwnPaths),
138 (rbum_rel::Entity, rbum_rel::Column::Owner),
139 (rbum_rel::Entity, rbum_rel::Column::CreateTime),
140 (rbum_rel::Entity, rbum_rel::Column::UpdateTime),
141 ])
142 .expr_as(
143 Expr::col((from_rbum_item_table.clone(), rbum_item::Column::Name)).if_null(""),
144 Alias::new("from_rbum_item_name"),
145 )
146 .expr_as(Expr::col((rbum_set::Entity, rbum_set::Column::Name)).if_null(""), Alias::new("from_rbum_set_name"))
147 .expr_as(
148 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Name)).if_null(""),
149 Alias::new("from_rbum_set_cate_name"),
150 )
151 .expr_as(
152 Expr::col((to_rbum_item_table.clone(), rbum_item::Column::Name)).if_null(""),
153 Alias::new("to_rbum_item_name"),
154 )
155 .from(rbum_rel::Entity)
156 .join_as(
157 JoinType::LeftJoin,
158 rbum_item::Entity,
159 from_rbum_item_table.clone(),
160 all![
161 Expr::col((from_rbum_item_table.clone(), rbum_item::Column::Id)).equals((rbum_rel::Entity, rbum_rel::Column::FromRbumId)),
162 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(RbumRelFromKind::Item.to_int())
163 ],
164 )
165 .left_join(
166 rbum_set::Entity,
167 all![
168 Expr::col((rbum_set::Entity, rbum_set::Column::Id)).equals((rbum_rel::Entity, rbum_rel::Column::FromRbumId)),
169 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(RbumRelFromKind::Set.to_int())
170 ],
171 )
172 .left_join(
173 rbum_set_cate::Entity,
174 all![
175 Expr::col((rbum_set_cate::Entity, rbum_set_cate::Column::Id)).equals((rbum_rel::Entity, rbum_rel::Column::FromRbumId)),
176 Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(RbumRelFromKind::SetCate.to_int())
177 ],
178 )
179 .join_as(
180 JoinType::LeftJoin,
181 rbum_item::Entity,
182 to_rbum_item_table.clone(),
183 Expr::col((to_rbum_item_table.clone(), rbum_item::Column::Id)).equals((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)),
184 );
185
186 if let Some(tag) = &filter.tag {
187 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Tag)).eq(tag.to_string()));
188 }
189 if let Some(from_rbum_kind) = &filter.from_rbum_kind {
190 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).eq(from_rbum_kind.to_int()));
191 }
192 if let Some(from_rbum_id) = &filter.from_rbum_id {
193 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).eq(from_rbum_id.to_string()));
194 }
195 if let Some(to_rbum_item_id) = &filter.to_rbum_item_id {
196 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(to_rbum_item_id.to_string()));
197 }
198 if let Some(from_rbum_scope_levels) = &filter.from_rbum_scope_levels {
199 query.and_where(Expr::col((from_rbum_item_table, rbum_item::Column::ScopeLevel)).is_in(from_rbum_scope_levels.clone()));
200 }
201 if let Some(to_rbum_item_scope_levels) = &filter.to_rbum_item_scope_levels {
202 query.and_where(Expr::col((to_rbum_item_table, rbum_item::Column::ScopeLevel)).is_in(to_rbum_item_scope_levels.clone()));
203 }
204 if let Some(to_own_paths) = &filter.to_own_paths {
205 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToOwnPaths)).eq(to_own_paths.to_string()));
206 }
207 if let Some(ext_eq) = &filter.ext_eq {
208 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Ext)).eq(ext_eq.to_string()));
209 }
210 if let Some(ext_like) = &filter.ext_like {
211 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Ext)).like(format!("%{ext_like}%").as_str()));
212 }
213 query.with_filter(Self::get_table_name(), &filter.basic, true, false, ctx);
214 Ok(query)
215 }
216}
217
218impl RbumRelServ {
219 pub async fn add_simple_rel(tag: &str, from_rbum_id: &str, to_rbum_item_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
227 RbumRelServ::add_rbum(
228 &mut RbumRelAddReq {
229 tag: tag.to_string(),
230 note: None,
231 from_rbum_kind: RbumRelFromKind::Item,
232 from_rbum_id: from_rbum_id.to_string(),
233 to_rbum_item_id: to_rbum_item_id.to_string(),
234 to_own_paths: ctx.own_paths.to_string(),
235 to_is_outside: false,
236 ext: None,
237 },
238 funs,
239 ctx,
240 )
241 .await?;
242 Ok(())
243 }
244
245 pub async fn add_rel(add_req: &mut RbumRelAggAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<String> {
249 let rbum_rel_id = Self::add_rbum(&mut add_req.rel, funs, ctx).await?;
250 for attr in &add_req.attrs {
251 RbumRelAttrServ::add_rbum(
252 &mut RbumRelAttrAddReq {
253 is_from: attr.is_from,
254 value: attr.value.to_string(),
255 name: attr.name.clone(),
256 rel_rbum_rel_id: rbum_rel_id.to_string(),
257 rel_rbum_kind_attr_id: attr.rel_rbum_kind_attr_id.clone(),
258 record_only: attr.record_only,
259 },
260 funs,
261 ctx,
262 )
263 .await?;
264 }
265 for env in &add_req.envs {
266 RbumRelEnvServ::add_rbum(
267 &mut RbumRelEnvAddReq {
268 kind: env.kind.clone(),
269 value1: env.value1.to_string(),
270 value2: env.value2.clone(),
271 rel_rbum_rel_id: rbum_rel_id.to_string(),
272 },
273 funs,
274 ctx,
275 )
276 .await?;
277 }
278 Ok(rbum_rel_id)
279 }
280
281 pub async fn find_from_id_rels(
285 tag: &str,
286 from_rbum_kind: &RbumRelFromKind,
287 with_sub: bool,
288 from_rbum_id: &str,
289 desc_sort_by_create: Option<bool>,
290 desc_sort_by_update: Option<bool>,
291 funs: &TardisFunsInst,
292 ctx: &TardisContext,
293 ) -> TardisResult<Vec<String>> {
294 Self::find_from_simple_rels(tag, from_rbum_kind, with_sub, from_rbum_id, desc_sort_by_create, desc_sort_by_update, funs, ctx)
295 .await
296 .map(|r| r.into_iter().map(|item| item.rel_id).collect())
297 }
298
299 pub async fn find_from_simple_rels(
303 tag: &str,
304 from_rbum_kind: &RbumRelFromKind,
305 with_sub: bool,
306 from_rbum_id: &str,
307 desc_sort_by_create: Option<bool>,
308 desc_sort_by_update: Option<bool>,
309 funs: &TardisFunsInst,
310 ctx: &TardisContext,
311 ) -> TardisResult<Vec<RbumRelBoneResp>> {
312 Self::find_rbums(
313 &RbumRelFilterReq {
314 basic: RbumBasicFilterReq {
315 with_sub_own_paths: with_sub,
316 ..Default::default()
317 },
318 tag: Some(tag.to_string()),
319 from_rbum_kind: Some(from_rbum_kind.clone()),
320 from_rbum_id: Some(from_rbum_id.to_string()),
321 ..Default::default()
322 },
323 desc_sort_by_create,
324 desc_sort_by_update,
325 funs,
326 ctx,
327 )
328 .await
329 .map(|r| r.into_iter().map(|item| RbumRelBoneResp::new(item, true)).collect())
330 }
331
332 pub async fn find_from_rels(
336 tag: &str,
337 from_rbum_kind: &RbumRelFromKind,
338 with_sub: bool,
339 from_rbum_id: &str,
340 desc_sort_by_create: Option<bool>,
341 desc_sort_by_update: Option<bool>,
342 funs: &TardisFunsInst,
343 ctx: &TardisContext,
344 ) -> TardisResult<Vec<RbumRelAggResp>> {
345 Self::find_rels(
346 &RbumRelFilterReq {
347 basic: RbumBasicFilterReq {
348 with_sub_own_paths: with_sub,
349 ..Default::default()
350 },
351 tag: Some(tag.to_string()),
352 from_rbum_kind: Some(from_rbum_kind.clone()),
353 from_rbum_id: Some(from_rbum_id.to_string()),
354 ..Default::default()
355 },
356 desc_sort_by_create,
357 desc_sort_by_update,
358 funs,
359 ctx,
360 )
361 .await
362 }
363
364 pub async fn paginate_from_id_rels(
368 tag: &str,
369 from_rbum_kind: &RbumRelFromKind,
370 with_sub: bool,
371 from_rbum_id: &str,
372 page_number: u32,
373 page_size: u32,
374 desc_sort_by_create: Option<bool>,
375 desc_sort_by_update: Option<bool>,
376 funs: &TardisFunsInst,
377 ctx: &TardisContext,
378 ) -> TardisResult<TardisPage<String>> {
379 let result = Self::paginate_from_simple_rels(
380 tag,
381 from_rbum_kind,
382 with_sub,
383 from_rbum_id,
384 page_number,
385 page_size,
386 desc_sort_by_create,
387 desc_sort_by_update,
388 funs,
389 ctx,
390 )
391 .await?;
392 Ok(TardisPage {
393 page_size: result.page_size,
394 page_number: result.page_number,
395 total_size: result.total_size,
396 records: result.records.into_iter().map(|item| item.rel_id).collect(),
397 })
398 }
399
400 pub async fn paginate_from_simple_rels(
404 tag: &str,
405 from_rbum_kind: &RbumRelFromKind,
406 with_sub: bool,
407 from_rbum_id: &str,
408 page_number: u32,
409 page_size: u32,
410 desc_sort_by_create: Option<bool>,
411 desc_sort_by_update: Option<bool>,
412 funs: &TardisFunsInst,
413 ctx: &TardisContext,
414 ) -> TardisResult<TardisPage<RbumRelBoneResp>> {
415 let result = Self::paginate_rbums(
416 &RbumRelFilterReq {
417 basic: RbumBasicFilterReq {
418 with_sub_own_paths: with_sub,
419 ..Default::default()
420 },
421 tag: Some(tag.to_string()),
422 from_rbum_kind: Some(from_rbum_kind.clone()),
423 from_rbum_id: Some(from_rbum_id.to_string()),
424 ..Default::default()
425 },
426 page_number,
427 page_size,
428 desc_sort_by_create,
429 desc_sort_by_update,
430 funs,
431 ctx,
432 )
433 .await?;
434 Ok(TardisPage {
435 page_size: result.page_size,
436 page_number: result.page_number,
437 total_size: result.total_size,
438 records: result.records.into_iter().map(|item| RbumRelBoneResp::new(item, true)).collect(),
439 })
440 }
441
442 pub async fn paginate_from_rels(
446 tag: &str,
447 from_rbum_kind: &RbumRelFromKind,
448 with_sub: bool,
449 from_rbum_id: &str,
450 page_number: u32,
451 page_size: u32,
452 desc_sort_by_create: Option<bool>,
453 desc_sort_by_update: Option<bool>,
454 funs: &TardisFunsInst,
455 ctx: &TardisContext,
456 ) -> TardisResult<TardisPage<RbumRelAggResp>> {
457 Self::paginate_rels(
458 &RbumRelFilterReq {
459 basic: RbumBasicFilterReq {
460 with_sub_own_paths: with_sub,
461 ..Default::default()
462 },
463 tag: Some(tag.to_string()),
464 from_rbum_kind: Some(from_rbum_kind.clone()),
465 from_rbum_id: Some(from_rbum_id.to_string()),
466 ..Default::default()
467 },
468 page_number,
469 page_size,
470 desc_sort_by_create,
471 desc_sort_by_update,
472 funs,
473 ctx,
474 )
475 .await
476 }
477
478 pub async fn count_from_rels(tag: &str, from_rbum_kind: &RbumRelFromKind, with_sub: bool, from_rbum_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
482 Self::count_rels(
483 &RbumRelFilterReq {
484 basic: RbumBasicFilterReq {
485 with_sub_own_paths: with_sub,
486 ..Default::default()
487 },
488 tag: Some(tag.to_string()),
489 from_rbum_kind: Some(from_rbum_kind.clone()),
490 from_rbum_id: Some(from_rbum_id.to_string()),
491 ..Default::default()
492 },
493 funs,
494 ctx,
495 )
496 .await
497 }
498
499 pub async fn find_to_id_rels(
503 tag: &str,
504 to_rbum_item_id: &str,
505 desc_sort_by_create: Option<bool>,
506 desc_sort_by_update: Option<bool>,
507 funs: &TardisFunsInst,
508 ctx: &TardisContext,
509 ) -> TardisResult<Vec<String>> {
510 Self::find_to_simple_rels(tag, to_rbum_item_id, desc_sort_by_create, desc_sort_by_update, funs, ctx).await.map(|r| r.into_iter().map(|item| item.rel_id).collect())
511 }
512
513 pub async fn find_to_simple_rels(
517 tag: &str,
518 to_rbum_item_id: &str,
519 desc_sort_by_create: Option<bool>,
520 desc_sort_by_update: Option<bool>,
521 funs: &TardisFunsInst,
522 ctx: &TardisContext,
523 ) -> TardisResult<Vec<RbumRelBoneResp>> {
524 Self::find_rbums(
525 &RbumRelFilterReq {
526 basic: RbumBasicFilterReq {
527 own_paths: Some(ctx.own_paths.to_string()),
528 with_sub_own_paths: true,
529 ignore_scope: true,
530 ..Default::default()
531 },
532 tag: Some(tag.to_string()),
533 to_rbum_item_id: Some(to_rbum_item_id.to_string()),
534 ..Default::default()
535 },
536 desc_sort_by_create,
537 desc_sort_by_update,
538 funs,
539 ctx,
540 )
541 .await
542 .map(|r| r.into_iter().map(|item| RbumRelBoneResp::new(item, false)).collect())
543 }
544
545 pub async fn find_to_rels(
549 tag: &str,
550 to_rbum_item_id: &str,
551 desc_sort_by_create: Option<bool>,
552 desc_sort_by_update: Option<bool>,
553 funs: &TardisFunsInst,
554 ctx: &TardisContext,
555 ) -> TardisResult<Vec<RbumRelAggResp>> {
556 Self::find_rels(
557 &RbumRelFilterReq {
558 basic: RbumBasicFilterReq {
559 own_paths: Some(ctx.own_paths.to_string()),
560 with_sub_own_paths: true,
561 ignore_scope: true,
562 ..Default::default()
563 },
564 tag: Some(tag.to_string()),
565 to_rbum_item_id: Some(to_rbum_item_id.to_string()),
566 ..Default::default()
567 },
568 desc_sort_by_create,
569 desc_sort_by_update,
570 funs,
571 ctx,
572 )
573 .await
574 }
575
576 pub async fn paginate_to_id_rels(
580 tag: &str,
581 to_rbum_item_id: &str,
582 page_number: u32,
583 page_size: u32,
584 desc_sort_by_create: Option<bool>,
585 desc_sort_by_update: Option<bool>,
586 funs: &TardisFunsInst,
587 ctx: &TardisContext,
588 ) -> TardisResult<TardisPage<String>> {
589 let result = Self::paginate_to_simple_rels(tag, to_rbum_item_id, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await?;
590 Ok(TardisPage {
591 page_size: result.page_size,
592 page_number: result.page_number,
593 total_size: result.total_size,
594 records: result.records.into_iter().map(|item| item.rel_id).collect(),
595 })
596 }
597
598 pub async fn paginate_to_simple_rels(
602 tag: &str,
603 to_rbum_item_id: &str,
604 page_number: u32,
605 page_size: u32,
606 desc_sort_by_create: Option<bool>,
607 desc_sort_by_update: Option<bool>,
608 funs: &TardisFunsInst,
609 ctx: &TardisContext,
610 ) -> TardisResult<TardisPage<RbumRelBoneResp>> {
611 let result = Self::paginate_rbums(
612 &RbumRelFilterReq {
613 basic: RbumBasicFilterReq {
614 own_paths: Some(ctx.own_paths.to_string()),
615 with_sub_own_paths: true,
616 ignore_scope: true,
617 ..Default::default()
618 },
619 tag: Some(tag.to_string()),
620 to_rbum_item_id: Some(to_rbum_item_id.to_string()),
621 ..Default::default()
622 },
623 page_number,
624 page_size,
625 desc_sort_by_create,
626 desc_sort_by_update,
627 funs,
628 ctx,
629 )
630 .await?;
631 Ok(TardisPage {
632 page_size: result.page_size,
633 page_number: result.page_number,
634 total_size: result.total_size,
635 records: result.records.into_iter().map(|item| RbumRelBoneResp::new(item, false)).collect(),
636 })
637 }
638
639 pub async fn paginate_to_rels(
643 tag: &str,
644 to_rbum_item_id: &str,
645 page_number: u32,
646 page_size: u32,
647 desc_sort_by_create: Option<bool>,
648 desc_sort_by_update: Option<bool>,
649 funs: &TardisFunsInst,
650 ctx: &TardisContext,
651 ) -> TardisResult<TardisPage<RbumRelAggResp>> {
652 Self::paginate_rels(
653 &RbumRelFilterReq {
654 basic: RbumBasicFilterReq {
655 own_paths: Some(ctx.own_paths.to_string()),
656 with_sub_own_paths: true,
657 ignore_scope: true,
658 ..Default::default()
659 },
660 tag: Some(tag.to_string()),
661 to_rbum_item_id: Some(to_rbum_item_id.to_string()),
662 ..Default::default()
663 },
664 page_number,
665 page_size,
666 desc_sort_by_create,
667 desc_sort_by_update,
668 funs,
669 ctx,
670 )
671 .await
672 }
673
674 pub async fn count_to_rels(tag: &str, to_rbum_item_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
678 Self::count_rels(
679 &RbumRelFilterReq {
680 basic: RbumBasicFilterReq {
681 own_paths: Some(ctx.own_paths.to_string()),
682 with_sub_own_paths: true,
683 ignore_scope: true,
684 ..Default::default()
685 },
686 tag: Some(tag.to_string()),
687 to_rbum_item_id: Some(to_rbum_item_id.to_string()),
688 ..Default::default()
689 },
690 funs,
691 ctx,
692 )
693 .await
694 }
695
696 async fn count_rels(filter: &RbumRelFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
700 RbumRelServ::count_rbums(filter, funs, ctx).await
701 }
702
703 pub async fn find_simple_rels(
711 filter: &RbumRelFilterReq,
712 desc_sort_by_create: Option<bool>,
713 desc_sort_by_update: Option<bool>,
714 package_to_info: bool,
715 funs: &TardisFunsInst,
716 ctx: &TardisContext,
717 ) -> TardisResult<Vec<RbumRelBoneResp>> {
718 RbumRelServ::find_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx)
719 .await
720 .map(|r| r.into_iter().map(|item| RbumRelBoneResp::new(item, package_to_info)).collect())
721 }
722
723 pub async fn find_rels(
727 filter: &RbumRelFilterReq,
728 desc_sort_by_create: Option<bool>,
729 desc_sort_by_update: Option<bool>,
730 funs: &TardisFunsInst,
731 ctx: &TardisContext,
732 ) -> TardisResult<Vec<RbumRelAggResp>> {
733 let rbum_rels = RbumRelServ::find_rbums(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await?;
734 Self::package_agg_rels(rbum_rels, filter, funs, ctx).await
735 }
736
737 pub async fn paginate_simple_rels(
745 filter: &RbumRelFilterReq,
746 page_number: u32,
747 page_size: u32,
748 desc_sort_by_create: Option<bool>,
749 desc_sort_by_update: Option<bool>,
750 package_to_info: bool,
751 funs: &TardisFunsInst,
752 ctx: &TardisContext,
753 ) -> TardisResult<TardisPage<RbumRelBoneResp>> {
754 let result = RbumRelServ::paginate_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await?;
755 Ok(TardisPage {
756 page_size: result.page_size,
757 page_number: result.page_number,
758 total_size: result.total_size,
759 records: result.records.into_iter().map(|item| RbumRelBoneResp::new(item, package_to_info)).collect(),
760 })
761 }
762
763 pub async fn paginate_rels(
767 filter: &RbumRelFilterReq,
768 page_number: u32,
769 page_size: u32,
770 desc_sort_by_create: Option<bool>,
771 desc_sort_by_update: Option<bool>,
772 funs: &TardisFunsInst,
773 ctx: &TardisContext,
774 ) -> TardisResult<TardisPage<RbumRelAggResp>> {
775 let rbum_rels = RbumRelServ::paginate_rbums(filter, page_number, page_size, desc_sort_by_create, desc_sort_by_update, funs, ctx).await?;
776 let result = Self::package_agg_rels(rbum_rels.records, filter, funs, ctx).await?;
777 Ok(TardisPage {
778 page_size: page_size as u64,
779 page_number: page_number as u64,
780 total_size: rbum_rels.total_size,
781 records: result,
782 })
783 }
784
785 async fn package_agg_rels(rels: Vec<RbumRelDetailResp>, filter: &RbumRelFilterReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Vec<RbumRelAggResp>> {
789 let mut result = Vec::with_capacity(rels.len());
790 for rel in rels {
791 let rbum_rel_id = rel.id.to_string();
792 let resp = RbumRelAggResp {
793 rel,
794 attrs: RbumRelAttrServ::find_rbums(
795 &RbumRelExtFilterReq {
796 basic: filter.basic.clone(),
797 rel_rbum_rel_id: Some(rbum_rel_id.clone()),
798 },
799 None,
800 None,
801 funs,
802 ctx,
803 )
804 .await?,
805 envs: RbumRelEnvServ::find_rbums(
806 &RbumRelExtFilterReq {
807 basic: filter.basic.clone(),
808 rel_rbum_rel_id: Some(rbum_rel_id.clone()),
809 },
810 None,
811 None,
812 funs,
813 ctx,
814 )
815 .await?,
816 };
817 result.push(resp);
818 }
819 Ok(result)
820 }
821
822 pub async fn find_rel_ids(find_req: &RbumRelSimpleFindReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Vec<String>> {
826 let ids = funs.db().find_dtos::<IdResp>(&Self::package_simple_rel_query(find_req, ctx)).await?.iter().map(|i| i.id.to_string()).collect::<Vec<String>>();
827 Ok(ids)
828 }
829
830 pub async fn check_simple_rel(find_req: &RbumRelSimpleFindReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<bool> {
834 funs.db().count(&Self::package_simple_rel_query(find_req, ctx)).await.map(|i| i > 0)
835 }
836
837 fn package_simple_rel_query(find_req: &RbumRelSimpleFindReq, ctx: &TardisContext) -> SelectStatement {
838 let mut query = Query::select();
839 query.column(rbum_rel::Column::Id).from(rbum_rel::Entity);
840 if let Some(tag) = &find_req.tag {
841 query.and_where(Expr::col(rbum_rel::Column::Tag).eq(tag.to_string()));
842 }
843 if let Some(from_rbum_kind) = &find_req.from_rbum_kind {
844 query.and_where(Expr::col(rbum_rel::Column::FromRbumKind).eq(from_rbum_kind.to_int()));
845 }
846 if let Some(from_rbum_id) = &find_req.from_rbum_id {
847 query.and_where(Expr::col(rbum_rel::Column::FromRbumId).eq(from_rbum_id.to_string()));
848 }
849 if let Some(to_rbum_item_id) = &find_req.to_rbum_item_id {
850 query.and_where(Expr::col(rbum_rel::Column::ToRbumItemId).eq(to_rbum_item_id.to_string()));
851 }
852 if let Some(from_own_paths) = &find_req.from_own_paths {
853 query.and_where(Expr::col(rbum_rel::Column::OwnPaths).eq(from_own_paths.to_string()));
854 }
855 if let Some(to_rbum_own_paths) = &find_req.to_rbum_own_paths {
856 query.and_where(Expr::col(rbum_rel::Column::ToOwnPaths).eq(to_rbum_own_paths.to_string()));
857 }
858 query.cond_where(all![any![
859 Expr::col(rbum_rel::Column::OwnPaths).like(format!("{}%", ctx.own_paths).as_str()),
860 Expr::col(rbum_rel::Column::ToOwnPaths).like(format!("{}%", ctx.own_paths).as_str())
861 ]]);
862 query
863 }
864
865 pub async fn check_rel(check_req: &RbumRelCheckReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<bool> {
869 if Self::do_check_rel(
873 &check_req.tag,
874 Some(vec![check_req.from_rbum_kind.clone()]),
875 Some(vec![check_req.from_rbum_id.clone()]),
876 Some(check_req.to_rbum_item_id.clone()),
877 &check_req.from_attrs,
878 &check_req.to_attrs,
879 &check_req.envs,
880 funs,
881 ctx,
882 )
883 .await?
884 {
885 return Ok(true);
886 }
887 let rel_rbum_set_cates = if check_req.from_rbum_kind == RbumRelFromKind::Item {
893 RbumSetItemServ::find_rbums(
894 &RbumSetItemFilterReq {
895 basic: Default::default(),
896 rel_rbum_item_ids: Some(vec![check_req.from_rbum_id.clone()]),
897 ..Default::default()
898 },
899 None,
900 None,
901 funs,
902 ctx,
903 )
904 .await?
905 .into_iter()
906 .into_group_map_by(|i| i.rel_rbum_set_id.clone())
907 .into_iter()
908 .map(|(set_id, cates)| {
909 (
910 set_id,
911 cates.into_iter().map(|cate| (cate.rel_rbum_set_cate_id.unwrap_or_default(), cate.rel_rbum_set_cate_sys_code.unwrap_or_default())).collect(),
912 )
913 })
914 .collect::<HashMap<String, Vec<(String, String)>>>()
915 } else if check_req.from_rbum_kind == RbumRelFromKind::SetCate {
916 let set_cate = RbumSetCateServ::peek_rbum(&check_req.from_rbum_id, &RbumSetCateFilterReq::default(), funs, ctx).await?;
917 HashMap::from([(set_cate.rel_rbum_set_id.clone(), vec![(set_cate.id, set_cate.sys_code)])])
918 } else {
919 return Ok(false);
920 };
921
922 for (set_id, cates) in rel_rbum_set_cates {
923 let mut set_cate_parent_ids = RbumSetCateServ::find_id_rbums(
927 &RbumSetCateFilterReq {
928 basic: Default::default(),
929 rel_rbum_set_id: Some(set_id.clone()),
930 sys_codes: Some(cates.iter().map(|i| i.1.clone()).collect()),
931 sys_code_query_kind: Some(RbumSetCateLevelQueryKind::Parent),
932 ..Default::default()
933 },
934 None,
935 None,
936 funs,
937 ctx,
938 )
939 .await?;
940 if check_req.from_rbum_kind == RbumRelFromKind::Item {
941 set_cate_parent_ids.insert(0, check_req.from_rbum_id.clone());
946 }
947 set_cate_parent_ids.push(set_id);
951
952 if Self::do_check_rel(
956 &check_req.tag,
957 Some(vec![RbumRelFromKind::SetCate, RbumRelFromKind::Set]),
961 Some(set_cate_parent_ids),
962 Some(check_req.to_rbum_item_id.clone()),
963 &check_req.from_attrs,
964 &check_req.to_attrs,
965 &check_req.envs,
966 funs,
967 ctx,
968 )
969 .await?
970 {
971 return Ok(true);
972 }
973 }
974 Ok(false)
975 }
976
977 async fn do_check_rel(
1026 tag: &str,
1027 from_rbum_kinds: Option<Vec<RbumRelFromKind>>,
1028 from_rbum_ids: Option<Vec<String>>,
1029 to_rbum_item_id: Option<String>,
1030 from_attrs: &HashMap<String, String>,
1031 to_attrs: &HashMap<String, String>,
1032 envs: &Vec<RbumRelEnvCheckReq>,
1033 funs: &TardisFunsInst,
1034 ctx: &TardisContext,
1035 ) -> TardisResult<bool> {
1036 let mut query = Query::select();
1037 query.column((rbum_rel::Entity, rbum_rel::Column::Id)).from(rbum_rel::Entity);
1038 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::Tag)).eq(tag));
1039 if let Some(from_rbum_kinds) = from_rbum_kinds {
1040 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumKind)).is_in(from_rbum_kinds.into_iter().map(|i| i.to_int()).collect::<Vec<_>>()));
1041 }
1042 if let Some(from_rbum_ids) = from_rbum_ids {
1043 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::FromRbumId)).is_in(from_rbum_ids));
1044 }
1045 if let Some(to_rbum_item_id) = to_rbum_item_id {
1046 query.and_where(Expr::col((rbum_rel::Entity, rbum_rel::Column::ToRbumItemId)).eq(to_rbum_item_id));
1047 }
1048 query.cond_where(all![any![
1049 Expr::col((rbum_rel::Entity, rbum_rel::Column::OwnPaths)).like(format!("{}%", ctx.own_paths).as_str()),
1050 Expr::col((rbum_rel::Entity, rbum_rel::Column::ToOwnPaths)).like(format!("{}%", ctx.own_paths).as_str())
1051 ]]);
1052 if !from_attrs.is_empty() || !to_attrs.is_empty() {
1053 let attr_table_without_cond = Alias::new(format!("{}_without_cond", RbumRelAttrServ::get_table_name()));
1054 let attr_table_with_cond = Alias::new(format!("{}_with_cond", RbumRelAttrServ::get_table_name()));
1055
1056 query.join_subquery(
1057 JoinType::LeftJoin,
1058 Query::select()
1059 .column(rbum_rel_attr::Column::RelRbumRelId)
1060 .expr_as(Expr::col(rbum_rel_attr::Column::RelRbumRelId).count(), Alias::new("attr_count"))
1061 .from(rbum_rel_attr::Entity)
1062 .and_where(Expr::col(rbum_rel_attr::Column::RecordOnly).eq(false))
1063 .group_by_col(rbum_rel_attr::Column::RelRbumRelId)
1064 .take(),
1065 attr_table_without_cond.clone(),
1066 Expr::col((attr_table_without_cond.clone(), rbum_rel_attr::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1067 );
1068
1069 let mut attr_conds = Cond::any();
1070 for (name, value) in from_attrs {
1071 attr_conds = attr_conds.add(all![
1072 Expr::col(rbum_rel_attr::Column::Name).eq(name),
1073 Expr::col(rbum_rel_attr::Column::Value).eq(value),
1074 Expr::col(rbum_rel_attr::Column::IsFrom).eq(true)
1075 ]);
1076 }
1077 for (name, value) in to_attrs {
1078 attr_conds = attr_conds.add(all![
1079 Expr::col(rbum_rel_attr::Column::Name).eq(name),
1080 Expr::col(rbum_rel_attr::Column::Value).eq(value),
1081 Expr::col(rbum_rel_attr::Column::IsFrom).eq(false)
1082 ]);
1083 }
1084 query.join_subquery(
1085 JoinType::LeftJoin,
1086 Query::select()
1087 .column(rbum_rel_attr::Column::RelRbumRelId)
1088 .expr_as(Expr::col(rbum_rel_attr::Column::RelRbumRelId).count(), Alias::new("attr_count"))
1089 .from(rbum_rel_attr::Entity)
1090 .and_where(Expr::col(rbum_rel_attr::Column::RecordOnly).eq(false))
1091 .cond_where(attr_conds)
1092 .group_by_col(rbum_rel_attr::Column::RelRbumRelId)
1093 .take(),
1094 attr_table_with_cond.clone(),
1095 Expr::col((attr_table_with_cond.clone(), rbum_rel_attr::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1096 );
1097
1098 query.cond_where(any![
1099 all![
1100 Expr::col((attr_table_without_cond.clone(), Alias::new("attr_count"))).is_null(),
1101 Expr::col((attr_table_with_cond.clone(), Alias::new("attr_count"))).is_null()
1102 ],
1103 Expr::col((attr_table_without_cond.clone(), Alias::new("attr_count"))).eq(Expr::col((attr_table_with_cond.clone(), Alias::new("attr_count"))))
1104 ]);
1105 } else {
1106 query.left_join(
1110 rbum_rel_attr::Entity,
1111 all![
1112 Expr::col((rbum_rel_attr::Entity, rbum_rel_attr::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1113 Expr::col((rbum_rel_attr::Entity, rbum_rel_attr::Column::RecordOnly)).eq(false)
1114 ],
1115 );
1116
1117 query.and_where(Expr::col((rbum_rel_attr::Entity, rbum_rel_attr::Column::Id)).is_null());
1118 }
1119
1120 if !envs.is_empty() {
1121 let env_table_without_cond = Alias::new(format!("{}_without_cond", RbumRelEnvServ::get_table_name()));
1122 let env_table_with_cond = Alias::new(format!("{}_with_cond", RbumRelEnvServ::get_table_name()));
1123
1124 query.join_subquery(
1125 JoinType::LeftJoin,
1126 Query::select()
1127 .column(rbum_rel_env::Column::RelRbumRelId)
1128 .expr_as(Expr::col(rbum_rel_env::Column::RelRbumRelId).count(), Alias::new("env_count"))
1129 .from(rbum_rel_env::Entity)
1130 .group_by_col(rbum_rel_env::Column::RelRbumRelId)
1131 .take(),
1132 env_table_without_cond.clone(),
1133 Expr::col((env_table_without_cond.clone(), rbum_rel_env::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1134 );
1135 let mut env_conds = Cond::any();
1136 for env in envs {
1137 match env.kind {
1138 RbumRelEnvKind::DatetimeRange | RbumRelEnvKind::TimeRange => match env.value.parse::<i64>() {
1139 Ok(num) => {
1140 env_conds = env_conds.add(all![
1141 Expr::col(rbum_rel_env::Column::Kind).eq(env.kind.to_int()),
1142 Expr::expr(Func::cast_as(Expr::col(rbum_rel_env::Column::Value1), Alias::new("INTEGER"))).lte(num),
1143 Expr::expr(Func::cast_as(Expr::col(rbum_rel_env::Column::Value2), Alias::new("INTEGER"))).gte(num)
1144 ]);
1145 }
1146 Err(_) => {
1147 return Err(funs.err().bad_request(
1148 &Self::get_obj_name(),
1149 "check",
1150 &format!("env value {} is not a number", env.value),
1151 "400-rbum-rel-env-value-not-number",
1152 ));
1153 }
1154 },
1155 RbumRelEnvKind::CallFrequency | RbumRelEnvKind::CallCount => match env.value.parse::<i64>() {
1156 Ok(num) => {
1157 env_conds = env_conds.add(all![
1158 Expr::col(rbum_rel_env::Column::Kind).eq(env.kind.to_int()),
1159 Expr::expr(Func::cast_as(Expr::col(rbum_rel_env::Column::Value1), Alias::new("INTEGER"))).gte(num)
1160 ]);
1161 }
1162 Err(_) => {
1163 return Err(funs.err().bad_request(
1164 &Self::get_obj_name(),
1165 "check",
1166 &format!("env value {} is not a number", env.value),
1167 "400-rbum-rel-env-value-not-number",
1168 ));
1169 }
1170 },
1171 RbumRelEnvKind::Ips => {
1172 env_conds = env_conds.add(all![
1173 Expr::col(rbum_rel_env::Column::Kind).eq(env.kind.to_int()),
1174 Expr::col(rbum_rel_env::Column::Value1).like(format!("%{}%", env.value))
1175 ]);
1176 }
1177 }
1178 }
1179 query.join_subquery(
1180 JoinType::LeftJoin,
1181 Query::select()
1182 .column(rbum_rel_env::Column::RelRbumRelId)
1183 .expr_as(Expr::col(rbum_rel_env::Column::RelRbumRelId).count(), Alias::new("env_count"))
1184 .from(rbum_rel_env::Entity)
1185 .cond_where(env_conds)
1186 .group_by_col(rbum_rel_env::Column::RelRbumRelId)
1187 .take(),
1188 env_table_with_cond.clone(),
1189 Expr::col((env_table_with_cond.clone(), rbum_rel_env::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1190 );
1191 query.cond_where(any![
1192 all![
1193 Expr::col((env_table_without_cond.clone(), Alias::new("env_count"))).is_null(),
1194 Expr::col((env_table_with_cond.clone(), Alias::new("env_count"))).is_null()
1195 ],
1196 Expr::col((env_table_without_cond.clone(), Alias::new("env_count"))).eq(Expr::col((env_table_with_cond.clone(), Alias::new("env_count"))))
1197 ]);
1198 } else {
1199 query.left_join(
1203 rbum_rel_env::Entity,
1204 Expr::col((rbum_rel_env::Entity, rbum_rel_env::Column::RelRbumRelId)).equals((rbum_rel::Entity, rbum_rel::Column::Id)),
1205 );
1206
1207 query.and_where(Expr::col((rbum_rel_env::Entity, rbum_rel_env::Column::Id)).is_null());
1208 }
1209
1210 funs.db().count(&query).await.map(|i| i > 0)
1211 }
1212
1213 pub async fn delete_rel_with_ext(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<u64> {
1217 let rbum_rel_env_ids = RbumRelEnvServ::find_id_rbums(
1218 &RbumRelExtFilterReq {
1219 basic: Default::default(),
1220 rel_rbum_rel_id: Some(id.to_string()),
1221 },
1222 None,
1223 None,
1224 funs,
1225 ctx,
1226 )
1227 .await?;
1228 let rbum_rel_attr_ids = RbumRelAttrServ::find_id_rbums(
1229 &RbumRelExtFilterReq {
1230 basic: Default::default(),
1231 rel_rbum_rel_id: Some(id.to_string()),
1232 },
1233 None,
1234 None,
1235 funs,
1236 ctx,
1237 )
1238 .await?;
1239 for rbum_rel_env_id in rbum_rel_env_ids {
1240 RbumRelEnvServ::delete_rbum(&rbum_rel_env_id, funs, ctx).await?;
1241 }
1242 for rbum_rel_attr_id in rbum_rel_attr_ids {
1243 RbumRelAttrServ::delete_rbum(&rbum_rel_attr_id, funs, ctx).await?;
1244 }
1245 RbumRelServ::delete_rbum(id, funs, ctx).await
1246 }
1247}
1248
1249#[async_trait]
1250impl RbumCrudOperation<rbum_rel_attr::ActiveModel, RbumRelAttrAddReq, RbumRelAttrModifyReq, RbumRelAttrDetailResp, RbumRelAttrDetailResp, RbumRelExtFilterReq> for RbumRelAttrServ {
1251 fn get_table_name() -> &'static str {
1252 rbum_rel_attr::Entity.table_name()
1253 }
1254
1255 async fn before_add_rbum(add_req: &mut RbumRelAttrAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
1256 Self::check_ownership_with_table_name(&add_req.rel_rbum_rel_id, RbumRelServ::get_table_name(), funs, ctx).await?;
1257 if let Some(rel_rbum_kind_attr_id) = &add_req.rel_rbum_kind_attr_id {
1258 Self::check_scope(rel_rbum_kind_attr_id, RbumKindAttrServ::get_table_name(), funs, ctx).await?;
1259 }
1260 Ok(())
1261 }
1262
1263 async fn package_add(add_req: &RbumRelAttrAddReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel_attr::ActiveModel> {
1264 let rbum_rel_attr_name = if let Some(rel_rbum_kind_attr_id) = &add_req.rel_rbum_kind_attr_id {
1265 funs.db()
1266 .get_dto::<NameResp>(
1267 Query::select().column(rbum_kind_attr::Column::Name).from(rbum_kind_attr::Entity).and_where(Expr::col(rbum_kind_attr::Column::Id).eq(rel_rbum_kind_attr_id)),
1268 )
1269 .await?
1270 .ok_or_else(|| {
1271 funs.err().not_found(
1272 &Self::get_obj_name(),
1273 "add",
1274 &format!("not found rbum_kind_attr {}", rel_rbum_kind_attr_id),
1275 "404-rbum-rel-not-exist-kind-attr",
1276 )
1277 })?
1278 .name
1279 } else if let Some(name) = &add_req.name {
1280 name.to_string()
1281 } else {
1282 return Err(funs.err().not_found(
1283 &Self::get_obj_name(),
1284 "add",
1285 "[rel_rbum_kind_attr_id] and [name] cannot be empty at the same time",
1286 "400-rbum-rel-name-require",
1287 ));
1288 };
1289
1290 if funs
1291 .db()
1292 .count(
1293 Query::select()
1294 .column(rbum_rel_attr::Column::Id)
1295 .from(rbum_rel_attr::Entity)
1296 .and_where(Expr::col(rbum_rel_attr::Column::RelRbumRelId).eq(&add_req.rel_rbum_rel_id))
1297 .and_where(Expr::col(rbum_rel_attr::Column::Name).eq(&rbum_rel_attr_name)),
1298 )
1299 .await?
1300 > 0
1301 {
1302 return Err(funs.err().conflict(
1303 &Self::get_obj_name(),
1304 "add",
1305 &format!("name {} already exists", rbum_rel_attr_name),
1306 "409-rbum-*-name-exist",
1307 ));
1308 }
1309
1310 Ok(rbum_rel_attr::ActiveModel {
1311 id: Set(TardisFuns::field.nanoid()),
1312 is_from: Set(add_req.is_from),
1313 value: Set(add_req.value.to_string()),
1314 name: Set(rbum_rel_attr_name),
1315 record_only: Set(add_req.record_only),
1316 rel_rbum_kind_attr_id: Set(add_req.rel_rbum_kind_attr_id.as_ref().unwrap_or(&"".to_string()).to_string()),
1317 rel_rbum_rel_id: Set(add_req.rel_rbum_rel_id.to_string()),
1318 ..Default::default()
1319 })
1320 }
1321
1322 async fn package_modify(id: &str, modify_req: &RbumRelAttrModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel_attr::ActiveModel> {
1323 let mut rbum_rel_attr = rbum_rel_attr::ActiveModel {
1324 id: Set(id.to_string()),
1325 ..Default::default()
1326 };
1327 rbum_rel_attr.value = Set(modify_req.value.to_string());
1328 Ok(rbum_rel_attr)
1329 }
1330
1331 async fn package_query(_: bool, filter: &RbumRelExtFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
1332 let mut query = Query::select();
1333 query
1334 .columns(vec![
1335 (rbum_rel_attr::Entity, rbum_rel_attr::Column::Id),
1336 (rbum_rel_attr::Entity, rbum_rel_attr::Column::IsFrom),
1337 (rbum_rel_attr::Entity, rbum_rel_attr::Column::Value),
1338 (rbum_rel_attr::Entity, rbum_rel_attr::Column::Name),
1339 (rbum_rel_attr::Entity, rbum_rel_attr::Column::RecordOnly),
1340 (rbum_rel_attr::Entity, rbum_rel_attr::Column::RelRbumKindAttrId),
1341 (rbum_rel_attr::Entity, rbum_rel_attr::Column::RelRbumRelId),
1342 (rbum_rel_attr::Entity, rbum_rel_attr::Column::OwnPaths),
1343 (rbum_rel_attr::Entity, rbum_rel_attr::Column::Owner),
1344 (rbum_rel_attr::Entity, rbum_rel_attr::Column::CreateTime),
1345 (rbum_rel_attr::Entity, rbum_rel_attr::Column::UpdateTime),
1346 ])
1347 .expr_as(
1348 Expr::col((rbum_kind_attr::Entity, rbum_kind_attr::Column::Name)).if_null(""),
1349 Alias::new("rel_rbum_kind_attr_name"),
1350 )
1351 .from(rbum_rel_attr::Entity)
1352 .left_join(
1353 rbum_kind_attr::Entity,
1354 Expr::col((rbum_kind_attr::Entity, rbum_kind_attr::Column::Id)).equals((rbum_rel_attr::Entity, rbum_rel_attr::Column::RelRbumKindAttrId)),
1355 );
1356 if let Some(rel_rbum_rel_id) = &filter.rel_rbum_rel_id {
1357 query.and_where(Expr::col((rbum_rel_attr::Entity, rbum_rel_attr::Column::RelRbumRelId)).eq(rel_rbum_rel_id.to_string()));
1358 }
1359 query.with_filter(Self::get_table_name(), &filter.basic, true, false, ctx);
1360 Ok(query)
1361 }
1362}
1363
1364#[async_trait]
1365impl RbumCrudOperation<rbum_rel_env::ActiveModel, RbumRelEnvAddReq, RbumRelEnvModifyReq, RbumRelEnvDetailResp, RbumRelEnvDetailResp, RbumRelExtFilterReq> for RbumRelEnvServ {
1366 fn get_table_name() -> &'static str {
1367 rbum_rel_env::Entity.table_name()
1368 }
1369
1370 async fn before_add_rbum(add_req: &mut RbumRelEnvAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
1371 Self::check_ownership_with_table_name(&add_req.rel_rbum_rel_id, RbumRelServ::get_table_name(), funs, ctx).await?;
1372 Ok(())
1373 }
1374
1375 async fn package_add(add_req: &RbumRelEnvAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel_env::ActiveModel> {
1376 Ok(rbum_rel_env::ActiveModel {
1377 id: Set(TardisFuns::field.nanoid()),
1378 kind: Set(add_req.kind.to_int()),
1379 value1: Set(add_req.value1.to_string()),
1380 value2: Set(add_req.value2.as_ref().unwrap_or(&"".to_string()).to_string()),
1381 rel_rbum_rel_id: Set(add_req.rel_rbum_rel_id.to_string()),
1382 ..Default::default()
1383 })
1384 }
1385
1386 async fn package_modify(id: &str, modify_req: &RbumRelEnvModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_rel_env::ActiveModel> {
1387 let mut rbum_rel_env = rbum_rel_env::ActiveModel {
1388 id: Set(id.to_string()),
1389 ..Default::default()
1390 };
1391 if let Some(value1) = &modify_req.value1 {
1392 rbum_rel_env.value1 = Set(value1.to_string());
1393 }
1394 if let Some(value2) = &modify_req.value2 {
1395 rbum_rel_env.value2 = Set(value2.to_string());
1396 }
1397 Ok(rbum_rel_env)
1398 }
1399
1400 async fn package_query(_: bool, filter: &RbumRelExtFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
1401 let mut query = Query::select();
1402 query
1403 .columns(vec![
1404 (rbum_rel_env::Entity, rbum_rel_env::Column::Id),
1405 (rbum_rel_env::Entity, rbum_rel_env::Column::Kind),
1406 (rbum_rel_env::Entity, rbum_rel_env::Column::Value1),
1407 (rbum_rel_env::Entity, rbum_rel_env::Column::Value2),
1408 (rbum_rel_env::Entity, rbum_rel_env::Column::RelRbumRelId),
1409 (rbum_rel_env::Entity, rbum_rel_env::Column::OwnPaths),
1410 (rbum_rel_env::Entity, rbum_rel_env::Column::Owner),
1411 (rbum_rel_env::Entity, rbum_rel_env::Column::CreateTime),
1412 (rbum_rel_env::Entity, rbum_rel_env::Column::UpdateTime),
1413 ])
1414 .from(rbum_rel_env::Entity);
1415
1416 if let Some(rel_rbum_rel_id) = &filter.rel_rbum_rel_id {
1417 query.and_where(Expr::col((rbum_rel_env::Entity, rbum_rel_env::Column::RelRbumRelId)).eq(rel_rbum_rel_id.to_string()));
1418 }
1419 query.with_filter(Self::get_table_name(), &filter.basic, true, false, ctx);
1420 Ok(query)
1421 }
1422}