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
|
package mapr
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/mimecast/dtail/internal/io/logger"
)
// QueryOperation determines the mapreduce operation.
type QueryOperation int
// The possible mapreduce operation.s
const (
UndefQueryOperation QueryOperation = iota
StringEq QueryOperation = iota
StringNe QueryOperation = iota
StringContains QueryOperation = iota
StringNotContains QueryOperation = iota
FloatOperation QueryOperation = iota
FloatEq QueryOperation = iota
FloatNe QueryOperation = iota
FloatLt QueryOperation = iota
FloatLe QueryOperation = iota
FloatGt QueryOperation = iota
FloatGe QueryOperation = iota
)
// Represent a parsed "where" clause, used by mapr.Query
type whereCondition struct {
lType fieldType
lString string
lFloat float64
Operation QueryOperation
rType fieldType
rString string
rFloat float64
}
func (wc *whereCondition) String() string {
return fmt.Sprintf("whereCondition(Operation:%v,lString:%s,lFloat:%v,lType:%s,rString:%s,rFloat:%v,rType:%s)",
wc.Operation, wc.lString, wc.lFloat, wc.lType.String(), wc.rString, wc.rFloat, wc.rType.String())
}
func makeWhereConditions(tokens []token) (where []whereCondition, err error) {
parse := func(tokens []token) (whereCondition, []token, error) {
var wc whereCondition
if len(tokens) < 3 {
return wc, nil, errors.New(invalidQuery + "Not enough arguments in 'where' clause")
}
whereOp := strings.ToLower(tokens[1].str)
switch whereOp {
case "==":
wc.Operation = FloatEq
case "!=":
wc.Operation = FloatNe
case "<":
wc.Operation = FloatLt
case "<=":
wc.Operation = FloatLe
case "=<":
wc.Operation = FloatLe
case ">":
wc.Operation = FloatGt
case ">=":
wc.Operation = FloatGe
case "=>":
wc.Operation = FloatGe
case "eq":
wc.Operation = StringEq
case "ne":
wc.Operation = StringNe
case "contains":
wc.Operation = StringContains
case "lacks":
wc.Operation = StringNotContains
default:
return wc, nil, errors.New(invalidQuery + "Unknown operation in 'where' clause: " + whereOp)
}
wc.lString = tokens[0].str
wc.rString = tokens[2].str
if wc.Operation > FloatOperation {
if !tokens[0].isBareword {
return wc, nil, errors.New(invalidQuery + "Expected bareword at 'where' clause's lValue: " + tokens[0].str)
}
if f, err := strconv.ParseFloat(wc.lString, 64); err == nil {
wc.lFloat = f
wc.lType = Float
} else {
wc.lType = Field
}
if !tokens[2].isBareword {
return wc, nil, errors.New(invalidQuery + "Expected bareword at 'where' clause's rValue: " + tokens[2].str)
}
if f, err := strconv.ParseFloat(wc.rString, 64); err == nil {
wc.rFloat = f
wc.rType = Float
} else {
wc.rType = Field
}
return wc, tokens[3:], nil
}
if tokens[0].isBareword {
wc.lType = Field
} else {
wc.lType = String
}
if tokens[2].isBareword {
wc.rType = Field
} else {
wc.rType = String
}
return wc, tokens[3:], nil
}
for len(tokens) > 0 {
var wc whereCondition
var err error
wc, tokens, err = parse(tokens)
if err != nil {
return nil, err
}
where = append(where, wc)
tokens = tokensConsumeOptional(tokens, "and")
}
return
}
func (wc *whereCondition) floatClause(lValue float64, rValue float64) bool {
switch wc.Operation {
case FloatEq:
return lValue == rValue
case FloatNe:
return lValue != rValue
case FloatLt:
return lValue < rValue
case FloatLe:
return lValue <= rValue
case FloatGt:
return lValue > rValue
case FloatGe:
return lValue >= rValue
default:
logger.Error("Unknown float operation", lValue, wc.Operation, rValue)
}
return false
}
func (wc *whereCondition) stringClause(lValue string, rValue string) bool {
switch wc.Operation {
case StringEq:
return lValue == rValue
case StringNe:
return lValue != rValue
case StringContains:
return strings.Contains(lValue, rValue)
case StringNotContains:
return !strings.Contains(lValue, rValue)
default:
logger.Error("Unknown string operation", lValue, wc.Operation, rValue)
}
return false
}
|