forked from YaoApp/yao
-
Notifications
You must be signed in to change notification settings - Fork 0
/
condition.go
170 lines (155 loc) · 3.87 KB
/
condition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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
}