moved filter logic into query
This commit is contained in:
parent
15d372ac55
commit
3b458f6ff1
4 changed files with 94 additions and 70 deletions
68
filter.go
68
filter.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue