From 05fa795f1d15118b526f7f782e300ac58de5813e Mon Sep 17 00:00:00 2001
From: Danis Kirasirov <dbgbbu@gmail.com>
Date: Fri, 26 Jan 2024 09:02:03 +0300
Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?=
 =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?=
 =?UTF-8?q?=D1=8F=20exists?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pkg/expr/expr_test.go  | 1 +
 pkg/expr/mongo.go      | 9 +++++++++
 pkg/expr/mongo_test.go | 1 +
 3 files changed, 11 insertions(+)

diff --git a/pkg/expr/expr_test.go b/pkg/expr/expr_test.go
index 5eafc368..15710da9 100644
--- a/pkg/expr/expr_test.go
+++ b/pkg/expr/expr_test.go
@@ -39,6 +39,7 @@ func TestIsExpression(t *testing.T) {
 		{"time", fmt.Sprintf("d > Time.Time('%s')", now.Format(time.RFC3339)), true},
 		{"in", "In(s, [1,2,3])", true},
 		{"in", "In(s, 1)", true},
+		{"exists", "exists(s)", true},
 		{"text search or id", "id", false},
 		{"numbers", "3", false},
 	}
diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go
index 397043c2..0aa9b29b 100644
--- a/pkg/expr/mongo.go
+++ b/pkg/expr/mongo.go
@@ -404,6 +404,15 @@ func (c *compiler) CallNode(node *ast.CallNode) interface{} {
 		}
 
 		return bson.M{fields: bson.M{"$in": array}}
+	case "exists":
+		field := c.identifier(node.Arguments[0])
+		if field == "" {
+			panic("incorrect argument, empty field name")
+		}
+		return bson.M{"$or": bson.A{
+			bson.M{field: bson.M{"$exists": true, "$type": "array"}},
+			bson.M{field: bson.M{"$ne": nil}},
+		}}
 
 	case "icontains":
 		v := c.identifier(node.Arguments[0])
diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go
index c44296f7..f50b27c2 100644
--- a/pkg/expr/mongo_test.go
+++ b/pkg/expr/mongo_test.go
@@ -30,6 +30,7 @@ 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},
+		{"exists", "exists(s)", nil, bson.M{"$or": bson.A{bson.M{"s": bson.M{"$exists": true, "$type": "array"}}, bson.M{"s": bson.M{"$ne": nil}}}}, 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},
-- 
GitLab