bios-basic 0.2.0

An embeddable message queue system
Documentation
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::vec;
use tardis::db::sea_orm::IdenStatic;
use tardis::regex::Regex;

use async_trait::async_trait;
use tardis::basic::dto::TardisContext;
use tardis::basic::field::TrimString;
use tardis::basic::result::TardisResult;
use tardis::db::reldb_client::IdResp;
use tardis::db::sea_orm::sea_query::*;
use tardis::db::sea_orm::*;
use tardis::TardisFuns;
use tardis::TardisFunsInst;

use crate::rbum::domain::{rbum_item, rbum_item_attr, rbum_kind, rbum_kind_attr, rbum_rel_attr};
use crate::rbum::dto::rbum_filer_dto::RbumKindAttrFilterReq;
use crate::rbum::dto::rbum_filer_dto::RbumKindFilterReq;
use crate::rbum::dto::rbum_kind_attr_dto::{RbumKindAttrAddReq, RbumKindAttrDetailResp, RbumKindAttrModifyReq, RbumKindAttrSummaryResp};
use crate::rbum::dto::rbum_kind_dto::{RbumKindAddReq, RbumKindDetailResp, RbumKindModifyReq, RbumKindSummaryResp};
use crate::rbum::rbum_enumeration::RbumScopeLevelKind;
use crate::rbum::serv::rbum_crud_serv::{RbumCrudOperation, RbumCrudQueryPackage, R_URL_PART_CODE};
use crate::rbum::serv::rbum_item_serv::{RbumItemAttrServ, RbumItemServ};
use crate::rbum::serv::rbum_rel_serv::RbumRelAttrServ;

pub struct RbumKindServ;
pub struct RbumKindAttrServ;

lazy_static! {
    pub static ref EXTRACT_R: Regex = Regex::new(r"\{(.+?)\}").expect("extract {} error");
}

