filtering.go 1.68 KB
package webutility

import (
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

type Filter map[string]string

func (f *Filter) Size() int {
	return len(*f)
}

func (f *Filter) Valid() bool {
	return len(*f) > 0
}

func (fs Filter) validate(validFilters []string) (Filter, bool) {
	goodFilters := make(map[string]string)
	cnt := 0
	len := 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(map[string]string, len(kvp))

	for i, _ := range kvp {
		kv := strings.Split(kvp[i], "::")
		if len(kv) == 2 {
			key, _ := url.QueryUnescape(kv[0])
			val, _ := url.QueryUnescape(kv[1])
			filters[key] = val
		}
	}

	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 len(filters) == 0 {
		return "", true
	}

	filters, ok = filters.validate(validFilters)
	if !ok {
		return "", ok
	}

	symbol := "="
	for k, v := range filters {
		if res != "" {
			res += " and "
		} else {
			res += " where "
		}
		c := string(v[0])
		if c == "<" || c == ">" {
			symbol = "" // examples: >3, >=3
		} else {
			symbol = "="
		}

		res += fmt.Sprintf("%s%s %s '%s'", prefix, k, symbol, v)
	}

	return res, ok
}