edge/pkg/storage/filter/filter.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
}