diff --git a/pkg/filter/filter_test.go b/pkg/filter/filter_test.go index 22770bc7a20120375461b443b9144019e330a499..7283e26a0dfebcc5159211e49c30dc29150f12db 100644 --- a/pkg/filter/filter_test.go +++ b/pkg/filter/filter_test.go @@ -1,20 +1,14 @@ package filter import ( - "context" - "fmt" - "os" "testing" "time" "git.perx.ru/perxis/perxis-go/pkg/schema" "git.perx.ru/perxis/perxis-go/pkg/schema/field" - "git.perx.ru/perxis/perxis-go/pkg/schema/validate" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" ) func TestFilterHandler(t *testing.T) { @@ -227,253 +221,253 @@ func TestFilterHandler(t *testing.T) { }) } -func TestFilterHandler_Integration(t *testing.T) { - ctx := context.Background() - - uri := os.Getenv("MONGO_URL") - if uri == "" { - uri = "mongodb://localhost:27017" - } - opts := options.Client().SetConnectTimeout(15 * time.Second).ApplyURI(uri) - client, err := mongo.Connect(context.Background(), opts) - require.NoError(t, err) - err = client.Ping(ctx, nil) - require.NoError(t, err) - - sch := schema.New( - "name", field.String(validate.Required()), - "color", field.String(), - "qty", field.Number(field.NumberFormatInt), - "info", field.Object( - "is_fruit", field.Bool(), - "similar", field.Array( - field.Object( - "name", field.Number(field.NumberFormatFloat), - "color", field.String(), - ), - ), - "desc", field.String(), - ), - "produced", field.Time(), - "shipment", field.Array(field.String()), - ) - - w1, _ := time.Parse(time.RFC3339, "2020-01-01T10:08:41Z") - w2, _ := time.Parse(time.RFC3339, "2020-05-01T10:08:41Z") - w3, _ := time.Parse(time.RFC3339, "2020-10-01T10:08:41Z") - - items := []map[string]interface{}{ - { - "name": "apple", - "color": "red", - "qty": 25, - "info": map[string]interface{}{ - "is_fruit": true, - "similar": []interface{}{ - map[string]interface{}{"name": "pear", "color": "yellow"}, - map[string]interface{}{"name": "lemon", "color": "yellow"}, - }, - "desc": "An apple is the edible fruit . Apple trees are cultivated worldwide and have religious and mythological " + - "significance in many cultures. Apples are eaten with honey at the Jewish New Year of Rosh Hashanah to symbolize a sweet new year.", - }, - "produced": w1, - "shipment": []interface{}{"Russia", "Iran"}, - "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.751472, 37.618727}}, - }, - { - "name": "orange", - "color": "orange", - "qty": 10, - "info": map[string]interface{}{ - "is_fruit": true, - "similar": []interface{}{ - map[string]interface{}{"name": "lemon", "color": "yellow"}, - map[string]interface{}{"name": "grapefruit", "color": "red"}, - }, - "desc": "The orange is the edible fruit of various citrus species; a hybrid between pomelo and mandarin. Orange trees are widely grown" + - " in tropical and subtropical climates for their sweet fruit. The fruit of the orange tree can be eaten fresh, or processed for its juice or fragrant peel.", - }, - "produced": w2, - "shipment": []interface{}{"Egypt", "Iran"}, - "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.716797, 37.552809}}, - }, - { - "name": "tomato", - "color": "red", - "qty": 1, - "info": map[string]interface{}{ - "is_fruit": false, - "similar": []interface{}{ - map[string]interface{}{"name": "cucumber", "color": "green"}, - map[string]interface{}{"name": "apple", "color": "yellow"}, - }, - "desc": "The tomato is the edible red berry. The tomato is consumed in diverse ways, raw or cooked, in many dishes, " + - "sauces, salads, and drinks. Numerous varieties of the tomato plant are widely grown in temperate climates across the world.", - }, - "produced": w3, - "shipment": []interface{}{"Russia", "Italy"}, - "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.760688, 37.619125}}, - }, - } - - db := client.Database("perxis_test_filter") - coll := db.Collection("items") - coll.Drop(ctx) - - for _, item := range items { - _, err = coll.InsertOne(ctx, item) - require.NoError(t, err) - } - - h := NewFilterHandler(sch) - h.SetQueryBuilder(NewMongoQueryBuilder()) - - t.Run("By Color [Equal/NotEqual]", func(t *testing.T) { - t.Run("Red", func(t *testing.T) { - query := h.Query(&Filter{Op: Equal, Field: "color", Value: "red"}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) - t.Run("Not Red", func(t *testing.T) { - query := h.Query(&Filter{Op: NotEqual, Field: "color", Value: "red"}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 1) - assert.Equal(t, "orange", data[0]["name"]) - }) - }) - t.Run("By Quantity [Less/Greater]", func(t *testing.T) { - query := h.Query(&Filter{Op: LessOrEqual, Field: "qty", Value: 25}, &Filter{Op: Greater, Field: "qty", Value: 1}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "orange"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) - t.Run("Not Fruit [Equal embedded field]", func(t *testing.T) { - query := h.Query(&Filter{Op: Equal, Field: "info.is_fruit", Value: false}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 1) - assert.Equal(t, "tomato", data[0]["name"]) - }) - t.Run("By Similar [In/NotIn]", func(t *testing.T) { - t.Run("Similar to cucumber, pear", func(t *testing.T) { - query := h.Query(&Filter{Op: In, Field: "info.similar.name", Value: []string{"cucumber", "pear"}}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) - t.Run("Not Similar to cucumber, pear", func(t *testing.T) { - query := h.Query(&Filter{Op: NotIn, Field: "info.similar.name", Value: []string{"cucumber", "grapefruit"}}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 1) - assert.Equal(t, "apple", data[0]["name"]) - }) - }) - t.Run("By Description [Contains/NotContains]", func(t *testing.T) { - t.Run("Contains", func(t *testing.T) { - query := h.Query(&Filter{Op: And, Value: []*Filter{ - &Filter{Op: In, Field: "info.similar.color", Value: []string{"yellow"}}, - &Filter{Op: Contains, Field: "info.desc", Value: "edible fruit"}, - }}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "orange"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) - t.Run("Not Contains", func(t *testing.T) { - query := h.Query(&Filter{Op: NotContains, Field: "info.desc", Value: "fruit"}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - for _, d := range data { - fmt.Println(d["name"]) - } - require.Len(t, data, 1) - assert.Equal(t, "tomato", data[0]["name"]) - }) - }) - t.Run("By Shipment [Contains/NotContains]", func(t *testing.T) { - t.Run("Contains", func(t *testing.T) { - query := h.Query( - &Filter{Op: Contains, Field: "shipment", Value: "Russia"}, - ) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) - t.Run("Not Contains", func(t *testing.T) { - query := h.Query(&Filter{Op: NotContains, Field: "shipment", Value: "Iran"}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - for _, d := range data { - fmt.Println(d["name"]) - } - require.Len(t, data, 1) - assert.Equal(t, "tomato", data[0]["name"]) - }) - }) - t.Run("Compound Query", func(t *testing.T) { - query := h.Query(&Filter{Op: Or, Value: []*Filter{ - &Filter{Op: And, Value: []*Filter{ - &Filter{Op: In, Field: "color", Value: []interface{}{"red", "yellow", "green"}}, - &Filter{Op: Less, Field: "qty", Value: 10}, - }}, // 1 - tomato - &Filter{Op: Equal, Field: "name", Value: "pepper"}, // 0 - &Filter{Op: And, Value: []*Filter{ - &Filter{Op: GreaterOrEqual, Field: "produced", Value: w1}, - &Filter{Op: Less, Field: "produced", Value: w2}, // 1 - apple - }}, - }}) - res, err := coll.Find(ctx, query) - require.NoError(t, err) - - var data []map[string]interface{} - err = res.All(ctx, &data) - require.NoError(t, err) - require.Len(t, data, 2) - assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) - }) -} +//func TestFilterHandler_Integration(t *testing.T) { +// ctx := context.Background() +// +// uri := os.Getenv("MONGO_URL") +// if uri == "" { +// uri = "mongodb://localhost:27017" +// } +// opts := options.Client().SetConnectTimeout(15 * time.Second).ApplyURI(uri) +// client, err := mongo.Connect(context.Background(), opts) +// require.NoError(t, err) +// err = client.Ping(ctx, nil) +// require.NoError(t, err) +// +// sch := schema.New( +// "name", field.String(validate.Required()), +// "color", field.String(), +// "qty", field.Number(field.NumberFormatInt), +// "info", field.Object( +// "is_fruit", field.Bool(), +// "similar", field.Array( +// field.Object( +// "name", field.Number(field.NumberFormatFloat), +// "color", field.String(), +// ), +// ), +// "desc", field.String(), +// ), +// "produced", field.Time(), +// "shipment", field.Array(field.String()), +// ) +// +// w1, _ := time.Parse(time.RFC3339, "2020-01-01T10:08:41Z") +// w2, _ := time.Parse(time.RFC3339, "2020-05-01T10:08:41Z") +// w3, _ := time.Parse(time.RFC3339, "2020-10-01T10:08:41Z") +// +// items := []map[string]interface{}{ +// { +// "name": "apple", +// "color": "red", +// "qty": 25, +// "info": map[string]interface{}{ +// "is_fruit": true, +// "similar": []interface{}{ +// map[string]interface{}{"name": "pear", "color": "yellow"}, +// map[string]interface{}{"name": "lemon", "color": "yellow"}, +// }, +// "desc": "An apple is the edible fruit . Apple trees are cultivated worldwide and have religious and mythological " + +// "significance in many cultures. Apples are eaten with honey at the Jewish New Year of Rosh Hashanah to symbolize a sweet new year.", +// }, +// "produced": w1, +// "shipment": []interface{}{"Russia", "Iran"}, +// "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.751472, 37.618727}}, +// }, +// { +// "name": "orange", +// "color": "orange", +// "qty": 10, +// "info": map[string]interface{}{ +// "is_fruit": true, +// "similar": []interface{}{ +// map[string]interface{}{"name": "lemon", "color": "yellow"}, +// map[string]interface{}{"name": "grapefruit", "color": "red"}, +// }, +// "desc": "The orange is the edible fruit of various citrus species; a hybrid between pomelo and mandarin. Orange trees are widely grown" + +// " in tropical and subtropical climates for their sweet fruit. The fruit of the orange tree can be eaten fresh, or processed for its juice or fragrant peel.", +// }, +// "produced": w2, +// "shipment": []interface{}{"Egypt", "Iran"}, +// "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.716797, 37.552809}}, +// }, +// { +// "name": "tomato", +// "color": "red", +// "qty": 1, +// "info": map[string]interface{}{ +// "is_fruit": false, +// "similar": []interface{}{ +// map[string]interface{}{"name": "cucumber", "color": "green"}, +// map[string]interface{}{"name": "apple", "color": "yellow"}, +// }, +// "desc": "The tomato is the edible red berry. The tomato is consumed in diverse ways, raw or cooked, in many dishes, " + +// "sauces, salads, and drinks. Numerous varieties of the tomato plant are widely grown in temperate climates across the world.", +// }, +// "produced": w3, +// "shipment": []interface{}{"Russia", "Italy"}, +// "storepoint": map[string]interface{}{"type": "Point", "coordinates": []float64{55.760688, 37.619125}}, +// }, +// } +// +// db := client.Database("perxis_test_filter") +// coll := db.Collection("items") +// coll.Drop(ctx) +// +// for _, item := range items { +// _, err = coll.InsertOne(ctx, item) +// require.NoError(t, err) +// } +// +// h := NewFilterHandler(sch) +// h.SetQueryBuilder(NewMongoQueryBuilder()) +// +// t.Run("By Color [Equal/NotEqual]", func(t *testing.T) { +// t.Run("Red", func(t *testing.T) { +// query := h.Query(&Filter{Op: Equal, Field: "color", Value: "red"}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +// t.Run("Not Red", func(t *testing.T) { +// query := h.Query(&Filter{Op: NotEqual, Field: "color", Value: "red"}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 1) +// assert.Equal(t, "orange", data[0]["name"]) +// }) +// }) +// t.Run("By Quantity [Less/Greater]", func(t *testing.T) { +// query := h.Query(&Filter{Op: LessOrEqual, Field: "qty", Value: 25}, &Filter{Op: Greater, Field: "qty", Value: 1}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "orange"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +// t.Run("Not Fruit [Equal embedded field]", func(t *testing.T) { +// query := h.Query(&Filter{Op: Equal, Field: "info.is_fruit", Value: false}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 1) +// assert.Equal(t, "tomato", data[0]["name"]) +// }) +// t.Run("By Similar [In/NotIn]", func(t *testing.T) { +// t.Run("Similar to cucumber, pear", func(t *testing.T) { +// query := h.Query(&Filter{Op: In, Field: "info.similar.name", Value: []string{"cucumber", "pear"}}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +// t.Run("Not Similar to cucumber, pear", func(t *testing.T) { +// query := h.Query(&Filter{Op: NotIn, Field: "info.similar.name", Value: []string{"cucumber", "grapefruit"}}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 1) +// assert.Equal(t, "apple", data[0]["name"]) +// }) +// }) +// t.Run("By Description [Contains/NotContains]", func(t *testing.T) { +// t.Run("Contains", func(t *testing.T) { +// query := h.Query(&Filter{Op: And, Value: []*Filter{ +// &Filter{Op: In, Field: "info.similar.color", Value: []string{"yellow"}}, +// &Filter{Op: Contains, Field: "info.desc", Value: "edible fruit"}, +// }}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "orange"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +// t.Run("Not Contains", func(t *testing.T) { +// query := h.Query(&Filter{Op: NotContains, Field: "info.desc", Value: "fruit"}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// for _, d := range data { +// fmt.Println(d["name"]) +// } +// require.Len(t, data, 1) +// assert.Equal(t, "tomato", data[0]["name"]) +// }) +// }) +// t.Run("By Shipment [Contains/NotContains]", func(t *testing.T) { +// t.Run("Contains", func(t *testing.T) { +// query := h.Query( +// &Filter{Op: Contains, Field: "shipment", Value: "Russia"}, +// ) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +// t.Run("Not Contains", func(t *testing.T) { +// query := h.Query(&Filter{Op: NotContains, Field: "shipment", Value: "Iran"}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// for _, d := range data { +// fmt.Println(d["name"]) +// } +// require.Len(t, data, 1) +// assert.Equal(t, "tomato", data[0]["name"]) +// }) +// }) +// t.Run("Compound Query", func(t *testing.T) { +// query := h.Query(&Filter{Op: Or, Value: []*Filter{ +// &Filter{Op: And, Value: []*Filter{ +// &Filter{Op: In, Field: "color", Value: []interface{}{"red", "yellow", "green"}}, +// &Filter{Op: Less, Field: "qty", Value: 10}, +// }}, // 1 - tomato +// &Filter{Op: Equal, Field: "name", Value: "pepper"}, // 0 +// &Filter{Op: And, Value: []*Filter{ +// &Filter{Op: GreaterOrEqual, Field: "produced", Value: w1}, +// &Filter{Op: Less, Field: "produced", Value: w2}, // 1 - apple +// }}, +// }}) +// res, err := coll.Find(ctx, query) +// require.NoError(t, err) +// +// var data []map[string]interface{} +// err = res.All(ctx, &data) +// require.NoError(t, err) +// require.Len(t, data, 2) +// assert.ElementsMatch(t, []interface{}{"apple", "tomato"}, []interface{}{data[0]["name"], data[1]["name"]}) +// }) +//}