From dbaf3e2b3c3a5bccadc290dab3358ab676d38761 Mon Sep 17 00:00:00 2001 From: Roman Khafizianov Date: Tue, 17 Jan 2023 14:04:55 +0100 Subject: [PATCH] database in/has filters: automatically wraps the non-list values --- pkg/lib/database/filter/filter.go | 49 ++++++++++++++------------ pkg/lib/database/filter/filter_test.go | 25 ++++++++++--- util/pbtypes/pbtypes.go | 12 +++++++ 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/pkg/lib/database/filter/filter.go b/pkg/lib/database/filter/filter.go index 155412138..27514a8ac 100644 --- a/pkg/lib/database/filter/filter.go +++ b/pkg/lib/database/filter/filter.go @@ -5,13 +5,14 @@ import ( "fmt" "strings" + "github.com/gogo/protobuf/types" + "github.com/anytypeio/go-anytype-middleware/pkg/lib/pb/model" "github.com/anytypeio/go-anytype-middleware/util/pbtypes" - "github.com/gogo/protobuf/types" ) var ( - ErrValueMustBeList = errors.New("value must be list") + ErrValueMustBeListSupporting = errors.New("value must be list supporting") ) func MakeAndFilter(protoFilters []*model.BlockContentDataviewFilter) (Filter, error) { @@ -78,18 +79,18 @@ func MakeFilter(proto *model.BlockContentDataviewFilter) (Filter, error) { Value: proto.Value, }}, nil case model.BlockContentDataviewFilter_In: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return In{ Key: proto.RelationKey, Value: list, }, nil case model.BlockContentDataviewFilter_NotIn: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return Not{In{ Key: proto.RelationKey, @@ -104,36 +105,36 @@ func MakeFilter(proto *model.BlockContentDataviewFilter) (Filter, error) { Key: proto.RelationKey, }}, nil case model.BlockContentDataviewFilter_AllIn: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return AllIn{ Key: proto.RelationKey, Value: list, }, nil case model.BlockContentDataviewFilter_NotAllIn: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return Not{AllIn{ Key: proto.RelationKey, Value: list, }}, nil case model.BlockContentDataviewFilter_ExactIn: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return ExactIn{ Key: proto.RelationKey, Value: list, }, nil case model.BlockContentDataviewFilter_NotExactIn: - list := proto.Value.GetListValue() - if list == nil { - return nil, ErrValueMustBeList + list, err := pbtypes.ValueListWrapper(proto.Value) + if err != nil { + return nil, ErrValueMustBeListSupporting } return Not{ExactIn{ Key: proto.RelationKey, @@ -362,12 +363,16 @@ func (l AllIn) FilterObject(g Getter) bool { if val == nil { return false } - list := val.GetListValue() + + list, err := pbtypes.ValueListWrapper(val) + if err != nil { + return false + } if list == nil { return false } exist := func(v *types.Value) bool { - for _, lv := range list.Values { + for _, lv := range list.GetValues() { if v.Equal(lv) { return true } diff --git a/pkg/lib/database/filter/filter_test.go b/pkg/lib/database/filter/filter_test.go index 59ace5d8f..9f2b51497 100644 --- a/pkg/lib/database/filter/filter_test.go +++ b/pkg/lib/database/filter/filter_test.go @@ -3,11 +3,12 @@ package filter import ( "testing" - "github.com/anytypeio/go-anytype-middleware/pkg/lib/pb/model" - "github.com/anytypeio/go-anytype-middleware/util/pbtypes" "github.com/gogo/protobuf/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/anytypeio/go-anytype-middleware/pkg/lib/pb/model" + "github.com/anytypeio/go-anytype-middleware/util/pbtypes" ) type testGetter map[string]*types.Value @@ -227,6 +228,22 @@ func TestAllIn_FilterObject(t *testing.T) { g := testGetter{"k": pbtypes.StringList([]string{"2", "3", "4"})} assert.False(t, allIn.FilterObject(g)) }) + + t.Run("ok string in Object", func(t *testing.T) { + allIn := AllIn{Key: "k", Value: pbtypes.StringList([]string{"1"}).GetListValue()} + g := testGetter{"k": pbtypes.String("1")} + assert.True(t, allIn.FilterObject(g)) + }) + + t.Run("ok string in Filter", func(t *testing.T) { + v, err := pbtypes.ValueListWrapper(pbtypes.String("1")) + assert.NoError(t, err) + + allIn := AllIn{Key: "k", Value: v} + + g := testGetter{"k": pbtypes.StringList([]string{"1", "2", "3"})} + assert.True(t, allIn.FilterObject(g)) + }) } func TestMakeAndFilter(t *testing.T) { @@ -313,9 +330,9 @@ func TestMakeAndFilter(t *testing.T) { model.BlockContentDataviewFilter_NotAllIn, } { _, err := MakeAndFilter([]*model.BlockContentDataviewFilter{ - {Condition: cond, Value: pbtypes.String("not list")}, + {Condition: cond, Value: pbtypes.Null()}, }) - assert.Equal(t, ErrValueMustBeList, err) + assert.Equal(t, ErrValueMustBeListSupporting, err) } }) diff --git a/util/pbtypes/pbtypes.go b/util/pbtypes/pbtypes.go index 4d343ef5d..32c09d7b3 100644 --- a/util/pbtypes/pbtypes.go +++ b/util/pbtypes/pbtypes.go @@ -428,3 +428,15 @@ func StructCompareIgnoreKeys(st1 *types.Struct, st2 *types.Struct, ignoreKeys [] } return true } + +// ValueListWrapper wraps single value into the list. If value is already a list, it is returned as is. +// Null and struct values are not supported +func ValueListWrapper(value *types.Value) (*types.ListValue, error) { + switch v := value.Kind.(type) { + case *types.Value_ListValue: + return v.ListValue, nil + case *types.Value_StringValue, *types.Value_NumberValue, *types.Value_BoolValue: + return &types.ListValue{Values: []*types.Value{value}}, nil + } + return nil, fmt.Errorf("not supported type") +}