package rule import ( "encoding/json" "git.sxidc.com/go-framework/baize/convenient/domain/query_rule/definition" "git.sxidc.com/go-framework/baize/framework/core/domain" "git.sxidc.com/go-framework/baize/framework/core/infrastructure" "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database" "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/clause" "git.sxidc.com/go-framework/baize/framework/core/infrastructure/database/sql" "git.sxidc.com/go-framework/baize/framework/core/tag/rule" "git.sxidc.com/go-tools/utils/strutils" "github.com/pkg/errors" ) const ( LogicalOperatorAnd = "and" LogicalOperatorOr = "or" ) func isSupportedLogicalOperator(logicalOperator string) bool { return logicalOperator == LogicalOperatorAnd || logicalOperator == LogicalOperatorOr } // Rule 规则二叉树 type Rule struct { LogicalOperator string `json:"logicalOperator"` Left *Rule `json:"left"` Right *Rule `json:"right"` FieldName string `json:"fieldName"` FieldType string `json:"fieldType"` Operator string `json:"operator"` Value any `json:"value"` } func (r Rule) check() error { if r.isNode() { return r.checkAsNode() } else { return r.checkAsLeaf() } } func (r Rule) checkAsNode() error { if !isSupportedLogicalOperator(r.LogicalOperator) { return errors.New("不支持的逻辑操作符") } if r.Left == nil { return errors.New("左结点为空") } if r.Right == nil { return errors.New("右结点为空") } if strutils.IsStringNotEmpty(r.Left.LogicalOperator) { err := r.Left.checkAsNode() if err != nil { return err } } else { err := r.Left.checkAsLeaf() if err != nil { return err } } if strutils.IsStringNotEmpty(r.Right.LogicalOperator) { err := r.Right.checkAsNode() if err != nil { return err } } else { err := r.Right.checkAsLeaf() if err != nil { return err } } return nil } func (r Rule) checkAsLeaf() error { if strutils.IsStringEmpty(r.FieldName) { return errors.New("字段名为空") } if !rule.IsSupportedType(r.FieldType) { return errors.New("字段类型不支持") } if !definition.IsSupportedOperator(r.Operator) { return errors.New("操作符不支持") } return nil } func (r Rule) isNode() bool { return strutils.IsStringNotEmpty(r.LogicalOperator) } // HasRule 检查是否存在规则 // 参数: // - dbSchema: 数据库schema // - scope: 范围 // - domainName: 领域名称 // - i: 基础设施 // 返回值: // - 是否存在规则 // - 错误 func HasRule(dbSchema string, scope string, domainName string, i *infrastructure.Infrastructure) (bool, error) { dbExecutor := i.DBExecutor() return database.CheckExist(dbExecutor, &sql.CheckExistExecuteParams{ TableName: domain.TableName(dbSchema, &Entity{}), Conditions: sql.NewConditions(). Equal(ColumnScope, scope). Equal(ColumnDomainName, domainName). Equal(ColumnEnabled, true), }) } // FormConditionClause 获取规则并返回条件语句 // 参数: // - dbSchema: 数据库schema // - scope: 范围 // - domainName: 领域名称 // - i: 基础设施 // - ruleParams: 规则参数 // 返回值: // - 语句接口,当错误为nil时,语句接口也可能是nil,代表该规则并没有被赋值,所以是没有条件的 // - 错误 func FormConditionClause(dbSchema string, scope string, domainName string, i *infrastructure.Infrastructure, ruleParams map[string]any) (clause.Clause, error) { r, err := getEnabledRule(dbSchema, scope, domainName, i) if err != nil { return nil, err } c, err := formConditionClause(domainName, r, ruleParams) if err != nil { return nil, err } return c, nil } // FormConditionClauseByRule 使用Rule结构构造并返回条件语句 // 参数: // - domainName: 领域名称 // - rule: Rule的结构 // - ruleParams: 规则参数 // 返回值: // - 语句接口,当错误为nil时,语句接口也可能是nil,代表该规则并没有被赋值,所以是没有条件的 // - 错误 func FormConditionClauseByRule(domainName string, r Rule, ruleParams map[string]any) (clause.Clause, error) { c, err := formConditionClause(domainName, r, ruleParams) if err != nil { return nil, err } return c, nil } const ( modifyBranchRoot = "root" modifyBranchLeft = "left" modifyBranchRight = "right" ) func ModifyLeafRuleStr(ruleStr string, leafRuleCallback func(leafRule *Rule) error) (string, error) { rootRule := new(Rule) err := json.Unmarshal([]byte(ruleStr), rootRule) if err != nil { return "", err } err = modifyLeafRule(nil, rootRule, modifyBranchRoot, leafRuleCallback) if err != nil { return "", err } newRuleStr, err := json.Marshal(rootRule) if err != nil { return "", err } return string(newRuleStr), nil } func modifyLeafRule(parentRule *Rule, r *Rule, branch string, leafRuleCallback func(leafRule *Rule) error) error { if r == nil { return nil } err := r.check() if err != nil { return err } if !r.isNode() { err := leafRuleCallback(r) if err != nil { return err } if parentRule == nil { return nil } switch branch { case modifyBranchRoot: return nil case modifyBranchLeft: parentRule.Left = r case modifyBranchRight: parentRule.Right = r default: return errors.New("不支持的分支类型: " + branch) } } err = modifyLeafRule(r, r.Left, modifyBranchLeft, leafRuleCallback) if err != nil { return err } err = modifyLeafRule(r, r.Right, modifyBranchRight, leafRuleCallback) if err != nil { return err } return nil } func modifyRule(rootRule *Rule, ruleCallback func(parentRule *Rule, r *Rule, branch string) error) error { if rootRule == nil { return nil } err := rootRule.check() if err != nil { return err } if !rootRule.isNode() { return ruleCallback(nil, rootRule, modifyBranchRoot) } err = ruleCallback(rootRule, rootRule.Left, modifyBranchLeft) if err != nil { return err } if rootRule.Left.isNode() { err := modifyRule(rootRule.Left, ruleCallback) if err != nil { return err } } err = ruleCallback(rootRule, rootRule.Right, modifyBranchRight) if err != nil { return err } if rootRule.Right.isNode() { err := modifyRule(rootRule.Right, ruleCallback) if err != nil { return err } } return nil } func getEnabledRule(dbSchema string, scope string, domainName string, i *infrastructure.Infrastructure) (Rule, error) { dbExecutor := i.DBExecutor() result, err := database.QueryOne(dbExecutor, &sql.QueryOneExecuteParams{ TableName: domain.TableName(dbSchema, &Entity{}), Conditions: sql.NewConditions(). Equal(ColumnScope, scope). Equal(ColumnDomainName, domainName). Equal(ColumnEnabled, true), }) if err != nil { return Rule{}, err } r := new(Rule) err = json.Unmarshal([]byte(result.ColumnValueString(ColumnRule)), r) if err != nil { return Rule{}, err } return *r, nil } func formConditionClause(domainName string, r Rule, ruleParams map[string]any) (clause.Clause, error) { err := r.check() if err != nil { return nil, err } if strutils.IsStringEmpty(r.LogicalOperator) { columnName, err := definition.GetColumnName(domainName, r.FieldName) if err != nil { return nil, err } ruleValue := r.Value if ruleParams != nil { ruleParamValue, ok := ruleParams[columnName] if ok { ruleValue = ruleParamValue } } if ruleValue == nil { return nil, nil } conditions := clause.NewConditions() err = definition.AddCondition(conditions, r.Operator, columnName, ruleValue) if err != nil { return nil, err } return conditions.And(), nil } leftClause, err := formConditionClause(domainName, *r.Left, ruleParams) if err != nil { return nil, err } rightClause, err := formConditionClause(domainName, *r.Right, ruleParams) if err != nil { return nil, err } switch r.LogicalOperator { case LogicalOperatorAnd: return clause.NewConditionJoin(leftClause, rightClause).And(), nil case LogicalOperatorOr: return clause.NewConditionJoin(leftClause, rightClause).Or(), nil default: return clause.NewConditionJoin(leftClause, rightClause).And(), nil } }