filtering.go
2.3 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 webutility
import (
"fmt"
"net/http"
"net/url"
"strings"
)
type Filter map[string][]string
func (f Filter) Get(key string) (values []string, ok bool) {
values, ok = f[key]
return values, ok
}
func (f Filter) Size() int {
return len(f)
}
func (f Filter) IsNotEmpty() bool {
return len(f) > 0
}
func (f Filter) ValueAt(val string, index int) string {
if filter, ok := f[val]; ok {
if len(filter) > index {
return filter[index]
}
}
return ""
}
func (fs Filter) validate(validFilters []string) (Filter, bool) {
goodFilters := make(Filter)
cnt, len := 0, 0
for f, _ := range fs {
len++
for _, v := range validFilters {
if f == v {
cnt++
goodFilters[f] = fs[f]
}
}
}
result := true
if len > 0 && cnt == 0 {
// if no valid filters are found declare filtering request as invalid
result = false
}
return goodFilters, result
}
// requires input in format: "param1::value1|param2::value2..."
func ParseFilters(req *http.Request, header string) (filters Filter) {
q := req.FormValue(header)
q = strings.Trim(q, "\"")
kvp := strings.Split(q, "|")
filters = make(Filter, len(kvp))
for i, _ := range kvp {
kv := strings.Split(kvp[i], "::")
if len(kv) == 2 {
key, _ := url.QueryUnescape(kv[0])
// get values (if more than 1)
vals := strings.Split(kv[1], ",")
for _, v := range vals {
u, _ := url.QueryUnescape(v)
filters[key] = append(filters[key], u)
}
}
}
return filters
}
// TODO(marko): very dodgy, needs more robustness
func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) {
if prefix != "" {
prefix += "."
}
if !filters.IsNotEmpty() {
return "", true
}
filters, ok = filters.validate(validFilters)
if !ok {
return "", false
}
for k, filter := range filters {
first := true
symbol := "="
if first {
res += " and "
first = false
} else {
res += " where "
}
res += "("
for i, f := range filter {
if strings.HasPrefix(f, "<") || strings.HasPrefix(f, ">") {
symbol = string(f[0])
f = strings.TrimLeft(f, "<>")
if strings.HasPrefix(f, "=") {
f = strings.TrimLeft(f, "=")
symbol += "="
}
}
res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, f)
if i < len(filter)-1 {
res += " or "
}
}
res += ")"
}
return res, ok
}