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