-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilter.go
120 lines (110 loc) · 2.72 KB
/
filter.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
package filter
import (
"encoding/json"
"fmt"
"strings"
)
var compareOperatorMapping = map[string]uint32{
"$eq": compareEq,
"$ne": compareNotEq,
"$gt": compareGt,
"$gte": compareGte,
"$lt": compareLt,
"$lte": compareLte,
"$in": compareIn,
"$nin": compareNotIn,
}
var logicOperatorMapping = map[string]uint32{
"$and": logicAnd,
"$or": logicOr,
"$not": logicNot,
}
type Filter struct {
rootAlias string
mapping map[string]string
}
func NewFilter(rootAlias string, aliasMap map[string]string) *Filter {
return &Filter{
rootAlias: rootAlias,
mapping: aliasMap,
}
}
func (f *Filter) Parse(query string) (Node, error) {
var q map[string]interface{}
err := json.Unmarshal([]byte(query), &q)
if err != nil {
return nil, err
}
return f.parseNode(q)
}
func (f *Filter) parseNode(node map[string]interface{}) (Node, error) {
var tree Node
for k, v := range node {
// check if field is a operator
if operator, ok := compareOperatorMapping[k]; ok {
fmt.Println(operator)
} else {
var node Node
var err error
// either implicit and or
switch v.(type) {
case string, bool, float64, nil:
node, err = NewCompareNode(f.replaceAlias(k), v, compareEq)
case []interface{}:
node, err = NewCompareNode(f.replaceAlias(k), v, compareIn)
case map[string]interface{}:
node, err = f.parseCompareNode(k, v.(map[string]interface{}))
}
if err != nil {
return nil, err
}
if tree == nil {
tree = node
} else {
tree = f.insertNode(tree, node)
}
}
}
return tree, nil
}
func (f *Filter) parseCompareNode(field string, cmp map[string]interface{}) (node Node, err error) {
if len(cmp) != 1 {
return nil, fmt.Errorf("Object for field %s must contain exactly one key", field)
}
for k, v := range cmp {
operator, ok := compareOperatorMapping[k]
if !ok {
return nil, fmt.Errorf("Unkown compare operator %s", k)
}
node, err = NewCompareNode(f.replaceAlias(field), v, operator)
}
return node, err
}
func (f *Filter) insertNode(tree Node, node Node) Node {
if logicNode, ok := tree.(*LogicNode); ok {
if logicNode.LeftNode == nil {
logicNode.LeftNode = node
} else if logicNode.RightNode == nil {
logicNode.RightNode = node
} else {
tree, _ = NewLogicNode(tree, node, logicNode.Operator)
}
} else {
tree, _ = NewLogicNode(tree, node, logicAnd)
}
return tree
}
func (f *Filter) replaceAlias(field string) string {
if repl, ok := f.mapping[field]; ok {
return repl
}
index := strings.LastIndex(field, ".")
if index == -1 && f.rootAlias != "" {
field = fmt.Sprintf("%s.%s", f.rootAlias, field)
} else if f.mapping != nil {
if prefix, ok := f.mapping[field[0:index]]; ok {
field = strings.Replace(field, field[0:index], prefix, 1)
}
}
return field
}