Add len(filter()) optimization

This commit is contained in:
Anton Medvedev
2023-08-24 11:15:43 +02:00
parent 1963e72aac
commit 22b3d6bf74
3 changed files with 50 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
package optimizer
import (
. "github.com/antonmedv/expr/ast"
)
type filterLen struct{}
func (*filterLen) Visit(node *Node) {
if ln, ok := (*node).(*BuiltinNode); ok &&
ln.Name == "len" &&
len(ln.Arguments) == 1 {
if filter, ok := ln.Arguments[0].(*BuiltinNode); ok &&
filter.Name == "filter" &&
len(filter.Arguments) == 2 {
Patch(node, &BuiltinNode{
Name: "count",
Arguments: filter.Arguments,
})
}
}
}
+1
View File
@@ -33,5 +33,6 @@ func Optimize(node *Node, config *conf.Config) error {
}
Walk(node, &inRange{})
Walk(node, &constRange{})
Walk(node, &filterLen{})
return nil
}
+27
View File
@@ -138,3 +138,30 @@ func TestOptimize_const_expr(t *testing.T) {
assert.Equal(t, ast.Dump(expected), ast.Dump(tree.Node))
}
func TestOptimize_filter_len(t *testing.T) {
tree, err := parser.Parse(`len(filter(users, .Name == "Bob"))`)
require.NoError(t, err)
err = optimizer.Optimize(&tree.Node, nil)
require.NoError(t, err)
expected := &ast.BuiltinNode{
Name: "count",
Arguments: []ast.Node{
&ast.IdentifierNode{Value: "users"},
&ast.ClosureNode{
Node: &ast.BinaryNode{
Operator: "==",
Left: &ast.MemberNode{
Node: &ast.PointerNode{},
Property: &ast.StringNode{Value: "Name"},
},
Right: &ast.StringNode{Value: "Bob"},
},
},
},
}
assert.Equal(t, ast.Dump(expected), ast.Dump(tree.Node))
}