package condition import ( "encoding/json" "strings" ) // conditionDTO 是 Condition 的 JSON 中间结构,用于避免 UnmarshalJSON 递归 type conditionDTO struct { Type string `json:"type"` Describe string `json:"describe,omitempty"` Exprs []*exprDTO `json:"exprs,omitempty"` Childrens []*conditionDTO `json:"childrens,omitempty"` } type exprDTO struct { Operator string `json:"operator"` Field string `json:"field"` FieldResource string `json:"fieldResource"` FieldSqlFunc string `json:"fieldSqlFunc,omitempty"` FieldSqlFuncParam string `json:"fieldSqlFuncParam,omitempty"` IgnoreEmptyParam bool `json:"ignoreEmptyParam,omitempty"` TokenType TokenType `json:"tokenType"` Token string `json:"token"` } func (this *Condition) UnmarshalJSON(data []byte) error { var dto conditionDTO if err := json.Unmarshal(data, &dto); err != nil { return err } conditionFromDTO(this, &dto) return nil } func (this Condition) MarshalJSON() ([]byte, error) { return json.Marshal(conditionToDTO(&this)) } func (this *ConditionExpr) UnmarshalJSON(data []byte) error { var dto exprDTO if err := json.Unmarshal(data, &dto); err != nil { return err } *this = *exprFromDTO(&dto) return nil } func (this ConditionExpr) MarshalJSON() ([]byte, error) { return json.Marshal(exprToDTO(&this)) } // FromMap 将 map[string]any 转换为 *Condition func FromMap(m map[string]any) (*Condition, error) { data, err := json.Marshal(m) if err != nil { return nil, err } cond := New() if err := json.Unmarshal(data, cond); err != nil { return nil, err } return cond, nil } func conditionFromDTO(c *Condition, dto *conditionDTO) { if strings.EqualFold(dto.Type, "OR") { c.typ = OR } else { c.typ = AND } c.describe = dto.Describe for _, e := range dto.Exprs { c.SetExpr(exprFromDTO(e)) } for _, child := range dto.Childrens { childCond := &Condition{} conditionFromDTO(childCond, child) c.SetCondition(childCond) } } func conditionToDTO(c *Condition) *conditionDTO { typ := "AND" if c.typ == OR { typ = "OR" } dto := &conditionDTO{Type: typ, Describe: c.describe} for _, e := range c.exprs { dto.Exprs = append(dto.Exprs, exprToDTO(e)) } for _, child := range c.childrens { dto.Childrens = append(dto.Childrens, conditionToDTO(child)) } return dto } func exprFromDTO(dto *exprDTO) *ConditionExpr { tokenType := dto.TokenType if tokenType == "" { tokenType = STRING } return &ConditionExpr{ operator: ToConditionOperator(dto.Operator), field: dto.Field, fieldResource: dto.FieldResource, fieldSqlFunc: dto.FieldSqlFunc, fieldSqlFuncParam: dto.FieldSqlFuncParam, ignoreEmptyParma: dto.IgnoreEmptyParam, tokenType: tokenType, token: dto.Token, } } func exprToDTO(e *ConditionExpr) *exprDTO { return &exprDTO{ Operator: operatorToString(e.operator), Field: e.field, FieldResource: e.fieldResource, FieldSqlFunc: e.fieldSqlFunc, FieldSqlFuncParam: e.fieldSqlFuncParam, IgnoreEmptyParam: e.ignoreEmptyParma, TokenType: e.tokenType, Token: e.token, } } func operatorToString(op ConditionOperator) string { switch op { case IS_NULL: return "IS NULL" case IS_NOT_NULL: return "IS NOT NULL" case EQ: return "=" case NE: return "!=" case GT: return ">" case GE: return ">=" case LT: return "<" case LE: return "<=" case LIKE: return "LIKE" case NOT_LIKE: return "NOT LIKE" case IN: return "IN" case NOT_IN: return "NOT IN" case REGEXP: return "REGEXP" case NOT_REGEXP: return "NOT REGEXP" default: return "=" } }