package helper
import (
"fmt"
"regexp"
"strings"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/kun/any"
)
// ComputeFunc 计算函数
type ComputeFunc func(interface{}, interface{}) bool
// Computes å¯ç”¨è®¡ç®—å¼
var Computes = map[string]ComputeFunc{
"=": func(left interface{}, right interface{}) bool {
return left == right
},
">": func(left interface{}, right interface{}) bool {
return any.Of(left).CFloat64() > any.Of(right).CFloat64()
},
">=": func(left interface{}, right interface{}) bool {
return any.Of(left).CFloat64() >= any.Of(right).CFloat64()
},
"<": func(left interface{}, right interface{}) bool {
return any.Of(left).CFloat64() < any.Of(right).CFloat64()
},
"<=": func(left interface{}, right interface{}) bool {
return any.Of(left).CFloat64() <= any.Of(right).CFloat64()
},
"!=": func(left interface{}, right interface{}) bool {
return left != right
},
"hasprefix": func(left interface{}, right interface{}) bool {
return strings.HasPrefix(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
},
"hassuffix": func(left interface{}, right interface{}) bool {
return strings.HasSuffix(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
},
"contains": func(left interface{}, right interface{}) bool {
return strings.Contains(fmt.Sprintf("%v", left), fmt.Sprintf("%v", right))
},
"match": func(left interface{}, right interface{}) bool {
re := regexp.MustCompile(fmt.Sprintf("%v", right))
return re.Match([]byte(fmt.Sprintf("%v", left)))
},
"is": func(left interface{}, right interface{}) bool {
if is, ok := right.(string); ok {
is = strings.ToLower(is)
if is == "null" {
return left == nil
} else if is == "notnull" {
return left != nil
}
}
return false
},
}
// Condition 判æ–æ¡ä»¶
type Condition struct {
Left interface{} `json:"left"`
Right interface{} `json:"right"`
Compute ComputeFunc `json:"-"`
OP string `json:"op"`
OR bool `json:"or"`
Comment string `json:"comment"`
}
// When 多项æ¡ä»¶åˆ¤æ–
func When(conds []Condition) bool {
res := true
for _, cond := range conds {
if cond.OR {
res = res || cond.Exec()
continue
}
res = res && cond.Exec()
}
return res
}
// Exec 执行æ¡ä»¶åˆ¤æ–
func (cond Condition) Exec() bool {
return cond.Compute(cond.Left, cond.Right)
}
// UnmarshalJSON for json marshalJSON
func (cond *Condition) UnmarshalJSON(data []byte) error {
origin := map[string]interface{}{}
err := jsoniter.Unmarshal(data, &origin)
if err != nil {
return err
}
*cond = ConditionOf(origin)
return nil
}
// MarshalJSON for json marshalJSON
func (cond Condition) MarshalJSON() ([]byte, error) {
return jsoniter.Marshal(cond.ToMap())
}
// ConditionOf 从 map[string]interface{}
func ConditionOf(input map[string]interface{}) Condition {
cond := Condition{}
for k, val := range input {
key := strings.ToLower(k)
// { "=": "foo" }
if compute, has := Computes[key]; has {
cond.Right = val
cond.Compute = compute
cond.OP = k
continue
}
switch key {
case "left":
cond.Left = val
continue
case "right":
cond.Right = val
continue
case "op":
if val, ok := val.(string); ok {
if compute, has := Computes[val]; has {
cond.Compute = compute
cond.OP = val
}
}
continue
case "or":
if val, ok := val.(bool); ok {
cond.OR = val
}
continue
case "comment":
if val, ok := val.(string); ok {
cond.Comment = val
}
continue
}
// { "用户ä¸å˜åœ¨": "bar"},
cond.Comment = key
cond.Left = val
}
return cond
}
// ToMap Condition 转æ¢ä¸º map[string]interface{}
func (cond Condition) ToMap() map[string]interface{} {
res := map[string]interface{}{}
if cond.OP != "" {
res[cond.OP] = cond.Right
}
if cond.Comment != "" {
res[cond.Comment] = cond.Left
} else {
res["left"] = cond.Left
res["right"] = cond.Right
}
if cond.OR {
res["or"] = true
}
return res
}