package query_rule import ( "encoding/json" "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/sql" "git.sxidc.com/go-framework/baize/framework/core/tag/rule" "git.sxidc.com/go-tools/utils/reflectutils" "git.sxidc.com/go-tools/utils/strutils" "github.com/pkg/errors" "reflect" "strings" ) const ( LogicalOperatorAnd = "and" LogicalOperatorOr = "or" ) func isSupportedLogicalOperator(logicalOperator string) bool { return logicalOperator == LogicalOperatorAnd || logicalOperator == LogicalOperatorOr } type Rule struct { LogicalOperator string `json:"logical_operator"` Left *Rule `json:"left"` Right *Rule `json:"right"` FieldName string `json:"fieldName"` FieldType string `json:"fieldType"` ColumnName string `json:"columnName"` Operator string `json:"operator"` Value any `json:"value"` } func (r Rule) Check() error { if strutils.IsStringNotEmpty(r.LogicalOperator) { 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 strutils.IsStringEmpty(r.ColumnName) { return errors.New("列名为空") } if !IsSupportedOperator(r.Operator) { return errors.New("操作符不支持") } if r.Value == nil { return errors.New("没有传递值") } return nil } func Lint(ruleStr string) error { r := new(Rule) err := json.Unmarshal([]byte(ruleStr), r) if err != nil { return err } return r.Check() } 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, &ValueObject{}), Conditions: sql.NewConditions().Equal(ColumnScope, scope).Equal(ColumnDomainName, domainName), }) } func GetRulesAndFormConditionClause(dbSchema string, scope string, domainName string, i *infrastructure.Infrastructure) (string, []any, error) { r, err := getRule(dbSchema, scope, domainName, i) if err != nil { return "", nil, err } clause, args, err := formConditionClause(r) if err != nil { return "", nil, err } return clause, args, nil } func getRule(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, &ValueObject{}), Conditions: sql.NewConditions().Equal(ColumnScope, scope).Equal(ColumnDomainName, domainName), }) 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(r Rule) (string, []any, error) { if strutils.IsStringEmpty(r.LogicalOperator) { conditions := sql.NewConditions() switch r.Operator { case opEqual: conditions.Equal(r.ColumnName, r.Value) case opNotEqual: conditions.Not(r.ColumnName, r.Value) case opLessThan: conditions.LessThan(r.ColumnName, r.Value) case opLessThanOrEqual: conditions.LessThanAndEqual(r.ColumnName, r.Value) case opGreaterThan: conditions.GreaterThan(r.ColumnName, r.Value) case opGreaterThanOrEqual: conditions.GreaterThanAndEqual(r.ColumnName, r.Value) case opIn: if reflect.TypeOf(r.Value).Kind() != reflect.Slice { return "", nil, errors.New("使用\"包含在列表\"操作符必须使用列表") } conditions.In(r.FieldName, r.Value) case opNotIn: if reflect.TypeOf(r.Value).Kind() != reflect.Slice { return "", nil, errors.New("使用\"不包含在列表\"操作符必须使用列表") } conditions.NotIn(r.FieldName, r.Value) case opPrefix: strValue, err := reflectutils.ToString(r.Value) if err != nil { return "", nil, err } conditions.Like(r.FieldName, strValue+"%") case opSuffix: strValue, err := reflectutils.ToString(r.Value) if err != nil { return "", nil, err } conditions.Like(r.FieldName, "%"+strValue) case opContains: strValue, err := reflectutils.ToString(r.Value) if err != nil { return "", nil, err } conditions.Like(r.FieldName, "%"+strValue+"%") default: return "", nil, errors.Errorf("不支持的操作符%v", r.Operator) } return conditions.And(), conditions.Args(), nil } leftClause, leftArgs, err := formConditionClause(*r.Left) if err != nil { return "", nil, err } rightClause, rightArgs, err := formConditionClause(*r.Right) if err != nil { return "", nil, err } clauseBuilder := strings.Builder{} clauseBuilder.WriteString("(" + leftClause + ")") switch r.LogicalOperator { case LogicalOperatorAnd: clauseBuilder.WriteString(" AND ") case LogicalOperatorOr: clauseBuilder.WriteString(" OR ") } clauseBuilder.WriteString("(" + rightClause + ")") args := make([]any, 0) args = append(args, leftArgs...) args = append(args, rightArgs...) return clauseBuilder.String(), args, nil }