-
Notifications
You must be signed in to change notification settings - Fork 6
/
operationNode.go
308 lines (263 loc) · 6.89 KB
/
operationNode.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
package query
import (
"bytes"
"encoding/gob"
"log"
"strings"
)
type OperationNodeI interface {
nodeContainer
Aliaser
}
// Operator is used internally by the framework to specify an operation to be performed by the database.
// Not all databases can perform all the operations. It will be up to the database driver to sort this out.
type Operator string
const (
// Standard logical operators
OpEqual Operator = "="
OpNotEqual Operator = "<>"
OpAnd = "AND"
OpOr = "OR"
OpXor = "XOR"
OpGreater = ">"
OpGreaterEqual = ">="
OpLess = "<"
OpLessEqual = "<="
// Unary logical
OpNot = "NOT"
OpAll = "1=1"
OpNone = "1=0"
// Math operators
OpAdd = "+"
OpSubtract = "-"
OpMultiply = "*"
OpDivide = "/"
OpModulo = "%"
// Unary math
OpNegate = " -"
// Bit operators
OpBitAnd = "&"
OpBitOr = "|"
OpBitXor = "^"
OpShiftLeft = "<<"
OpShiftRight = ">>"
// Unary bit
OpBitInvert = "~"
// Function operator
// The function name is followed by the operators in parenthesis
OpFunc = "func"
// SQL functions that act like operators in that the operator is put in between the operands
OpLike = "LIKE" // This is very SQL specific and may not be supported in NoSql
OpIn = "IN"
OpNotIn = "NOT IN"
// Special NULL tests
OpNull = "NULL"
OpNotNull = "NOT NULL"
// Our own custom operators for universal support
OpStartsWith = "StartsWith"
OpEndsWith = "EndsWith"
OpContains = "Contains"
OpDateAddSeconds = "AddSeconds" // Adds the given number of seconds to a datetime
)
// String returns a string representation of the Operator type. For convenience, this also corresponds to the SQL
// representation of an operator
func (o Operator) String() string {
return string(o)
}
// An OperationNode is a general purpose structure that specifies an operation on a node or group of nodes.
// The operation could be arithmetic, boolean, or a function.
type OperationNode struct {
nodeAlias
op Operator
operands []NodeI
functionName string // for function operations specific to the db driver
distinct bool // some aggregate queries, particularly count, allow this inside the function
}
// NewOperationNode returns a new operation.
func NewOperationNode(op Operator, operands ...interface{}) *OperationNode {
n := &OperationNode{
op: op,
}
n.assignOperands(operands...)
return n
}
// NewFunctionNode returns an operation node that executes a database function.
func NewFunctionNode(functionName string, operands ...interface{}) *OperationNode {
n := &OperationNode{
op: OpFunc,
functionName: functionName,
}
n.assignOperands(operands...)
return n
}
// NewCountNode creates a Count function node. If no operands are given, it will use * as the parameter to the function
// which means it will count nulls. To NOT count nulls, at least one table name needs to be specified.
func NewCountNode(operands ...NodeI) *OperationNode {
n := &OperationNode{
op: OpFunc,
functionName: "COUNT",
}
for _, op := range operands {
n.operands = append(n.operands, op)
}
return n
}
func (n *OperationNode) nodeType() NodeType {
return OperationNodeType
}
// assignOperands processes the list of operands at run time, making sure all static values are escaped
func (n *OperationNode) assignOperands(operands ...interface{}) {
var op interface{}
if operands != nil {
for _, op = range operands {
if ni, ok := op.(NodeI); ok {
n.operands = append(n.operands, ni)
} else {
n.operands = append(n.operands, NewValueNode(op))
}
}
}
}
/*
func (n *OperationNode) Ascending() *OperationNode {
n.sortDescending = false
return n
}
func (n *OperationNode) Descending() *OperationNode {
n.sortDescending = true
return n
}
*/
// Distinct sets the operation to return distinct results
func (n *OperationNode) Distinct() *OperationNode {
n.distinct = true
return n
}
/*
func (n *OperationNode) sortDesc() bool {
return n.sortDescending
}
*/
// Equals is used internally by the framework to tell if two nodes are equal
func (n *OperationNode) Equals(n2 NodeI) bool {
if cn, ok := n2.(*OperationNode); ok {
if cn.op != n.op {
return false
}
if cn.functionName != n.functionName {
return false
}
/*
if cn.isAggregate != n.isAggregate {
return false
}
*/
/*
if cn.sortDescending != n.sortDescending {
return false
}*/
if cn.operands == nil && n.operands == nil {
return true // neither side has operands, so no need to check further
}
if len(cn.operands) != len(n.operands) {
return false
}
for i, o := range n.operands {
if !o.Equals(cn.operands[i]) {
return false
}
}
return true
}
return false
}
func (n *OperationNode) containedNodes() (nodes []NodeI) {
for _, op := range n.operands {
if nc, ok := op.(nodeContainer); ok {
nodes = append(nodes, nc.containedNodes()...)
} else {
nodes = append(nodes, op)
}
}
return
}
func (n *OperationNode) tableName() string {
return ""
}
func (n *OperationNode) databaseKey() string {
return ""
}
func (n *OperationNode) log(level int) {
tabs := strings.Repeat("\t", level)
log.Print(tabs + "Op: " + n.op.String())
}
func (n *OperationNode) GobEncode() (data []byte, err error) {
var buf bytes.Buffer
e := gob.NewEncoder(&buf)
if err = e.Encode(n.alias); err != nil {
panic(err)
}
if err = e.Encode(n.op); err != nil {
panic(err)
}
if err = e.Encode(n.operands); err != nil {
panic(err)
}
if err = e.Encode(n.functionName); err != nil {
panic(err)
}
if err = e.Encode(n.distinct); err != nil {
panic(err)
}
data = buf.Bytes()
return
}
func (n *OperationNode) GobDecode(data []byte) (err error) {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
if err = dec.Decode(&n.alias); err != nil {
panic(err)
}
if err = dec.Decode(&n.op); err != nil {
panic(err)
}
if err = dec.Decode(&n.operands); err != nil {
panic(err)
}
if err = dec.Decode(&n.functionName); err != nil {
panic(err)
}
if err = dec.Decode(&n.distinct); err != nil {
panic(err)
}
return
}
func init() {
gob.Register(&OperationNode{})
}
// OperationNodeOperator is used internally by the framework to get the operator.
func OperationNodeOperator(n *OperationNode) Operator {
return n.op
}
// OperationNodeOperands is used internally by the framework to get the operands.
func OperationNodeOperands(n *OperationNode) []NodeI {
return n.operands
}
// OperationNodeFunction is used internally by the framework to get the function.
func OperationNodeFunction(n *OperationNode) string {
return n.functionName
}
// OperationNodeDistinct is used internally by the framework to get the distinct value.
func OperationNodeDistinct(n *OperationNode) bool {
return n.distinct
}
/*
func OperationIsAggregate(n *OperationNode) bool {
return n.isAggregate
}
*/
/*
func OperationSortDescending(n *OperationNode) bool {
return n.sortDescending
}
*/