151 lines
2.9 KiB
Go
151 lines
2.9 KiB
Go
package filter
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
any = '*'
|
|
anys = string(any)
|
|
)
|
|
|
|
func checkFields(s []string, val string) error {
|
|
for _, v := range s {
|
|
if v == "" {
|
|
return errors.New("invalid subfield: " + val)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func clearFields(s string) []string {
|
|
a := strings.Split(s, " ")
|
|
b := make([]string, len(a))
|
|
c := 0
|
|
for _, v := range a {
|
|
if v != "" {
|
|
b[c] = v
|
|
c++
|
|
}
|
|
}
|
|
return b[:c]
|
|
}
|
|
|
|
type less func(i, j int) bool
|
|
|
|
func reverse(f less) less {
|
|
return func(i, j int) bool {
|
|
return f(j, i)
|
|
}
|
|
}
|
|
|
|
func walkFields(v reflect.Value, fields []string) reflect.Value {
|
|
for i := 0; i < len(fields); i++ {
|
|
if v.Kind() != reflect.Struct {
|
|
return reflect.ValueOf(nil)
|
|
}
|
|
v = v.FieldByName(fields[i])
|
|
}
|
|
return v
|
|
}
|
|
|
|
func index(f Filter, i int, fields []string) (val reflect.Value) {
|
|
return walkFields(reflect.ValueOf(f.Index(i)).FieldByName(fields[0]), fields[1:])
|
|
}
|
|
|
|
func makeLess(f Filter, fields []string) less {
|
|
switch index(f, 0, fields).Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16,
|
|
reflect.Int32, reflect.Int64:
|
|
return func(i, j int) bool { return index(f, i, fields).Int() < index(f, j, fields).Int() }
|
|
case reflect.Float32, reflect.Float64:
|
|
return func(i, j int) bool { return index(f, i, fields).Float() < index(f, j, fields).Float() }
|
|
case reflect.String:
|
|
return func(i, j int) bool { return index(f, i, fields).String() < index(f, j, fields).String() }
|
|
case reflect.Bool:
|
|
return func(i, _ int) bool { return index(f, i, fields).Bool() }
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getValue(v reflect.Value) (s string, b bool, err error) {
|
|
switch v.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16,
|
|
reflect.Int32, reflect.Int64:
|
|
s = strconv.FormatInt(v.Int(), 10)
|
|
case reflect.Float32, reflect.Float64:
|
|
s = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
|
case reflect.String:
|
|
s = v.String()
|
|
case reflect.Bool:
|
|
b = v.Bool()
|
|
default:
|
|
err = errors.New("nil")
|
|
}
|
|
return
|
|
}
|
|
|
|
func matchFunc(v string) func(string) bool {
|
|
vl := len(v)
|
|
switch {
|
|
case vl >= 3:
|
|
if v[0] == any && v[vl-1] == any && v[1] != any && v[vl-2] != any {
|
|
return func(s string) bool {
|
|
return strings.Contains(s, v[1:vl-1])
|
|
}
|
|
}
|
|
fallthrough
|
|
case vl >= 2:
|
|
switch {
|
|
case v[0] == any && v[1] != any:
|
|
return func(s string) bool {
|
|
return strings.HasSuffix(s, v[1:])
|
|
}
|
|
case v[vl-1] == any && v[vl-2] != any:
|
|
return func(s string) bool {
|
|
return strings.HasPrefix(s, v[:vl-1])
|
|
}
|
|
}
|
|
}
|
|
v = strings.Replace(v, anys+anys, anys, -1)
|
|
return func(s string) bool {
|
|
if s == v {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
func ft(b bool) bool {
|
|
if b {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func ff(b bool) bool {
|
|
if !b {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func f(b bool) bool {
|
|
return false
|
|
}
|
|
|
|
func boolFunc(v string) func(bool) bool {
|
|
if len(v) == 0 {
|
|
return f
|
|
}
|
|
if v[0] == 't' {
|
|
return ft
|
|
}
|
|
if v[0] == 'f' {
|
|
return ff
|
|
}
|
|
return f
|
|
}
|