filtering.go
2.43 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
129
130
131
132
133
134
package webutility
import (
"fmt"
"net/http"
"net/url"
"strings"
)
// Filter ...
type Filter map[string][]string
// Get ...
func (f Filter) Get(key string) (values []string, ok bool) {
values, ok = f[key]
return values, ok
}
// Count ...
func (f Filter) Count() int {
return len(f)
}
// Add ...
func (f Filter) Add(key, val string) {
f[key] = append(f[key], val)
}
// ValueAt ...
func (f Filter) ValueAt(val string, index int) string {
if filter, ok := f[val]; ok {
if len(filter) > index {
return filter[index]
}
}
return ""
}
func (f Filter) validate(validFilters []string) (Filter, bool) {
goodFilters := make(Filter)
cnt, len := 0, 0
for fi := range f {
len++
for _, v := range validFilters {
if fi == v {
cnt++
goodFilters[fi] = f[fi]
}
}
}
result := true
if len > 0 && cnt == 0 {
// if no valid filters are found declare filtering request as invalid
result = false
}
return goodFilters, result
}
// ParseFilters 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
}
// MakeFilterString is very dodgy, needs more robustness.
// TODO(marko)
func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) {
if prefix != "" {
prefix += "."
}
if filters.Count() == 0 {
return "", true
}
filters, ok = filters.validate(validFilters)
if !ok {
return "", false
}
first := true
for k, filter := range filters {
symbol := "="
if first {
res += " where "
first = false
} else {
res += " and "
}
res += "("
for i, f := range filter {
if strings.HasPrefix(f, "<") || 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
}