diff --git a/pkg/expr/expr_test.go b/pkg/expr/expr_test.go index 5eafc368bed934e0bd0805f4818442a75256931c..15710da9fb3933690f677e1f9305288a786bac8b 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 397043c2fc9e99ad26498b3aecbf87280ac795a1..0aa9b29b7d261d47834f61f3bf87028f4f1c76c0 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 c44296f7110381852d8b6ecb570eb8445f3c0c37..f50b27c2d8827197e001caad82341c47065c93e5 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},