From 46b70309a39ad75e365f55d650efd087fc40f4a1 Mon Sep 17 00:00:00 2001 From: ljl <17743125563@163.com> Date: Wed, 26 Jun 2024 14:53:32 +0800 Subject: [PATCH] iam:fix org stats. --- .../src/basic/serv/clients/iam_kv_client.rs | 37 +++-- .../basic/serv/clients/iam_stats_client.rs | 132 ++++++++++++++++++ .../iam/src/basic/serv/iam_role_serv.rs | 7 +- .../iam/src/basic/serv/iam_set_serv.rs | 24 ++-- .../supports/iam/src/console_common/api.rs | 1 + .../src/console_common/api/iam_cc_org_api.rs | 2 +- .../console_common/api/iam_cc_org_task_api.rs | 28 ++++ .../supports/iam/src/console_common/serv.rs | 1 + .../serv/iam_cc_org_task_serv.rs | 84 +++++++++++ frontend/sdks/invoke/Cargo.toml | 3 +- frontend/sdks/invoke/src/clients.rs | 2 + .../invoke/src/clients/spi_search_client.rs | 1 + .../invoke/src/clients/spi_stats_client.rs | 33 +++++ frontend/sdks/invoke/src/dto.rs | 1 + .../sdks/invoke/src/dto/stats_record_dto.rs | 79 +++++++++++ 15 files changed, 401 insertions(+), 34 deletions(-) create mode 100644 backend/supports/iam/src/basic/serv/clients/iam_stats_client.rs create mode 100644 backend/supports/iam/src/console_common/api/iam_cc_org_task_api.rs create mode 100644 backend/supports/iam/src/console_common/serv/iam_cc_org_task_serv.rs create mode 100644 frontend/sdks/invoke/src/clients/spi_stats_client.rs create mode 100644 frontend/sdks/invoke/src/dto/stats_record_dto.rs diff --git a/backend/supports/iam/src/basic/serv/clients/iam_kv_client.rs b/backend/supports/iam/src/basic/serv/clients/iam_kv_client.rs index ecba2f44f..1f23542ab 100644 --- a/backend/supports/iam/src/basic/serv/clients/iam_kv_client.rs +++ b/backend/supports/iam/src/basic/serv/clients/iam_kv_client.rs @@ -34,18 +34,13 @@ impl IamKvClient { .await } - pub async fn async_add_or_modify_key_name( - key: String, - name: String, - _funs: &TardisFunsInst, - ctx: &TardisContext, - ) -> TardisResult<()> { + pub async fn async_add_or_modify_key_name(tag: String, key: String, name: String, _funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { let ctx_clone = ctx.clone(); ctx.add_async_task(Box::new(|| { Box::pin(async move { let task_handle = tokio::spawn(async move { let funs = iam_constants::get_tardis_inst(); - let _ = Self::add_or_modify_key_name(&key, &name, &funs, &ctx_clone).await; + let _ = Self::add_or_modify_key_name(&tag, &key, &name, &funs, &ctx_clone).await; }); task_handle.await.unwrap(); Ok(()) @@ -69,6 +64,21 @@ impl IamKvClient { .await } + pub async fn async_delete_key_name(tag: String, key: String, _funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let ctx_clone = ctx.clone(); + ctx.add_async_task(Box::new(|| { + Box::pin(async move { + let task_handle = tokio::spawn(async move { + let funs = iam_constants::get_tardis_inst(); + let _ = Self::delete_key_name(&tag, &key, &funs, &ctx_clone).await; + }); + task_handle.await.unwrap(); + Ok(()) + }) + })) + .await + } + pub async fn add_or_modify_item( key: &str, value: &Value, @@ -80,13 +90,12 @@ impl IamKvClient { SpiKvClient::add_or_modify_item(key, value, info, scope_level.map(|kind| kind.to_int()), funs, ctx).await } - pub async fn add_or_modify_key_name( - key: &str, - name: &str, - funs: &TardisFunsInst, - ctx: &TardisContext, - ) -> TardisResult<()> { - SpiKvClient::add_or_modify_key_name(key, name, funs, ctx).await + pub async fn add_or_modify_key_name(tag: &str, key: &str, name: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + SpiKvClient::add_or_modify_key_name(&format!("{}:{}", tag, key), name, funs, ctx).await + } + + pub async fn delete_key_name(tag: &str, key: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + SpiKvClient::delete_item(&format!("__k_n__:{}:{}", tag, key), funs, ctx).await } pub async fn delete_item(key: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { diff --git a/backend/supports/iam/src/basic/serv/clients/iam_stats_client.rs b/backend/supports/iam/src/basic/serv/clients/iam_stats_client.rs new file mode 100644 index 000000000..6531c0ca1 --- /dev/null +++ b/backend/supports/iam/src/basic/serv/clients/iam_stats_client.rs @@ -0,0 +1,132 @@ +use bios_basic::rbum::{ + dto::rbum_filer_dto::{RbumBasicFilterReq, RbumSetCateFilterReq, RbumSetFilterReq, RbumSetItemFilterReq}, + serv::{ + rbum_crud_serv::RbumCrudOperation, + rbum_set_serv::{RbumSetCateServ, RbumSetItemServ, RbumSetServ}, + }, +}; +use bios_sdk_invoke::{clients::spi_stats_client::SpiStatsClient, dto::stats_record_dto::StatsFactRecordLoadReq}; +use itertools::Itertools; + +use tardis::{ + basic::{dto::TardisContext, result::TardisResult}, + serde_json::json, + tokio, TardisFunsInst, +}; + +use crate::{ + iam_config::{IamBasicConfigApi, IamConfig}, + iam_constants, + iam_enumeration::IamSetKind, +}; + +use super::iam_kv_client::IamKvClient; +pub struct IamStatsClient; + +impl IamStatsClient { + pub async fn async_org_fact_record_load(org_cate_id: String, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let ctx_clone = ctx.clone(); + let org_cate = RbumSetCateServ::get_rbum( + &org_cate_id, + &RbumSetCateFilterReq { + basic: RbumBasicFilterReq { + with_sub_own_paths: true, + own_paths: Some("".to_owned()), + ..Default::default() + }, + ..Default::default() + }, + funs, + ctx, + ) + .await?; + let set = RbumSetServ::get_rbum( + &org_cate.rel_rbum_set_id, + &RbumSetFilterReq { + basic: RbumBasicFilterReq { + with_sub_own_paths: true, + own_paths: Some("".to_owned()), + ..Default::default() + }, + ..Default::default() + }, + funs, + ctx, + ) + .await?; + // 只允许组织 Set 继续执行 + if set.kind != IamSetKind::Org.to_string() { + return Ok(()); + } + let account_ids = RbumSetItemServ::find_rbums( + &RbumSetItemFilterReq { + basic: RbumBasicFilterReq { + with_sub_own_paths: true, + own_paths: Some("".to_owned()), + ..Default::default() + }, + rel_rbum_item_disabled: Some(false), + // rel_rbum_set_id: Some(org_set_id), + rel_rbum_set_cate_ids: Some(vec![org_cate_id.clone()]), + rel_rbum_item_kind_ids: Some(vec![funs.iam_basic_kind_account_id()]), + ..Default::default() + }, + None, + None, + funs, + &ctx_clone, + ) + .await? + .into_iter() + .map(|resp| resp.rel_rbum_item_id) + .collect(); + ctx.add_async_task(Box::new(|| { + Box::pin(async move { + let task_handle = tokio::spawn(async move { + let funs = iam_constants::get_tardis_inst(); + let _ = Self::org_fact_record_load(org_cate_id.clone(), account_ids, &funs, &ctx_clone).await; + let _ = IamKvClient::async_add_or_modify_key_name(funs.conf::().spi.kv_orgs_prefix.clone(), org_cate_id, org_cate.name, &funs, &ctx_clone).await; + }); + task_handle.await.unwrap(); + Ok(()) + }) + })) + .await + } + + pub async fn org_fact_record_load(org_id: String, account_id: Vec, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let add_req = StatsFactRecordLoadReq { + own_paths: ctx.own_paths.clone(), + ct: tardis::chrono::Utc::now(), + data: json!({ + "org_id": org_id, + "account_ids": account_id, + "account_num": account_id.len(), + }), + ext: None, + }; + SpiStatsClient::fact_record_load(&funs.conf::().spi.kv_orgs_prefix.clone(), &org_id, add_req, funs, ctx).await?; + Ok(()) + } + + pub async fn async_org_fact_record_remove(org_id: String, _funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let ctx_clone = ctx.clone(); + ctx.add_async_task(Box::new(|| { + Box::pin(async move { + let task_handle = tokio::spawn(async move { + let funs = iam_constants::get_tardis_inst(); + let _ = Self::org_fact_record_remove(org_id.clone(), &funs, &ctx_clone).await; + let _ = IamKvClient::async_delete_key_name(funs.conf::().spi.kv_orgs_prefix.clone(), org_id, &funs, &ctx_clone).await; + }); + task_handle.await.unwrap(); + Ok(()) + }) + })) + .await + } + + pub async fn org_fact_record_remove(org_id: String, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + SpiStatsClient::fact_record_delete(&funs.conf::().spi.kv_orgs_prefix.clone(), &org_id, funs, ctx).await?; + Ok(()) + } +} diff --git a/backend/supports/iam/src/basic/serv/iam_role_serv.rs b/backend/supports/iam/src/basic/serv/iam_role_serv.rs index 466ac4b2c..0cfa1af07 100644 --- a/backend/supports/iam/src/basic/serv/iam_role_serv.rs +++ b/backend/supports/iam/src/basic/serv/iam_role_serv.rs @@ -117,7 +117,7 @@ impl RbumItemCrudOperation().spi.kv_orgs_prefix.clone(), result.clone().unwrap()), - &add_req.name, - funs, - ctx, - ) - .await?; + IamStatsClient::async_org_fact_record_load(result.clone().unwrap(), &funs, &ctx).await?; } if result.is_ok() { kind.make_ascii_lowercase(); @@ -269,13 +264,7 @@ impl IamSetServ { ) .await?; } else if kind == IamSetKind::Org.to_string() && result.is_ok() { - SpiKvClient::add_or_modify_key_name( - &format!("{}:{}", funs.conf::().spi.kv_orgs_prefix.clone(), &set_cate_id), - &set_cate_item.name.clone(), - funs, - ctx, - ) - .await?; + IamStatsClient::async_org_fact_record_load(set_cate_id.to_owned(), &funs, &ctx).await?; } kind.make_ascii_lowercase(); match kind.as_str() { @@ -340,6 +329,9 @@ impl IamSetServ { if result.is_ok() { let mut kind = item.kind; + if kind == IamSetKind::Org.to_string() { + IamStatsClient::async_org_fact_record_remove(set_cate_id.to_owned(), &funs, &ctx).await?; + } kind.make_ascii_lowercase(); let (op_describe, tag, op_kind) = match kind.as_str() { "org" => ("删除部门".to_string(), Some(LogParamTag::IamOrg), Some("Delete".to_string())), @@ -621,6 +613,7 @@ impl IamSetServ { ) .await; let _ = IamSearchClient::async_add_or_modify_account_search(&add_req.rel_rbum_item_id, Box::new(true), "", funs, ctx).await; + IamStatsClient::async_org_fact_record_load(set_cate_id.clone(), &funs, &ctx).await?; } result @@ -647,6 +640,9 @@ impl IamSetServ { let result = RbumSetItemServ::delete_rbum(set_item_id, funs, ctx).await; if result.is_ok() && item.rel_rbum_item_kind_id == funs.iam_basic_kind_account_id() { + if let Some(cate_id) = item.rel_rbum_set_cate_id.clone() { + IamStatsClient::async_org_fact_record_load(cate_id, &funs, &ctx).await?; + } if let Ok(account) = IamAccountServ::get_item(item.rel_rbum_item_id.clone().as_str(), &IamAccountFilterReq::default(), funs, ctx).await { let _ = IamLogClient::add_ctx_task( LogParamTag::IamOrg, diff --git a/backend/supports/iam/src/console_common/api.rs b/backend/supports/iam/src/console_common/api.rs index 5d4eef78b..b5c47e33b 100644 --- a/backend/supports/iam/src/console_common/api.rs +++ b/backend/supports/iam/src/console_common/api.rs @@ -5,6 +5,7 @@ pub mod iam_cc_app_api; pub mod iam_cc_app_set_api; pub mod iam_cc_config_api; pub mod iam_cc_org_api; +pub mod iam_cc_org_task_api; pub mod iam_cc_res_api; pub mod iam_cc_role_api; pub mod iam_cc_system_api; diff --git a/backend/supports/iam/src/console_common/api/iam_cc_org_api.rs b/backend/supports/iam/src/console_common/api/iam_cc_org_api.rs index 5f7b2e68c..3be7672b7 100644 --- a/backend/supports/iam/src/console_common/api/iam_cc_org_api.rs +++ b/backend/supports/iam/src/console_common/api/iam_cc_org_api.rs @@ -3,7 +3,7 @@ use crate::basic::serv::iam_set_serv::IamSetServ; use crate::iam_constants; use bios_basic::helper::request_helper::try_set_real_ip_from_req_to_ctx; use bios_basic::rbum::dto::rbum_filer_dto::RbumSetTreeFilterReq; -use bios_basic::rbum::dto::rbum_set_dto::{RbumSetTreeCateNodeResp, RbumSetTreeCateResp, RbumSetTreeResp}; +use bios_basic::rbum::dto::rbum_set_dto::{RbumSetTreeCateNodeResp, RbumSetTreeResp}; use bios_basic::rbum::rbum_enumeration::RbumSetCateLevelQueryKind; use tardis::web::context_extractor::TardisContextExtractor; use tardis::web::poem::Request; diff --git a/backend/supports/iam/src/console_common/api/iam_cc_org_task_api.rs b/backend/supports/iam/src/console_common/api/iam_cc_org_task_api.rs new file mode 100644 index 000000000..b161fead4 --- /dev/null +++ b/backend/supports/iam/src/console_common/api/iam_cc_org_task_api.rs @@ -0,0 +1,28 @@ +use bios_basic::{helper::request_helper::try_set_real_ip_from_req_to_ctx, process::task_processor::TaskProcessor}; +use tardis::web::{ + context_extractor::TardisContextExtractor, + poem::Request, + poem_openapi, + web_resp::{TardisApiResult, TardisResp}, +}; + +use crate::{console_common::serv::iam_cc_org_task_serv::IamCcOrgTaskServ, iam_constants}; + +#[derive(Clone, Default)] +pub struct IamCcOrgTaskApi; + +/// Common Console Org task API +#[poem_openapi::OpenApi(prefix_path = "/cc/org/task", tag = "bios_basic::ApiTag::Common")] +impl IamCcOrgTaskApi { + #[oai(path = "/", method = "get")] + async fn execute_org_task(&self, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult> { + try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?; + let funs = iam_constants::get_tardis_inst(); + IamCcOrgTaskServ::execute_org_task(&funs, &ctx.0).await?; + if let Some(task_id) = TaskProcessor::get_task_id_with_ctx(&ctx.0).await? { + TardisResp::accepted(Some(task_id)) + } else { + TardisResp::ok(None) + } + } +} diff --git a/backend/supports/iam/src/console_common/serv.rs b/backend/supports/iam/src/console_common/serv.rs index 16891bc51..589210ae4 100644 --- a/backend/supports/iam/src/console_common/serv.rs +++ b/backend/supports/iam/src/console_common/serv.rs @@ -1,2 +1,3 @@ pub mod iam_cc_account_task_serv; +pub mod iam_cc_org_task_serv; pub mod iam_cc_role_task_serv; diff --git a/backend/supports/iam/src/console_common/serv/iam_cc_org_task_serv.rs b/backend/supports/iam/src/console_common/serv/iam_cc_org_task_serv.rs new file mode 100644 index 000000000..cfa62f771 --- /dev/null +++ b/backend/supports/iam/src/console_common/serv/iam_cc_org_task_serv.rs @@ -0,0 +1,84 @@ +use crate::{ + basic::serv::clients::iam_stats_client::IamStatsClient, + iam_config::IamConfig, + iam_constants, + iam_enumeration::IamSetKind, + iam_initializer::{default_iam_send_avatar, ws_iam_send_client}, +}; +use bios_basic::{ + process::task_processor::TaskProcessor, + rbum::{ + dto::rbum_filer_dto::{RbumBasicFilterReq, RbumSetCateFilterReq, RbumSetFilterReq}, + serv::{ + rbum_crud_serv::RbumCrudOperation, + rbum_set_serv::{RbumSetCateServ, RbumSetServ}, + }, + }, +}; + +use tardis::{ + basic::{dto::TardisContext, result::TardisResult}, + TardisFunsInst, +}; + +pub struct IamCcOrgTaskServ; + +impl IamCcOrgTaskServ { + pub async fn execute_org_task(funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult> { + let task_ctx = ctx.clone(); + TaskProcessor::execute_task_with_ctx( + &funs.conf::().cache_key_async_task_status, + move |_task_id| async move { + let mut funs = iam_constants::get_tardis_inst(); + funs.begin().await?; + let base_org_set_ids = RbumSetServ::find_id_rbums( + &RbumSetFilterReq { + basic: RbumBasicFilterReq { + own_paths: Some("".to_string()), + with_sub_own_paths: true, + ..Default::default() + }, + kind: Some(IamSetKind::Org.to_string()), + ..Default::default() + }, + None, + None, + &funs, + &task_ctx, + ) + .await?; + for org_set_id in base_org_set_ids { + let base_org_set_cate_ids = RbumSetCateServ::find_id_rbums( + &RbumSetCateFilterReq { + basic: RbumBasicFilterReq { + own_paths: Some("".to_string()), + with_sub_own_paths: true, + ..Default::default() + }, + rel_rbum_set_id: Some(org_set_id.clone()), + ..Default::default() + }, + None, + None, + &funs, + &task_ctx, + ) + .await?; + for org_set_cate_id in base_org_set_cate_ids { + IamStatsClient::async_org_fact_record_load(org_set_cate_id, &funs, &task_ctx).await?; + } + } + funs.commit().await?; + task_ctx.execute_task().await?; + Ok(()) + }, + &funs.cache(), + ws_iam_send_client().await.clone(), + default_iam_send_avatar().await.clone(), + Some(vec![format!("account/{}", ctx.owner)]), + ctx, + ) + .await?; + Ok(None) + } +} diff --git a/frontend/sdks/invoke/Cargo.toml b/frontend/sdks/invoke/Cargo.toml index 3e0d21865..8eefec087 100644 --- a/frontend/sdks/invoke/Cargo.toml +++ b/frontend/sdks/invoke/Cargo.toml @@ -15,11 +15,12 @@ name = "bios_sdk_invoke" path = "src/lib.rs" [features] -default = ["spi_kv", "spi_log", "spi_search", "iam", "event"] +default = ["spi_kv", "spi_log", "spi_search", "spi_stats", "iam", "event"] spi_base = [] spi_kv = ["spi_base"] spi_log = ["spi_base"] spi_search = ["spi_base"] +spi_stats = ["spi_base"] iam = [] event = [] macro = ["dep:simple-invoke-client-macro"] diff --git a/frontend/sdks/invoke/src/clients.rs b/frontend/sdks/invoke/src/clients.rs index 8e7067aac..5c728de8e 100644 --- a/frontend/sdks/invoke/src/clients.rs +++ b/frontend/sdks/invoke/src/clients.rs @@ -21,6 +21,8 @@ pub mod spi_kv_client; pub mod spi_log_client; #[cfg(feature = "spi_search")] pub mod spi_search_client; +#[cfg(feature = "spi_stats")] +pub mod spi_stats_client; #[cfg(feature = "iam")] pub mod iam_client; diff --git a/frontend/sdks/invoke/src/clients/spi_search_client.rs b/frontend/sdks/invoke/src/clients/spi_search_client.rs index b94199019..d5a6b76eb 100644 --- a/frontend/sdks/invoke/src/clients/spi_search_client.rs +++ b/frontend/sdks/invoke/src/clients/spi_search_client.rs @@ -38,6 +38,7 @@ impl SpiSearchClient { let search_url = BaseSpiClient::module_url(InvokeModuleKind::Search, funs).await?; let headers = BaseSpiClient::headers(None, funs, ctx).await?; funs.web_client().delete_to_void(&format!("{search_url}/ci/item/{tag}/{key}"), headers.clone()).await?; + SpiKvClient::delete_item(&format!("__k_n__:{tag}:{key}"), funs, ctx).await?; Ok(()) } } diff --git a/frontend/sdks/invoke/src/clients/spi_stats_client.rs b/frontend/sdks/invoke/src/clients/spi_stats_client.rs new file mode 100644 index 000000000..11805c2c0 --- /dev/null +++ b/frontend/sdks/invoke/src/clients/spi_stats_client.rs @@ -0,0 +1,33 @@ +use tardis::basic::dto::TardisContext; +use tardis::basic::result::TardisResult; +use tardis::TardisFunsInst; + +use crate::dto::stats_record_dto::StatsFactRecordLoadReq; +use crate::invoke_enumeration::InvokeModuleKind; + +use super::base_spi_client::BaseSpiClient; + +pub struct SpiStatsClient; + +impl SpiStatsClient { + pub async fn fact_record_load(fact_key: &str, record_key: &str, add_req: StatsFactRecordLoadReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let stats_url: String = BaseSpiClient::module_url(InvokeModuleKind::Stats, funs).await?; + let headers = BaseSpiClient::headers(None, funs, ctx).await?; + funs.web_client().put_obj_to_str(&format!("{stats_url}/ci/record/fact/{fact_key}/{record_key}"), &add_req, headers.clone()).await?; + Ok(()) + } + + pub async fn fact_records_load(fact_key: &str, add_req: Vec, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let stats_url: String = BaseSpiClient::module_url(InvokeModuleKind::Stats, funs).await?; + let headers = BaseSpiClient::headers(None, funs, ctx).await?; + funs.web_client().put_obj_to_str(&format!("{stats_url}/ci/record/fact/{fact_key}/batch/load"), &add_req, headers.clone()).await?; + Ok(()) + } + + pub async fn fact_record_delete(fact_key: &str, record_key: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let stats_url = BaseSpiClient::module_url(InvokeModuleKind::Stats, funs).await?; + let headers = BaseSpiClient::headers(None, funs, ctx).await?; + funs.web_client().delete_to_void(&format!("{stats_url}/ci/record/fact/{fact_key}/{record_key}"), headers.clone()).await?; + Ok(()) + } +} diff --git a/frontend/sdks/invoke/src/dto.rs b/frontend/sdks/invoke/src/dto.rs index e9e9e951a..d3aa7b032 100644 --- a/frontend/sdks/invoke/src/dto.rs +++ b/frontend/sdks/invoke/src/dto.rs @@ -1 +1,2 @@ pub mod search_item_dto; +pub mod stats_record_dto; \ No newline at end of file diff --git a/frontend/sdks/invoke/src/dto/stats_record_dto.rs b/frontend/sdks/invoke/src/dto/stats_record_dto.rs new file mode 100644 index 000000000..cd592e5d1 --- /dev/null +++ b/frontend/sdks/invoke/src/dto/stats_record_dto.rs @@ -0,0 +1,79 @@ +use serde::{Deserialize, Serialize}; +use tardis::{ + chrono::{DateTime, Utc}, + serde_json::Value, + web::poem_openapi, +}; + +/// 事实记录加载请求对象 +/// Load Fact Record Request Object +#[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] +pub struct StatsFactRecordLoadReq { + /// Own paths + pub own_paths: String, + /// Create time + pub ct: DateTime, + /// Field data + /// 字段数据 + /// + /// Map format,key = field name of the fact table,value = field value + /// Map格式,key=事实表的字段名,value=字段值 + pub data: Value, + /// Dynamic data + /// + /// 动态数据 + pub ext: Option, +} +/// Load Fact Record Request Object +/// +/// 事实记录加载请求对象 +#[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] +pub struct StatsFactRecordsLoadReq { + /// Primary key + pub key: String, + /// Own paths + pub own_paths: String, + /// Create time + pub ct: DateTime, + /// Field data + /// 字段数据 + /// + /// Map format,key = field name of the fact table,value = field value + /// Map格式,key=事实表的字段名,value=字段值 + pub data: Value, + + /// Dynamic data + /// + /// 动态数据 + pub ext: Option, +} + +/// Add Dimension Record Request Object +/// +/// 添加维度记录请求对象 +#[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] +pub struct StatsDimRecordAddReq { + /// Primary key + /// + /// 主键 + pub key: Value, + /// The name of the dimension + /// + /// 显示名称 + pub show_name: String, + /// The parent primary key, if present, indicates that this is a multilevel record + /// + /// 父主键,如果存在,表示这是一个多级记录 + pub parent_key: Option, +} + +/// Delete Dimension Record Request Object +/// +/// 删除维度记录请求对象 +#[derive(poem_openapi::Object, Serialize, Deserialize, Debug)] +pub struct StatsDimRecordDeleteReq { + /// Primary key + /// + /// 主键 + pub key: Value, +}