diff --git a/perxis-proto b/perxis-proto index 63410745d6008eaa9d9b00626b5f5b6891ac9189..78fe6a1ea7e2fe588e4107bf14ac85293b201163 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 597180a671e80c2a5bc79bb8efd9bbee940120e4..f0e335786bdad0ecdc0baa7c0cb86b0d1ab32484 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 dee6e668c490a6d375a77c532862f5389b1bd5f4..bbe42465e9a3e46a36430e918c31c81d22c7eb4a 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) } }