forked from araddon/qlbridge
/
logic.go
316 lines (283 loc) · 8.55 KB
/
logic.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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package builtins
import (
"fmt"
"math"
u "github.com/araddon/gou"
"github.com/araddon/qlbridge/expr"
"github.com/araddon/qlbridge/value"
)
var _ = u.EMPTY
// Not urnary negation function
//
// not(eq(5,5)) => false, true
// not(eq("false")) => false, true
//
type Not struct{}
// Type bool
func (m *Not) Type() value.ValueType { return value.BoolType }
func (m *Not) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 1 {
return nil, fmt.Errorf("Expected exactly 1 arg for NOT(arg) but got %s", n)
}
return notEval, nil
}
func notEval(ctx expr.EvalContext, args []value.Value) (value.Value, bool) {
boolVal, ok := value.ValueToBool(args[0])
if ok {
return value.NewBoolValue(!boolVal), true
}
return value.BoolValueFalse, false
}
// Equal function? returns true if items are equal
//
// // given context {"name":"wil","event":"stuff", "int4": 4}
//
// eq(int4,5) => false
//
type Eq struct{}
// Type bool
func (m *Eq) Type() value.ValueType { return value.BoolType }
func (m *Eq) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 args for EQ(lh, rh) but got %s", n)
}
return equalEval, nil
}
func equalEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
eq, err := value.Equal(vals[0], vals[1])
if err == nil {
return value.NewBoolValue(eq), true
}
return value.BoolValueFalse, false
}
// Ne Not Equal function? returns true if items are equal
//
// // given {"5s":"5","item4":4,"item4s":"4"}
//
// ne(`5s`,5) => true, true
// ne(`not_a_field`,5) => false, true
// ne(`item4s`,5) => false, true
// ne(`item4`,5) => false, true
//
type Ne struct{}
// Type bool
func (m *Ne) Type() value.ValueType { return value.BoolType }
func (m *Ne) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 args for NE(lh, rh) but got %s", n)
}
return notEqualEval, nil
}
func notEqualEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
eq, err := value.Equal(vals[0], vals[1])
if err == nil {
return value.NewBoolValue(!eq), true
}
return value.BoolValueFalse, false
}
// Gt GreaterThan is left hand > right hand.
// Must be able to convert items to Floats.
//
// gt(5,6) => true, true
type Gt struct{}
// Type bool
func (m *Gt) Type() value.ValueType { return value.BoolType }
func (m *Gt) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 args for Gt(lh, rh) but got %s", n)
}
return greaterThanEval, nil
}
func greaterThanEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
left, _ := value.ValueToFloat64(vals[0])
right, _ := value.ValueToFloat64(vals[1])
if math.IsNaN(left) || math.IsNaN(right) {
return value.BoolValueFalse, false
}
return value.NewBoolValue(left > right), true
}
// Ge GreaterThan or Equal func. Must be able to convert items to Floats.
//
type Ge struct{}
// Type bool
func (m *Ge) Type() value.ValueType { return value.BoolType }
func (m *Ge) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 args for GE(lh, rh) but got %s", n)
}
return greatherThanOrEqualEval, nil
}
func greatherThanOrEqualEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
left, _ := value.ValueToFloat64(vals[0])
right, _ := value.ValueToFloat64(vals[1])
if math.IsNaN(left) || math.IsNaN(right) {
return value.BoolValueFalse, false
}
return value.NewBoolValue(left >= right), true
}
// Le Less Than or Equal. Must be able to convert items to Floats.
//
type Le struct{}
// Type bool
func (m *Le) Type() value.ValueType { return value.BoolType }
func (m *Le) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 args for Le(lh, rh) but got %s", n)
}
return lessThanOrEqualEval, nil
}
func lessThanOrEqualEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
left, _ := value.ValueToFloat64(vals[0])
right, _ := value.ValueToFloat64(vals[1])
if math.IsNaN(left) || math.IsNaN(right) {
return value.BoolValueFalse, false
}
return value.NewBoolValue(left <= right), true
}
// Lt Less Than Must be able to convert items to Floats
//
// lt(5, 6) => true
//
type Lt struct{}
// Type bool
func (m *Lt) Type() value.ValueType { return value.BoolType }
func (m *Lt) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 2 {
return nil, fmt.Errorf("Expected exactly 2 arg for Lt(lh, rh) but got %s", n)
}
return lessThanEval, nil
}
func lessThanEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
left, _ := value.ValueToFloat64(vals[0])
right, _ := value.ValueToFloat64(vals[1])
if math.IsNaN(left) || math.IsNaN(right) {
return value.BoolValueFalse, false
}
return value.NewBoolValue(left < right), true
}
// Exists Answers True/False if the field exists and is non null
//
// exists(real_field) => true
// exists("value") => true
// exists("") => false
// exists(empty_field) => false
// exists(2) => true
// exists(todate(date_field)) => true
//
type Exists struct{}
// Type bool
func (m *Exists) Type() value.ValueType { return value.BoolType }
func (m *Exists) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) != 1 {
return nil, fmt.Errorf("Expected exactly 1 arg for Exists(arg) but got %s", n)
}
return existsEval, nil
}
func existsEval(ctx expr.EvalContext, args []value.Value) (value.Value, bool) {
switch node := args[0].(type) {
// case *expr.IdentityNode:
// _, ok := ctx.Get(node.Text)
// if ok {
// return value.BoolValueTrue, true
// }
// return value.BoolValueFalse, true
// case *expr.StringNode:
// _, ok := ctx.Get(node.Text)
// if ok {
// return value.BoolValueTrue, true
// }
// return value.BoolValueFalse, true
case value.StringValue:
if node.Nil() {
return value.BoolValueFalse, true
}
return value.BoolValueTrue, true
case value.BoolValue:
return value.BoolValueTrue, true
case value.NumberValue:
return value.BoolValueTrue, true
case value.IntValue:
return value.BoolValueTrue, true
case value.TimeValue:
if node.Nil() {
return value.BoolValueFalse, true
}
return value.BoolValueTrue, true
case value.StringsValue, value.SliceValue, value.MapIntValue:
return value.BoolValueTrue, true
case value.JsonValue, value.StructValue:
return value.BoolValueTrue, true
}
return value.BoolValueFalse, true
}
// Any Answers True/False if any of the arguments evaluate to truish (javascripty)
// type definintion of true
//
// Rules for if True:
// int != 0
// string != ""
// boolean natively supported true/false
// time != time.IsZero()
//
// Examples:
// any(item,item2) => true, true
// any(not_field) => false, true
type Any struct{}
// Type bool
func (m *Any) Type() value.ValueType { return value.BoolType }
func (m *Any) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) < 1 {
return nil, fmt.Errorf("Expected 1 or more args for Any(arg, arg, ...) but got %s", n)
}
return anyEval, nil
}
func anyEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
for _, v := range vals {
if v == nil || v.Err() || v.Nil() {
// continue
} else {
return value.NewBoolValue(true), true
}
}
return value.NewBoolValue(false), true
}
// All Answers True/False if all of the arguments evaluate to truish (javascripty)
// type definintion of true. Non-Nil, non-Error, values.
//
// Rules for if True:
// int != 0
// string != ""
// boolean natively supported true/false
// time != time.IsZero()
//
// Examples:
// all("hello",2, true) => true
// all("hello",0,true) => false
// all("",2, true) => false
type All struct{}
func allEval(ctx expr.EvalContext, vals []value.Value) (value.Value, bool) {
for _, v := range vals {
if v.Err() || v.Nil() {
return value.NewBoolValue(false), true
}
switch vt := v.(type) {
case value.BoolValue:
if vt.Val() == false {
return value.NewBoolValue(false), true
}
case value.NumericValue:
if iv := vt.Int(); iv != 0 {
return value.NewBoolValue(false), true
}
}
}
return value.NewBoolValue(true), true
}
func (m *All) Validate(n *expr.FuncNode) (expr.EvaluatorFunc, error) {
if len(n.Args) < 1 {
return nil, fmt.Errorf(`Expected 1 or more args for All(true, tobool(item)) but got %s`, n)
}
return allEval, nil
}
// Type is BoolType for All function
func (m *All) Type() value.ValueType { return value.BoolType }