Skip to content

Commit c035a48

Browse files
committed
fix(optimizer): wrap merged results as predicates
Ensure combined predicates in consecutive `filter()` calls are wrapped in a `PredicateNode`. Previously, the optimizer created a raw `BinaryNode` for merged filters, causing type assertion panics. The expr parser generates `filter(array, predicate)` calls only. This fix ensures that the merged predicate is wrapped as an `ast.PredicateNode`. Adds a regression test. Signed-off-by: Ville Vesilehto <[email protected]>
1 parent 5ac4a1a commit c035a48

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

optimizer/fold.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,12 @@ func (fold *fold) Visit(node *Node) {
296296
Name: "filter",
297297
Arguments: []Node{
298298
base.Arguments[0],
299-
&BinaryNode{
300-
Operator: "&&",
301-
Left: base.Arguments[1].(*PredicateNode).Node,
302-
Right: n.Arguments[1].(*PredicateNode).Node,
299+
&PredicateNode{
300+
Node: &BinaryNode{
301+
Operator: "&&",
302+
Left: base.Arguments[1].(*PredicateNode).Node,
303+
Right: n.Arguments[1].(*PredicateNode).Node,
304+
},
303305
},
304306
},
305307
})

optimizer/fold_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ func TestOptimize_constant_folding_filter_filter(t *testing.T) {
7070
Value: 2,
7171
},
7272
},
73-
&ast.BoolNode{
74-
Value: true,
73+
&ast.PredicateNode{
74+
Node: &ast.BoolNode{
75+
Value: true,
76+
},
7577
},
7678
},
7779
Throws: false,

test/issues/857/issue_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/expr-lang/expr"
7+
"github.com/expr-lang/expr/internal/testify/require"
8+
)
9+
10+
func TestIssue857(t *testing.T) {
11+
foo := map[string]any{
12+
"entry": map[string]any{
13+
"alpha": "x",
14+
"beta": 1,
15+
},
16+
}
17+
bar := map[string]any{
18+
"entry": map[string]any{
19+
"alpha": "x",
20+
"beta": 1,
21+
},
22+
}
23+
24+
env := map[string]any{
25+
"foo": foo,
26+
"bar": bar,
27+
}
28+
29+
code := `
30+
foo
31+
| keys()
32+
| filter(# in bar)
33+
| filter(foo[#].alpha == bar[#].alpha)
34+
| filter(foo[#].beta == bar[#].beta)
35+
`
36+
37+
_, err := expr.Compile(code, expr.Env(env))
38+
require.NoError(t, err)
39+
}

0 commit comments

Comments
 (0)