Commit dcfc40497987d8c2eceff79446bf29135ced7b10

Authored by Marko Tikvić
1 parent edd7c4f4d7
Exists in master

improved filtering

Showing 1 changed file with 47 additions and 23 deletions   Show diff stats
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "net/http" 5 "net/http"
6 "net/url" 6 "net/url"
7 "strings" 7 "strings"
8 ) 8 )
9 9
10 type Filter map[string]string 10 type Filter map[string][]string
11 11
12 func (f *Filter) Size() int { 12 func (f Filter) Get(key string) (values []string, ok bool) {
13 return len(*f) 13 values, ok = f[key]
14 return values, ok
14 } 15 }
15 16
16 func (f *Filter) Valid() bool { 17 func (f Filter) Size() int {
17 return len(*f) > 0 18 return len(f)
19 }
20
21 func (f Filter) IsNotEmpty() bool {
22 return len(f) > 0
18 } 23 }
19 24
20 func (fs Filter) validate(validFilters []string) (Filter, bool) { 25 func (fs Filter) validate(validFilters []string) (Filter, bool) {
21 goodFilters := make(map[string]string) 26 goodFilters := make(Filter)
22 cnt := 0 27 cnt, len := 0, 0
23 len := 0
24 for f, _ := range fs { 28 for f, _ := range fs {
25 len++ 29 len++
26 for _, v := range validFilters { 30 for _, v := range validFilters {
27 if f == v { 31 if f == v {
28 cnt++ 32 cnt++
29 goodFilters[f] = fs[f] 33 goodFilters[f] = fs[f]
30 } 34 }
31 } 35 }
32 } 36 }
33 37
34 result := true 38 result := true
35 if len > 0 && cnt == 0 { 39 if len > 0 && cnt == 0 {
36 // if no valid filters are found declare filtering request as invalid 40 // if no valid filters are found declare filtering request as invalid
37 result = false 41 result = false
38 } 42 }
39 43
40 return goodFilters, result 44 return goodFilters, result
41 } 45 }
42 46
43 // requires input in format: "param1::value1|param2::value2..." 47 // requires input in format: "param1::value1|param2::value2..."
44 func ParseFilters(req *http.Request, header string) (filters Filter) { 48 func ParseFilters(req *http.Request, header string) (filters Filter) {
45 q := req.FormValue(header) 49 q := req.FormValue(header)
46 q = strings.Trim(q, "\"") 50 q = strings.Trim(q, "\"")
47 kvp := strings.Split(q, "|") 51 kvp := strings.Split(q, "|")
48 filters = make(map[string]string, len(kvp)) 52 filters = make(Filter, len(kvp))
49 53
50 for i, _ := range kvp { 54 for i, _ := range kvp {
51 kv := strings.Split(kvp[i], "::") 55 kv := strings.Split(kvp[i], "::")
52 if len(kv) == 2 { 56 if len(kv) == 2 {
53 key, _ := url.QueryUnescape(kv[0]) 57 key, _ := url.QueryUnescape(kv[0])
54 val, _ := url.QueryUnescape(kv[1]) 58
55 filters[key] = val 59 // get values (if more than 1)
60 vals := strings.Split(kv[1], ",")
61 for _, v := range vals {
62 u, _ := url.QueryUnescape(v)
63 filters[key] = append(filters[key], u)
64 }
56 } 65 }
57 } 66 }
58 67
59 return filters 68 return filters
60 } 69 }
61 70
62 // TODO(marko): very dodgy, needs more robustness 71 // TODO(marko): very dodgy, needs more robustness
63 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) { 72 func MakeFilterString(prefix string, filters Filter, validFilters []string) (res string, ok bool) {
64 if prefix != "" { 73 if prefix != "" {
65 prefix += "." 74 prefix += "."
66 } 75 }
67 if len(filters) == 0 { 76
77 if !filters.IsNotEmpty() {
68 return "", true 78 return "", true
69 } 79 }
70 80
71 filters, ok = filters.validate(validFilters) 81 filters, ok = filters.validate(validFilters)
72 if !ok { 82 if !ok {
73 return "", ok 83 return "", false
74 } 84 }
75 85
76 symbol := "=" 86 for k, filter := range filters {
77 for k, v := range filters { 87 first := true
78 if res != "" { 88 symbol := "="
89
90 if first {
79 res += " and " 91 res += " and "
92 first = false
80 } else { 93 } else {
81 res += " where " 94 res += " where "
82 } 95 }
83 c := string(v[0])
84 if c == "<" || c == ">" {
85 symbol = "" // examples: >3, >=3
86 } else {
87 symbol = "="
88 }
89 96
90 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v) 97 res += "("
98 for i, f := range filter {
99 if strings.HasPrefix(f, "<") || strings.HasPrefix(f, ">") {
100 symbol = string(f[0])
101 f = strings.TrimLeft(f, "<>")
102 if strings.HasPrefix(f, "=") {
103 f = strings.TrimLeft(f, "=")
104 symbol += "="
105 }
106 }
107
108 res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, f)
109
110 if i < len(filter)-1 {
111 res += " or "
112 }