137 lines
2.5 KiB
Go
137 lines
2.5 KiB
Go
|
package filter
|
||
|
|
||
|
import (
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type Filter struct {
|
||
|
root Operator
|
||
|
}
|
||
|
|
||
|
func (f *Filter) Root() Operator {
|
||
|
return f.root
|
||
|
}
|
||
|
|
||
|
func New(root Operator) *Filter {
|
||
|
return &Filter{root}
|
||
|
}
|
||
|
|
||
|
func NewFrom(raw map[string]interface{}) (*Filter, error) {
|
||
|
if len(raw) != 1 {
|
||
|
return nil, errors.WithStack(ErrInvalidRoot)
|
||
|
}
|
||
|
|
||
|
op, err := toFieldOperator(raw)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &Filter{op}, nil
|
||
|
}
|
||
|
|
||
|
func toFieldOperator(v interface{}) (Operator, error) {
|
||
|
vv, ok := v.(map[string]interface{})
|
||
|
if !ok {
|
||
|
return nil, errors.WithStack(ErrInvalidFieldOperator)
|
||
|
}
|
||
|
|
||
|
ops := make([]Operator, 0)
|
||
|
|
||
|
for rawToken, val := range vv {
|
||
|
var (
|
||
|
op Operator
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
token := Token(rawToken)
|
||
|
|
||
|
switch {
|
||
|
case isAggregatorToken(token):
|
||
|
op, err = toAggregateOperator(token, val)
|
||
|
|
||
|
case isFieldToken(token):
|
||
|
fields, ok := val.(map[string]interface{})
|
||
|
if !ok {
|
||
|
return nil, errors.WithStack(ErrInvalidFieldMap)
|
||
|
}
|
||
|
|
||
|
switch token {
|
||
|
case TokenEq:
|
||
|
op = NewEqOperator(fields)
|
||
|
case TokenNeq:
|
||
|
op = NewNeqOperator(fields)
|
||
|
case TokenGt:
|
||
|
op = NewGtOperator(fields)
|
||
|
case TokenGte:
|
||
|
op = NewGteOperator(fields)
|
||
|
case TokenLt:
|
||
|
op = NewLtOperator(fields)
|
||
|
case TokenLte:
|
||
|
op = NewLteOperator(fields)
|
||
|
case TokenIn:
|
||
|
op = NewInOperator(fields)
|
||
|
case TokenLike:
|
||
|
op = NewLikeOperator(fields)
|
||
|
default:
|
||
|
return nil, errors.Wrapf(ErrUnknownOperator, "unknown operator field '%s'", token)
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return nil, errors.Wrapf(ErrUnknownOperator, "unknown operator field '%s'", token)
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ops = append(ops, op)
|
||
|
}
|
||
|
|
||
|
and := NewAndOperator(ops...)
|
||
|
|
||
|
return and, nil
|
||
|
}
|
||
|
|
||
|
func toAggregateOperator(token Token, v interface{}) (Operator, error) {
|
||
|
vv, ok := v.([]interface{})
|
||
|
if !ok {
|
||
|
return nil, errors.WithStack(ErrInvalidAggregationOperator)
|
||
|
}
|
||
|
|
||
|
ops := make([]Operator, 0)
|
||
|
|
||
|
for _, c := range vv {
|
||
|
op, err := toFieldOperator(c)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ops = append(ops, op)
|
||
|
}
|
||
|
|
||
|
var aggregator Operator
|
||
|
|
||
|
switch token {
|
||
|
case TokenAnd:
|
||
|
aggregator = NewAndOperator(ops...)
|
||
|
case TokenOr:
|
||
|
aggregator = NewOrOperator(ops...)
|
||
|
case TokenNot:
|
||
|
aggregator = NewNotOperator(ops...)
|
||
|
}
|
||
|
|
||
|
return aggregator, nil
|
||
|
}
|
||
|
|
||
|
func isAggregatorToken(token Token) bool {
|
||
|
return token == TokenAnd || token == TokenOr || token == TokenNot
|
||
|
}
|
||
|
|
||
|
func isFieldToken(token Token) bool {
|
||
|
return token == TokenEq ||
|
||
|
token == TokenGt || token == TokenGte ||
|
||
|
token == TokenLt || token == TokenLte ||
|
||
|
token == TokenNeq || token == TokenIn ||
|
||
|
token == TokenLike
|
||
|
}
|