moved filter logic into query

This commit is contained in:
ston1th 2017-11-12 14:33:39 +01:00
commit 3b458f6ff1
4 changed files with 94 additions and 70 deletions

View file

@ -40,27 +40,41 @@ const (
asc = "asc"
)
// Logic is the filter logic
type Logic int
type logic int
const (
// AND all statements have to match
AND Logic = iota
// OR only one statement has to match
OR
// NOT none of the statements have to match
NOT
undefined logic = iota
and
or
not
)
func parseLogic(s string) (l logic, ok bool) {
ok = true
switch s {
case "AND":
l = and
case "OR":
l = or
case "NOT":
l = not
default:
ok = false
l = and
}
return
}
// Query is the filter query
type Query struct {
q string
m []match
l Logic
l logic
s sorter
}
// NewQuery parses the filter/sort query and match logic
// If the query does not start with a filter logic (AND, OR, NOT), it defaults to AND.
// Examples:
// Explicit match: <struct field>:<struct value>
// Wildcard match (use ** to match the '*' character):
@ -80,11 +94,8 @@ type Query struct {
// sort:<struct field>:asc
// sort:<struct field>:desc
// sort:<struct field>.<struct field>:desc
func NewQuery(s string, l Logic) (q *Query, err error) {
if l > 2 || l < 0 {
l = AND
}
q = &Query{q: s, l: l}
func NewQuery(s string) (q *Query, err error) {
q = &Query{q: s}
if s == "" {
err = errors.New("query is empty")
return
@ -95,6 +106,13 @@ func NewQuery(s string, l Logic) (q *Query, err error) {
if v == "" {
continue
}
if q.l == undefined {
l, ok := parseLogic(v)
q.l = l
if ok {
continue
}
}
if !q.s.enabled {
s := strings.SplitN(v, ":", 3)
if len(s) == 3 {
@ -125,19 +143,19 @@ func NewQuery(s string, l Logic) (q *Query, err error) {
err = errors.New("invalid match: " + v)
return
}
if l == AND {
if q.l == and {
if _, ok := qm[m[0]]; ok {
err = errors.New("field for AND matching used more than once: " + m[0])
return
}
qm[m[0]] = struct{}{}
}
mf := strings.Split(m[0], ".")
if err = checkFields(mf, m[0]); err != nil {
f := strings.Split(m[0], ".")
if err = checkFields(f, m[0]); err != nil {
return
}
q.m = append(q.m, match{
mf,
f,
matchFunc(m[1]),
boolFunc(m[1]),
})
@ -145,8 +163,8 @@ func NewQuery(s string, l Logic) (q *Query, err error) {
if len(q.m) == 0 {
q.s.only = true
}
if len(q.m) == 1 && q.l != NOT {
q.l = OR
if len(q.m) == 1 && q.l != not {
q.l = or
}
return
}
@ -158,16 +176,16 @@ func (q *Query) String() string {
func (q *Query) check(oks []bool) (b bool) {
b = true
switch q.l {
case AND:
case and:
for _, ok := range oks {
if !ok {
b = false
return
}
}
case OR:
case or:
b = false
case NOT:
case not:
for _, ok := range oks {
if ok {
b = false
@ -190,7 +208,7 @@ func (q *Query) match(v reflect.Value) (ok bool) {
oks []bool
match bool
)
if q.l != OR {
if q.l != or {
oks = make([]bool, ql)
}
for i, qv := range q.m {
@ -212,7 +230,7 @@ func (q *Query) match(v reflect.Value) (ok bool) {
default:
match = qv.mf(s)
}
if q.l == OR {
if q.l == or {
if match {
return true
}