From 86e68a0b5655465f576c29f668449cc7e4121f25 Mon Sep 17 00:00:00 2001 From: Danis Kirasirov <dbgbbu@gmail.com> Date: Thu, 11 Jan 2024 16:37:54 +0300 Subject: [PATCH] fix expressions "not in" and "object.field" --- pkg/expr/mongo.go | 25 ++++++++++++++++++++++++- pkg/expr/mongo_test.go | 3 +++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go index 11f124d8..8ff04088 100644 --- a/pkg/expr/mongo.go +++ b/pkg/expr/mongo.go @@ -43,6 +43,7 @@ func convertToMongo(ctx context.Context, tree *parser.Tree, env map[string]inter env[EnvContextKey] = ctx config := GetDefaultConfig(env) + config.Visitors = append(config.Visitors, notinPatcher{}) for _, op := range ops { op(config) @@ -212,6 +213,8 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) interface{} { case "!", "not": return bson.M{"$not": op} + case "": + return op default: panic(fmt.Sprintf("unknown operator (%v)", node.Operator)) } @@ -329,7 +332,7 @@ func (c *compiler) ChainNode(node *ast.ChainNode) string { func (c *compiler) MemberNode(node *ast.MemberNode) string { v := c.compile(node.Node) if val, ok := v.(string); ok { - return fmt.Sprintf("%s.%s", val, node.Property) + return fmt.Sprintf("%s.%s", val, c.compile(node.Property)) } panic(fmt.Sprintf("unsupported property for %v", ast.Dump(node.Node))) } @@ -639,3 +642,23 @@ func (c *compiler) PairNode(node *ast.PairNode) interface{} { //c.compile(node.Key) //c.compile(node.Value) } + +type notinPatcher struct{} + +func (t notinPatcher) Visit(node *ast.Node) { + nodeNot, ok := (*node).(*ast.UnaryNode) + if !ok || nodeNot.Operator != "not" { + return + } + + inNode, ok := nodeNot.Node.(*ast.BinaryNode) + if !ok || inNode.Operator != "in" { + return + } + + nodeNot.Operator = "" + ast.Patch(node, nodeNot) + + inNode.Operator = "not in" + ast.Patch(&nodeNot.Node, inNode) +} \ No newline at end of file diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go index 31cf9e2a..c44296f7 100644 --- a/pkg/expr/mongo_test.go +++ b/pkg/expr/mongo_test.go @@ -30,6 +30,9 @@ func TestConvertToMongo(t *testing.T) { {"equal", "s == 3", nil, bson.M{"s": 3}, false}, {"in array", "s in [1,2,3]", nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false}, {"not in array", "s not in [1,2,3]", nil, bson.M{"s": bson.M{"$nin": []interface{}{1, 2, 3}}}, false}, + {"field#1", "s.test > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, + {"field#2", "s['test'] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, + {"field#3", "s[test] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false}, {"contains", "s contains 'some'", nil, bson.M{"s": bson.M{"$regex": "some"}}, false}, {"contains with . + () $ {} ^", "value contains 'something with . + () $ {} ^'", nil, bson.M{"value": bson.M{"$regex": "something with \\. \\+ \\(\\) \\$ \\{\\} \\^"}}, false}, {"startsWith", "s startsWith 'some'", nil, bson.M{"s": bson.M{"$regex": "^some.*"}}, false}, -- GitLab