-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfilterql.go
More file actions
128 lines (109 loc) · 2.75 KB
/
filterql.go
File metadata and controls
128 lines (109 loc) · 2.75 KB
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
package filterql
import (
"net/url"
"strconv"
"strings"
)
var (
comparisonOperators = map[string]string{
"eq": " = ",
"lte": " =< ",
"gte": " >= ",
"lt": " < ",
"gt": " > ",
"nt": " <> ",
"lk": " LIKE ",
}
logicalOperators = map[string]string{
"and": " AND ",
"or": " OR ",
}
)
//FilteredResult defines the final output of a parse querystring
type FilteredResult struct {
Field string
Type string
Value interface{}
Operator string
Condition string
}
//QueryStringParser converts URL querystring into a slice of `FilteredResult.`
//Given the querystring `?first_name=john:eq:and&last_name=doe:eq`
func QueryStringParser(queryStr string, filters map[string]string) []FilteredResult {
//define custom map type to allowduplicate keys
type Map struct {
Key string
Value string
}
params := []Map{}
searchFilters := []FilteredResult{}
parts := strings.Split(queryStr, "&")
//build a key/value map of the querystring by
//storing the query as key and the fragment as the value
for _, part := range parts {
split := strings.Split(part, "=")
if len(split) > 1 && split[1] != "" {
params = append(params, Map{
Key: split[0],
Value: split[1],
})
} else {
params = append(params, Map{
Key: split[0],
Value: "",
})
}
}
//
for _, param := range params {
for name, varType := range filters {
if param.Key == name {
esc, _ := url.QueryUnescape(param.Value)
parseValue, operator, condition := RHSParser(esc, varType)
searchFilters = append(searchFilters, FilteredResult{
Field: param.Key,
Type: varType,
Value: parseValue,
Operator: operator,
Condition: condition,
})
break
}
}
}
return searchFilters
}
//RHSParser separates the fragment part of the query string into three parts
//value, comparison operator (=, >, <, <>, <=, >=, LIKE) and logical operator (AND/OR).
func RHSParser(queryStrValue string, valueType string) (value interface{}, comparisonOperator string, logicOperator string) {
var val interface{}
var cOperator string = " = "
var lOperator string = " AND "
parts := strings.Split(queryStrValue, ":")
len := len(parts)
if valueType == "int" {
var number int64
number, _ = strconv.ParseInt(parts[0], 10, 64)
val = number
} else if valueType == "float" {
number := 0.0
number, _ = strconv.ParseFloat(parts[0], 64)
val = number
} else {
val = parts[0]
}
if len == 1 {
cOperator = comparisonOperators["eq"]
lOperator = " AND "
return val, cOperator, lOperator
}
if comparisonOperators[parts[1]] != "" {
cOperator = comparisonOperators[parts[1]]
}
if len == 3 {
if logicalOperators[parts[2]] != "" {
lOperator = logicalOperators[parts[2]]
}
}
return val, cOperator, lOperator
}