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