-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
348 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
{ | ||
package filter | ||
|
||
func ParseFilter(expr string, opts ...Option) (Filter, error) { | ||
filter, err := Parse("", []byte(expr), opts...) | ||
if err != nil { | ||
parserErr := err.(errList)[0].(*parserError) | ||
return nil, fmt.Errorf("invalid filter '%s', %s", expr, parserErr.Inner) | ||
} | ||
|
||
return filter.(Filter), nil | ||
} | ||
} | ||
|
||
Rule <- not:BinaryNot group:LogicalFilterGroup op:LogicalOperator group2:LogicalFilterGroup { | ||
chain, err := NewChain(group2.(Filter), op.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
none, err := NewChain(group.(Filter), not.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
chain.Add(none.(Filter)) | ||
|
||
return chain, nil | ||
} | ||
/ not:BinaryNot group:LogicalFilterGroup { | ||
return NewChain(group.(Filter), not.(string)) | ||
} | ||
/ group:LogicalFilterGroup op:LogicalOperator not:BinaryNot group2:LogicalFilterGroup { | ||
none, err := NewChain(group2.(Filter), not.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
chain, err := NewChain(group.(Filter), op.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
chain.Add(none.(Filter)) | ||
|
||
return chain, nil | ||
} | ||
/ group:LogicalFilterGroup & EOF { | ||
return group, nil | ||
} | ||
LogicalFilterGroup <- open:OpenBrace chain:FilterChain clo:ClosingBrace { | ||
return chain, nil | ||
} | ||
/ chain:FilterChain { | ||
return chain, nil | ||
} | ||
FilterChain <- chain:LogicalConditionExpr { | ||
return chain, nil | ||
} | ||
/ cond:Condition rules:LogicalConditionExpr+ { | ||
filters := rules.([]interface{}) | ||
if len(filters) == 0 { | ||
return cond, nil | ||
} | ||
|
||
var rule Chainable | ||
chains := make(map[string]Chainable, 1) | ||
for i := len(filters)-1; i >= 0; i-- { | ||
chain := filters[i].(Chainable) | ||
if i == 0 { | ||
chain.Add(cond.(Filter)) | ||
} | ||
|
||
if i == len(filters)-1 { | ||
rule = chain | ||
continue | ||
} | ||
|
||
// We don't need a nested filter chain of the same type! | ||
if reflect.TypeOf(chain) == reflect.TypeOf(rule) { | ||
rule.Add(chain.Rules()...) | ||
continue | ||
} | ||
|
||
lastRule, ok := chains[reflect.TypeOf(chain).String()] | ||
if !ok { | ||
chains[reflect.TypeOf(chain).String()] = chain | ||
} else { | ||
lastRule.Add(chain.Rules()...) | ||
} | ||
} | ||
|
||
for _, chain := range chains { | ||
rule.Add(chain.(Filter)) | ||
} | ||
|
||
return rule, nil | ||
} | ||
/ cond:Condition { | ||
return cond, nil | ||
} | ||
LogicalConditionExpr <- op:LogicalOperator not:BinaryNot cond:Condition { | ||
chain, err := NewChain(cond.(Filter), not.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return NewChain(chain.(Filter), op.(string)) | ||
} | ||
/ not:BinaryNot cond:Condition { | ||
return NewChain(cond.(Filter), not.(string)) | ||
} | ||
/ op:LogicalOperator cond:Condition { | ||
return NewChain(cond.(Filter), op.(string)) | ||
} | ||
Condition <- col:Identifier op:Operator val:Identifier { | ||
column, err := url.QueryUnescape(col.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
value, err := url.QueryUnescape(val.(string)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return NewCondition(column, op.(string), value) | ||
} | ||
/ expr:ExistsExpr { | ||
return expr, nil | ||
} | ||
ExistsExpr <- col:Identifier &LogicalOperator { | ||
return NewExists(col.(string)) | ||
} | ||
/ col:Identifier &EOF { | ||
return NewExists(col.(string)) | ||
} | ||
Operator <- ( "<=" / ">=" / "!=" / "=" / "<"/ ">" ) { | ||
c.globalStore["lastMatch"] = "op" | ||
return string(c.text), nil | ||
} | ||
OpenBrace <- open:"(" { | ||
val, ok := c.globalStore["braces"] | ||
if !ok { | ||
c.globalStore["braces"] = 1 | ||
} else { | ||
c.globalStore["braces"] = val.(int) + 1 | ||
} | ||
|
||
return string(c.text), nil | ||
} | ||
ClosingBrace <- clos:")" { | ||
val, ok := c.globalStore["braces"] | ||
if !ok { | ||
c.globalStore["braces"] = -1 | ||
} else { | ||
c.globalStore["braces"] = val.(int) - 1 | ||
} | ||
|
||
return string(c.text), nil | ||
} | ||
BinaryNot <- not:"!" { | ||
c.globalStore["lastMatch"] = "logicalOp" | ||
return string(c.text), nil | ||
} | ||
LogicalOperator <- ( "&" / "|" ) { | ||
c.globalStore["lastMatch"] = "logicalOp" | ||
return string(c.text), nil | ||
} | ||
Identifier "column or value" <- [a-zA-Z0-9_%*]+ { | ||
c.globalStore["lastMatch"] = "identifier" | ||
return string(c.text), nil | ||
} | ||
/ ! { | ||
val, ok := c.globalStore["lastMatch"] | ||
if ok && (val == "op" || val == "logicalOp") { | ||
panic(fmt.Sprintf("unexpected '%s' at pos %d", string(c.text), c.pos.col)) | ||
} | ||
|
||
braces, ok := c.globalStore["braces"] | ||
if ok && braces.(int) > 0 { | ||
return false, errors.New("missing closing parenthesis ')'") | ||
} | ||
|
||
if ok && braces.(int) < 0 { | ||
return false, errors.New("missing opening parenthesis '('") | ||
} | ||
|
||
return false, nil | ||
} | ||
EOF <- !. |
Oops, something went wrong.