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) Count() int { return len(f) } func (f Filter) Add(key, val string) { f[key] = append(f[key], val) } 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.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 }