From 3d08d8140fa0c7be722c7bbbdcf0c1db539476a2 Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Wed, 25 Nov 2020 19:32:52 +0300 Subject: [PATCH] [#209] object: Support `splitID` search attribute Signed-off-by: Alex Vanin --- pkg/object/raw.go | 4 +-- pkg/object/raw_test.go | 5 +--- pkg/object/rw.go | 16 ++++++----- pkg/object/search.go | 8 ++++++ pkg/object/search_test.go | 17 +++++++++++ pkg/object/splitid.go | 59 ++++++++++++++++++++++++++++++++++++++ pkg/object/splitid_test.go | 38 ++++++++++++++++++++++++ v2/object/filters.go | 3 ++ 8 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 pkg/object/splitid.go create mode 100644 pkg/object/splitid_test.go diff --git a/pkg/object/raw.go b/pkg/object/raw.go index 5ae3108f..b7b3b177 100644 --- a/pkg/object/raw.go +++ b/pkg/object/raw.go @@ -111,8 +111,8 @@ func (o *RawObject) SetChildren(v ...*ID) { } // SetSplitID sets split identifier for the split object. -func (o *RawObject) SetSplitID(v []byte) { - o.setSplitID(v) +func (o *RawObject) SetSplitID(id *SplitID) { + o.setSplitID(id) } // SetParentID sets identifier of the parent object. diff --git a/pkg/object/raw_test.go b/pkg/object/raw_test.go index f6e85a87..902e3fa9 100644 --- a/pkg/object/raw_test.go +++ b/pkg/object/raw_test.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "testing" - "github.com/google/uuid" "github.com/nspcc-dev/neofs-api-go/pkg" "github.com/nspcc-dev/neofs-api-go/pkg/container" "github.com/nspcc-dev/neofs-api-go/pkg/owner" @@ -196,9 +195,7 @@ func TestRawObject_SetSplitID(t *testing.T) { require.Nil(t, obj.SplitID()) - splitID, err := uuid.New().MarshalBinary() - require.NoError(t, err) - + splitID := NewSplitID() obj.SetSplitID(splitID) require.Equal(t, obj.SplitID(), splitID) diff --git a/pkg/object/rw.go b/pkg/object/rw.go index 0412f913..35e56f19 100644 --- a/pkg/object/rw.go +++ b/pkg/object/rw.go @@ -253,16 +253,18 @@ func (o *rwObject) setChildren(v ...*ID) { // SplitID return split identity of split object. If object is not split // returns nil. -func (o *rwObject) SplitID() []byte { - return (*object.Object)(o). - GetHeader(). - GetSplit(). - GetSplitID() +func (o *rwObject) SplitID() *SplitID { + return NewSplitIDFromV2( + (*object.Object)(o). + GetHeader(). + GetSplit(). + GetSplitID(), + ) } -func (o *rwObject) setSplitID(id []byte) { +func (o *rwObject) setSplitID(id *SplitID) { o.setSplitFields(func(split *object.SplitHeader) { - split.SetSplitID(id) + split.SetSplitID(id.ToV2()) }) } diff --git a/pkg/object/search.go b/pkg/object/search.go index 2a835baa..d23b3df3 100644 --- a/pkg/object/search.go +++ b/pkg/object/search.go @@ -70,6 +70,7 @@ const ( fKeyType fKeyHomomorphicHash fKeyParent + fKeySplitID fKeyPropRoot fKeyPropPhy ) @@ -98,6 +99,8 @@ func (k filterKey) String() string { return v2object.FilterHeaderHomomorphicHash case fKeyParent: return v2object.FilterHeaderParent + case fKeySplitID: + return v2object.FilterHeaderSplitID case fKeyPropRoot: return v2object.FilterPropertyRoot case fKeyPropPhy: @@ -224,6 +227,7 @@ func (f *SearchFilters) AddPhyFilter() { f.addPhyFilter() } +// AddParentIDFilter adds filter by parent identifier. func (f *SearchFilters) AddParentIDFilter(m SearchMatchType, id *ID) { f.addReservedFilter(m, fKeyParent, id) } @@ -232,3 +236,7 @@ func (f *SearchFilters) AddParentIDFilter(m SearchMatchType, id *ID) { func (f *SearchFilters) AddObjectIDFilter(m SearchMatchType, id *ID) { f.addReservedFilter(m, fKeyObjectID, id) } + +func (f *SearchFilters) AddSplitIDFilter(m SearchMatchType, id *SplitID) { + f.addReservedFilter(m, fKeySplitID, id) +} diff --git a/pkg/object/search_test.go b/pkg/object/search_test.go index b3407cc8..f477f4f2 100644 --- a/pkg/object/search_test.go +++ b/pkg/object/search_test.go @@ -123,3 +123,20 @@ func TestSearchFilters_AddObjectIDFilter(t *testing.T) { require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) }) } + +func TestSearchFilters_AddSplitIDFilter(t *testing.T) { + id := object.NewSplitID() + + fs := new(object.SearchFilters) + fs.AddSplitIDFilter(object.MatchStringEqual, id) + + t.Run("v2", func(t *testing.T) { + fsV2 := fs.ToV2() + + require.Len(t, fsV2, 1) + + require.Equal(t, v2object.FilterHeaderSplitID, fsV2[0].GetKey()) + require.Equal(t, id.String(), fsV2[0].GetValue()) + require.Equal(t, v2object.MatchStringEqual, fsV2[0].GetMatchType()) + }) +} diff --git a/pkg/object/splitid.go b/pkg/object/splitid.go new file mode 100644 index 00000000..7f395671 --- /dev/null +++ b/pkg/object/splitid.go @@ -0,0 +1,59 @@ +package object + +import ( + "github.com/google/uuid" +) + +// SplitID is a UUIDv4 used as attribute in split objects. +type SplitID struct { + uuid uuid.UUID +} + +// NewSplitID returns UUID representation of splitID attribute. +func NewSplitID() *SplitID { + return &SplitID{ + uuid: uuid.New(), + } +} + +// NewSplitIDFromV2 returns parsed UUID from bytes. +// If v is invalid UUIDv4 byte sequence, then function returns nil. +func NewSplitIDFromV2(v []byte) *SplitID { + id := uuid.New() + + err := id.UnmarshalBinary(v) + if err != nil { + return nil + } + + return &SplitID{ + uuid: id, + } +} + +// Parse converts UUIDv4 string representation into SplitID. +func (id *SplitID) Parse(s string) (err error) { + id.uuid, err = uuid.Parse(s) + if err != nil { + return err + } + + return nil +} + +// String returns UUIDv4 string representation of SplitID. +func (id SplitID) String() string { + return id.uuid.String() +} + +// SetUUID sets pre created UUID structure as SplitID. +func (id *SplitID) SetUUID(v uuid.UUID) { + id.uuid = v +} + +// ToV2 converts SplitID to a representation of SplitID in neofs-api v2. +func (id SplitID) ToV2() []byte { + data, _ := id.uuid.MarshalBinary() // err is always nil + + return data +} diff --git a/pkg/object/splitid_test.go b/pkg/object/splitid_test.go new file mode 100644 index 00000000..3e144eb8 --- /dev/null +++ b/pkg/object/splitid_test.go @@ -0,0 +1,38 @@ +package object_test + +import ( + "testing" + + "github.com/google/uuid" + "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/stretchr/testify/require" +) + +func TestSplitID(t *testing.T) { + id := object.NewSplitID() + + t.Run("toV2/fromV2", func(t *testing.T) { + data := id.ToV2() + + newID := object.NewSplitIDFromV2(data) + require.NotNil(t, newID) + + require.Equal(t, id, newID) + }) + + t.Run("string/parse", func(t *testing.T) { + idStr := id.String() + + newID := object.NewSplitID() + require.NoError(t, newID.Parse(idStr)) + + require.Equal(t, id, newID) + }) + + t.Run("set UUID", func(t *testing.T) { + newUUID := uuid.New() + id.SetUUID(newUUID) + + require.Equal(t, newUUID.String(), id.String()) + }) +} diff --git a/v2/object/filters.go b/v2/object/filters.go index 0777e968..8340cea8 100644 --- a/v2/object/filters.go +++ b/v2/object/filters.go @@ -33,6 +33,9 @@ const ( // FilterHeaderParent is a filter key to "split.parent" field of the object header. FilterHeaderParent = ReservedFilterPrefix + "split.parent" + + // FilterHeaderParent is a filter key to "split.splitID" field of the object header. + FilterHeaderSplitID = ReservedFilterPrefix + "split.splitID" ) const (