From b42f9cc634bf5f632b026983901637d711d73440 Mon Sep 17 00:00:00 2001
From: ko_oler <kooler89@gmail.com>
Date: Tue, 20 Feb 2024 11:40:59 +0300
Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D1=82?=
 =?UTF-8?q?=D1=8C=20=D1=81=D0=B8=D0=B3=D0=BD=D0=B0=D1=82=D1=83=D1=80=D0=B0?=
 =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20ConvertToMongo?=
 =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20?=
 =?UTF-8?q?=D1=81=20=D0=BC=D0=B0=D1=81=D1=81=D0=B8=D0=B2=D0=BE=D0=BC=20?=
 =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 perxis-proto           |  2 +-
 pkg/expr/mongo.go      | 35 +++++++++++++++++++++++------------
 pkg/expr/mongo_test.go | 20 +++++++++++++++++---
 3 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/perxis-proto b/perxis-proto
index 63410745..78fe6a1e 160000
--- a/perxis-proto
+++ b/perxis-proto
@@ -1 +1 @@
-Subproject commit 63410745d6008eaa9d9b00626b5f5b6891ac9189
+Subproject commit 78fe6a1ea7e2fe588e4107bf14ac85293b201163
diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go
index 597180a6..f0e33578 100644
--- a/pkg/expr/mongo.go
+++ b/pkg/expr/mongo.go
@@ -20,44 +20,55 @@ var geoTypes = map[string]string{
 	"polygon": "$polygon",
 }
 
-func ConvertToMongo(ctx context.Context, exp string, env map[string]interface{}, identifierRenameFn func(string) string, ops ...expr.Option) (b bson.M, err error) {
-	if exp == "" {
+type MongoExprConfig struct {
+	Env                map[string]any
+	IdentifierRenameFn func(s string) string
+	Ops                []expr.Option
+}
+
+func ConvertToMongo(ctx context.Context, config *MongoExprConfig, expressions ...string) (b bson.M, err error) {
+	if len(expressions) == 0 {
 		return bson.M{}, nil
 	}
-	tree, err := parser.Parse(exp)
+	tree, err := parser.Parse("(" + strings.Join(expressions, ") && (") + ")")
 	if err != nil {
 		return nil, err
 	}
-	return convertToMongo(ctx, tree, env, identifierRenameFn, ops...)
+	return convertToMongo(ctx, config, tree)
 }
 
-func convertToMongo(ctx context.Context, tree *parser.Tree, env map[string]interface{}, identifierRenameFn func(string) string, ops ...expr.Option) (b bson.M, err error) {
+func convertToMongo(ctx context.Context, config *MongoExprConfig, tree *parser.Tree) (b bson.M, err error) {
 	defer func() {
 		if r := recover(); r != nil {
 			err = fmt.Errorf("%v", r)
 		}
 	}()
 
+	if config == nil {
+		config = new(MongoExprConfig)
+	}
+
+	env := config.Env
 	if env == nil {
 		env = make(map[string]interface{})
 	}
 
 	env[EnvContextKey] = ctx
-	config := GetDefaultConfig(env)
+	exprConfig := GetDefaultConfig(env)
 
-	for _, op := range ops {
-		op(config)
+	for _, op := range config.Ops {
+		op(exprConfig)
 	}
 
-	env = config.Env.(map[string]interface{})
+	env = exprConfig.Env.(map[string]interface{})
 
-	if len(config.Visitors) >= 0 {
-		for _, v := range config.Visitors {
+	if len(exprConfig.Visitors) >= 0 {
+		for _, v := range exprConfig.Visitors {
 			ast.Walk(&tree.Node, v)
 		}
 	}
 
-	c := &compiler{tree: tree, env: env, config: config, identifierRenameFn: identifierRenameFn}
+	c := &compiler{tree: tree, env: env, config: exprConfig, identifierRenameFn: config.IdentifierRenameFn}
 	v, ok := c.compile(tree.Node).(bson.M)
 	if !ok || v == nil {
 		return nil, fmt.Errorf("invalid expression")
diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go
index dee6e668..bbe42465 100644
--- a/pkg/expr/mongo_test.go
+++ b/pkg/expr/mongo_test.go
@@ -22,12 +22,14 @@ func TestConvertToMongo(t *testing.T) {
 
 	tests := []struct {
 		name    string
-		eval    string
+		eval    any
 		env     map[string]interface{}
 		wantB   bson.M
 		wantErr bool
 	}{
 		{"equal", "s == 3", nil, bson.M{"s": 3}, false},
+		{"equal (with []string)", []string{"object.space_id == 'sp'", "object.organization_id == 'org'"}, nil, bson.M{"$and": bson.A{bson.M{"object.space_id": "sp"}, bson.M{"object.organization_id": "org"}}}, false},
+		{"equal (with nil []string)", nil, nil, bson.M{}, 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#1", "exists(s)", nil, bson.M{"s": bson.M{"$exists": true}}, false},
@@ -80,7 +82,17 @@ func TestConvertToMongo(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			gotB, err := ConvertToMongo(ctx, tt.eval, tt.env, nil)
+
+			var exprs []string
+			switch v := tt.eval.(type) {
+			case []string:
+				exprs = v
+			case string:
+				exprs = []string{v}
+			}
+
+			config := &MongoExprConfig{Env: tt.env}
+			gotB, err := ConvertToMongo(ctx, config, exprs...)
 			if tt.wantErr {
 				require.Error(t, err)
 				return
@@ -102,8 +114,10 @@ func BenchmarkConvertToMongo(b *testing.B) {
 	exp := InStringArray("id", ids)
 	//fmt.Println(len(exp))
 
+	config := &MongoExprConfig{Ops: []expr.Option{expr.Patch(&testVisitor{})}}
+
 	for i := 0; i < b.N; i++ {
-		_, _ = ConvertToMongo(ctx, exp, nil, nil, expr.Patch(&testVisitor{}))
+		_, _ = ConvertToMongo(ctx, config, exp)
 	}
 }
 
-- 
GitLab