#[async_trait]
impl RbumCrudOperation<rbum_kind::ActiveModel, RbumKindAddReq, RbumKindModifyReq, RbumKindSummaryResp, RbumKindDetailResp, RbumKindFilterReq> for RbumKindServ {
    fn get_table_name() -> &'static str {
        rbum_kind::Entity.table_name()
    }

    async fn before_add_rbum(add_req: &mut RbumKindAddReq, funs: &TardisFunsInst, _: &TardisContext) -> TardisResult<()> {
        if !R_URL_PART_CODE.is_match(&add_req.code) {
            return Err(funs.err().bad_request(&Self::get_obj_name(), "add", &format!("code {} is invalid", add_req.code), "400-rbum-*-code-illegal"));
        }
        if funs.db().count(Query::select().column(rbum_kind::Column::Id).from(rbum_kind::Entity).and_where(Expr::col(rbum_kind::Column::Code).eq(add_req.code.to_string()))).await?
            > 0
        {
            return Err(funs.err().conflict(&Self::get_obj_name(), "add", &format!("code {} already exists", add_req.code), "409-rbum-*-code-exist"));
        }
        Ok(())
    }

    async fn package_add(add_req: &RbumKindAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_kind::ActiveModel> {
        Ok(rbum_kind::ActiveModel {
            id: Set(TardisFuns::field.nanoid()),
            module: Set(add_req.module.as_ref().unwrap_or(&"".to_string()).to_string()),
            code: Set(add_req.code.to_string()),
            name: Set(add_req.name.to_string()),
            note: Set(add_req.note.as_ref().unwrap_or(&"".to_string()).to_string()),
            icon: Set(add_req.icon.as_ref().unwrap_or(&"".to_string()).to_string()),
            sort: Set(add_req.sort.unwrap_or(0)),
            ext_table_name: Set(add_req.ext_table_name.as_ref().unwrap_or(&"".to_string()).to_string()),
            scope_level: Set(add_req.scope_level.as_ref().unwrap_or(&RbumScopeLevelKind::Private).to_int()),
            ..Default::default()
        })
    }

    async fn package_modify(id: &str, modify_req: &RbumKindModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_kind::ActiveModel> {
        let mut rbum_kind = rbum_kind::ActiveModel {
            id: Set(id.to_string()),
            ..Default::default()
        };
        if let Some(module) = &modify_req.module {
            rbum_kind.module = Set(module.to_string());
        }
        if let Some(name) = &modify_req.name {
            rbum_kind.name = Set(name.to_string());
        }
        if let Some(note) = &modify_req.note {
            rbum_kind.note = Set(note.to_string());
        }
        if let Some(icon) = &modify_req.icon {
            rbum_kind.icon = Set(icon.to_string());
        }
        if let Some(sort) = modify_req.sort {
            rbum_kind.sort = Set(sort);
        }
        if let Some(ext_table_name) = &modify_req.ext_table_name {
            rbum_kind.ext_table_name = Set(ext_table_name.to_string());
        }
        if let Some(scope_level) = &modify_req.scope_level {
            rbum_kind.scope_level = Set(scope_level.to_int());
        }
        Ok(rbum_kind)
    }

    async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumKindDetailResp>> {
        Self::check_ownership(id, funs, ctx).await?;
        Self::check_exist_before_delete(id, RbumKindAttrServ::get_table_name(), rbum_kind_attr::Column::RelRbumKindId.as_str(), funs).await?;
        Self::check_exist_before_delete(id, RbumItemServ::get_table_name(), rbum_item::Column::RelRbumKindId.as_str(), funs).await?;
        Ok(None)
    }

    async fn package_query(is_detail: bool, filter: &RbumKindFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
        let mut query = Query::select();
        query.columns(vec![
            (rbum_kind::Entity, rbum_kind::Column::Id),
            (rbum_kind::Entity, rbum_kind::Column::Module),
            (rbum_kind::Entity, rbum_kind::Column::Code),
            (rbum_kind::Entity, rbum_kind::Column::Name),
            (rbum_kind::Entity, rbum_kind::Column::Note),
            (rbum_kind::Entity, rbum_kind::Column::Icon),
            (rbum_kind::Entity, rbum_kind::Column::Sort),
            (rbum_kind::Entity, rbum_kind::Column::ExtTableName),
            (rbum_kind::Entity, rbum_kind::Column::OwnPaths),
            (rbum_kind::Entity, rbum_kind::Column::Owner),
            (rbum_kind::Entity, rbum_kind::Column::CreateTime),
            (rbum_kind::Entity, rbum_kind::Column::UpdateTime),
            (rbum_kind::Entity, rbum_kind::Column::ScopeLevel),
        ]);
        if let Some(module) = &filter.module {
            query.and_where(Expr::col((rbum_kind::Entity, rbum_kind::Column::Module)).eq(module.to_string()));
        }
        query.from(rbum_kind::Entity).with_filter(Self::get_table_name(), &filter.basic, is_detail, true, ctx);
        Ok(query)
    }
}

impl RbumKindServ {
    pub async fn get_rbum_kind_id_by_code(code: &str, funs: &TardisFunsInst) -> TardisResult<Option<String>> {
        let resp = funs
            .db()
            .get_dto::<IdResp>(Query::select().column(rbum_kind::Column::Id).from(rbum_kind::Entity).and_where(Expr::col(rbum_kind::Column::Code).eq(code)))
            .await?
            .map(|r| r.id);
        Ok(resp)
    }
}

#[async_trait]
impl RbumCrudOperation<rbum_kind_attr::ActiveModel, RbumKindAttrAddReq, RbumKindAttrModifyReq, RbumKindAttrSummaryResp, RbumKindAttrDetailResp, RbumKindAttrFilterReq>
    for RbumKindAttrServ
{
    fn get_table_name() -> &'static str {
        rbum_kind_attr::Entity.table_name()
    }

    async fn before_add_rbum(add_req: &mut RbumKindAttrAddReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> {
        Self::check_scope(&add_req.rel_rbum_kind_id, RbumKindServ::get_table_name(), funs, ctx).await?;
        if funs
            .db()
            .count(
                Query::select()
                    .column(rbum_kind_attr::Column::Id)
                    .from(rbum_kind_attr::Entity)
                    .and_where(Expr::col(rbum_kind_attr::Column::Name).eq(add_req.name.to_string()))
                    .and_where(Expr::col(rbum_kind_attr::Column::Module).eq(add_req.module.as_ref().unwrap_or(&TrimString("".to_string())).to_string()))
                    .and_where(Expr::col(rbum_kind_attr::Column::RelRbumKindId).eq(add_req.rel_rbum_kind_id.as_str()))
                    .and_where(Expr::col(rbum_kind_attr::Column::OwnPaths).like(format!("{}%", ctx.own_paths).as_str())),
            )
            .await?
            > 0
        {
            return Err(funs.err().conflict(&Self::get_obj_name(), "add", &format!("name {} already exists", add_req.name), "409-rbum-*-name-exist"));
        }
        Ok(())
    }

    async fn package_add(add_req: &RbumKindAttrAddReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_kind_attr::ActiveModel> {
        Ok(rbum_kind_attr::ActiveModel {
            id: Set(TardisFuns::field.nanoid()),
            module: Set(add_req.module.as_ref().unwrap_or(&TrimString("".to_string())).to_string()),
            name: Set(add_req.name.to_string()),
            label: Set(add_req.label.to_string()),
            note: Set(add_req.note.as_ref().unwrap_or(&"".to_string()).to_string()),
            sort: Set(add_req.sort.unwrap_or(0)),
            position: Set(add_req.position.unwrap_or(false)),
            capacity: Set(add_req.capacity.unwrap_or(false)),
            overload: Set(add_req.overload.unwrap_or(false)),
            secret: Set(add_req.secret.unwrap_or(false)),
            main_column: Set(add_req.main_column.unwrap_or(false)),
            idx: Set(add_req.idx.unwrap_or(false)),
            data_type: Set(add_req.data_type.to_string()),
            widget_type: Set(add_req.widget_type.to_string()),
            widget_columns: Set(add_req.widget_columns.unwrap_or(0)),
            hide: Set(add_req.hide.unwrap_or(false)),
            show_by_conds: Set(add_req.show_by_conds.as_ref().unwrap_or(&"".to_string()).to_string()),
            default_value: Set(add_req.default_value.as_ref().unwrap_or(&"".to_string()).to_string()),
            dyn_default_value: Set(add_req.dyn_default_value.as_ref().unwrap_or(&"".to_string()).to_string()),
            options: Set(add_req.options.as_ref().unwrap_or(&"".to_string()).to_string()),
            dyn_options: Set(add_req.dyn_options.as_ref().unwrap_or(&"".to_string()).to_string()),
            required: Set(add_req.required.unwrap_or(false)),
            min_length: Set(add_req.min_length.unwrap_or(0)),
            max_length: Set(add_req.max_length.unwrap_or(0)),
            action: Set(add_req.action.as_ref().unwrap_or(&"".to_string()).to_string()),
            ext: Set(add_req.ext.as_ref().unwrap_or(&"".to_string()).to_string()),
            parent_attr_name: Set(add_req.parent_attr_name.as_ref().unwrap_or(&TrimString("".to_string())).to_string()),
            rel_rbum_kind_id: Set(add_req.rel_rbum_kind_id.to_string()),
            scope_level: Set(add_req.scope_level.as_ref().unwrap_or(&RbumScopeLevelKind::Private).to_int()),
            ..Default::default()
        })
    }

    async fn package_modify(id: &str, modify_req: &RbumKindAttrModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult<rbum_kind_attr::ActiveModel> {
        let mut rbum_kind_attr = rbum_kind_attr::ActiveModel {
            id: Set(id.to_string()),
            ..Default::default()
        };
        if let Some(label) = &modify_req.label {
            rbum_kind_attr.label = Set(label.to_string());
        }
        if let Some(note) = &modify_req.note {
            rbum_kind_attr.note = Set(note.to_string());
        }
        if let Some(sort) = modify_req.sort {
            rbum_kind_attr.sort = Set(sort);
        }
        if let Some(position) = modify_req.position {
            rbum_kind_attr.position = Set(position);
        }
        if let Some(capacity) = modify_req.capacity {
            rbum_kind_attr.capacity = Set(capacity);
        }
        if let Some(overload) = modify_req.overload {
            rbum_kind_attr.overload = Set(overload);
        }
        if let Some(secret) = modify_req.secret {
            rbum_kind_attr.secret = Set(secret);
        }
        if let Some(main_column) = modify_req.main_column {
            rbum_kind_attr.main_column = Set(main_column);
        }
        if let Some(idx) = modify_req.idx {
            rbum_kind_attr.idx = Set(idx);
        }
        if let Some(data_type) = &modify_req.data_type {
            rbum_kind_attr.data_type = Set(data_type.to_string());
        }
        if let Some(widget_type) = &modify_req.widget_type {
            rbum_kind_attr.widget_type = Set(widget_type.to_string());
        }
        if let Some(widget_columns) = modify_req.widget_columns {
            rbum_kind_attr.widget_columns = Set(widget_columns);
        }
        if let Some(hide) = modify_req.hide {
            rbum_kind_attr.hide = Set(hide);
        }
        if let Some(show_by_conds) = &modify_req.show_by_conds {
            rbum_kind_attr.show_by_conds = Set(show_by_conds.to_string());
        }
        if let Some(default_value) = &modify_req.default_value {
            rbum_kind_attr.default_value = Set(default_value.to_string());
        }
        if let Some(dyn_default_value) = &modify_req.dyn_default_value {
            rbum_kind_attr.dyn_default_value = Set(dyn_default_value.to_string());
        }
        if let Some(options) = &modify_req.options {
            rbum_kind_attr.options = Set(options.to_string());
        }
        if let Some(dyn_options) = &modify_req.dyn_options {
            rbum_kind_attr.dyn_options = Set(dyn_options.to_string());
        }
        if let Some(required) = modify_req.required {
            rbum_kind_attr.required = Set(required);
        }
        if let Some(min_length) = modify_req.min_length {
            rbum_kind_attr.min_length = Set(min_length);
        }
        if let Some(max_length) = modify_req.max_length {
            rbum_kind_attr.max_length = Set(max_length);
        }
        if let Some(action) = &modify_req.action {
            rbum_kind_attr.action = Set(action.to_string());
        }
        if let Some(ext) = &modify_req.ext {
            rbum_kind_attr.ext = Set(ext.to_string());
        }
        if let Some(parent_attr_name) = &modify_req.parent_attr_name {
            rbum_kind_attr.parent_attr_name = Set(parent_attr_name.to_string());
        }
        if let Some(scope_level) = &modify_req.scope_level {
            rbum_kind_attr.scope_level = Set(scope_level.to_int());
        }
        Ok(rbum_kind_attr)
    }

    async fn before_delete_rbum(id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<Option<RbumKindAttrDetailResp>> {
        Self::check_ownership(id, funs, ctx).await?;
        Self::check_exist_before_delete(id, RbumItemAttrServ::get_table_name(), rbum_item_attr::Column::RelRbumKindAttrId.as_str(), funs).await?;
        Self::check_exist_before_delete(id, RbumRelAttrServ::get_table_name(), rbum_rel_attr::Column::RelRbumKindAttrId.as_str(), funs).await?;
        Ok(None)
    }

    async fn package_query(is_detail: bool, filter: &RbumKindAttrFilterReq, _: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<SelectStatement> {
        let mut query = Query::select();
        query
            .columns(vec![
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Id),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Module),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Name),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Label),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Note),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Sort),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Position),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Capacity),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Overload),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Secret),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Idx),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::DataType),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::WidgetType),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::WidgetColumns),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::MainColumn),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Hide),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::ShowByConds),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::DefaultValue),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::DynDefaultValue),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Options),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::DynOptions),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Required),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::MinLength),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::MaxLength),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Action),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Ext),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::ParentAttrName),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::RelRbumKindId),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::OwnPaths),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::Owner),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::CreateTime),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::UpdateTime),
                (rbum_kind_attr::Entity, rbum_kind_attr::Column::ScopeLevel),
            ])
            .from(rbum_kind_attr::Entity);
        if let Some(secret) = filter.secret {
            query.and_where(Expr::col(rbum_kind_attr::Column::Secret).eq(secret));
        }
        if let Some(parent_attr_name) = &filter.parent_attr_name {
            query.and_where(Expr::col(rbum_kind_attr::Column::ParentAttrName).eq(parent_attr_name.to_string()));
        }
        if is_detail {
            query.expr_as(Expr::col((rbum_kind::Entity, rbum_kind::Column::Name)), Alias::new("rel_rbum_kind_name")).inner_join(
                rbum_kind::Entity,
                Expr::col((rbum_kind::Entity, rbum_kind::Column::Id)).equals((rbum_kind_attr::Entity, rbum_kind_attr::Column::RelRbumKindId)),
            );
        }
        query.with_filter(Self::get_table_name(), &filter.basic, is_detail, true, ctx);
        Ok(query)
    }
}

impl RbumKindAttrServ {
    /// URL replace
    ///
    /// URL替换
    ///
    /// Replace ``{key}`` in the URL with the value in values.
    ///
    /// 将URL中的 ``{key}`` 替换为values中的值。
    pub fn url_replace(uri: &str, values: &HashMap<String, String>) -> TardisResult<String> {
        let mut new_uri = uri.to_string();
        for mat in EXTRACT_R.captures_iter(uri) {
            let old_key = mat.get(0).expect("ignore").as_str();
            let key = &old_key[1..old_key.len() - 1];
            if let Some(value) = values.get(key) {
                new_uri = new_uri.replace(old_key, value);
            }
        }
        Ok(new_uri)
    }

    /// Whether the URL contains unreplaced placeholders
    ///
    /// URL中是否包含未替换的占位符
    pub fn url_has_placeholder(uri: &str) -> TardisResult<bool> {
        Ok(!EXTRACT_R.is_match(uri))
    }
}