forked from TrueCloudLab/frostfs-sdk-go
[#247] object: Introduce Patch type
* Make ToV2, FromV2 converters for Patch and PayloadPatch; * Add unit-tests. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
e83d6b7c6a
commit
6dd500def9
4 changed files with 267 additions and 3 deletions
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module git.frostfs.info/TrueCloudLab/frostfs-sdk-go
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240726072425-3dfa2f4fd65e
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1
|
git.frostfs.info/TrueCloudLab/hrw v1.2.1
|
||||||
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
|
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,5 +1,5 @@
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240726072425-3dfa2f4fd65e h1:gEWT+70E/RvGkxtSv+PlyUN2vtJVymhQa1mypvrXukM=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3 h1:BbtF/98HU0nBl4szdDYAV3XadNE5sJ92uSFmNePQmfA=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240726072425-3dfa2f4fd65e/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240730145254-c27b978770a3/go.mod h1:OBDSr+DqV1z4VDouoX3YMleNc4DPBVBWTG3WDT2PK1o=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e h1:kcBqZBiFIUBATUqEuvVigtkJJWQ2Gug/eYXn967o3M4=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e h1:kcBqZBiFIUBATUqEuvVigtkJJWQ2Gug/eYXn967o3M4=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e/go.mod h1:F/fe1OoIDKr5Bz99q4sriuHDuf3aZefZy9ZsCqEtgxc=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
||||||
|
|
103
object/patch.go
Normal file
103
object/patch.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||||
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Patch is a patch that's applied for an object.
|
||||||
|
type Patch struct {
|
||||||
|
// The address of the object for which the patch is being applied.
|
||||||
|
Address oid.Address
|
||||||
|
|
||||||
|
// The list of new attributes to set in the object's header.
|
||||||
|
NewAttributes []Attribute
|
||||||
|
|
||||||
|
// If ReplaceAttributes flag is true, then the header's attributes are reset and
|
||||||
|
// filled with NewAttributes. Otherwise, the attributes are just merged.
|
||||||
|
ReplaceAttributes bool
|
||||||
|
|
||||||
|
// Payload patch. If this field is not set, then it assumed such Patch patches only
|
||||||
|
// header (see NewAttributes, ReplaceAttributes).
|
||||||
|
PayloadPatch *PayloadPatch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Patch) ToV2() *v2object.PatchRequestBody {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v2 := new(v2object.PatchRequestBody)
|
||||||
|
|
||||||
|
addrV2 := new(refs.Address)
|
||||||
|
p.Address.WriteToV2(addrV2)
|
||||||
|
v2.SetAddress(addrV2)
|
||||||
|
|
||||||
|
attrs := make([]v2object.Attribute, len(p.NewAttributes))
|
||||||
|
for i := range p.NewAttributes {
|
||||||
|
attrs[i] = *p.NewAttributes[i].ToV2()
|
||||||
|
}
|
||||||
|
v2.SetNewAttributes(attrs)
|
||||||
|
v2.SetReplaceAttributes(p.ReplaceAttributes)
|
||||||
|
|
||||||
|
v2.SetPatch(p.PayloadPatch.ToV2())
|
||||||
|
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Patch) FromV2(patch *v2object.PatchRequestBody) {
|
||||||
|
if patch == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr := patch.GetAddress(); addr != nil {
|
||||||
|
_ = p.Address.ReadFromV2(*addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
newAttrs := patch.GetNewAttributes()
|
||||||
|
p.NewAttributes = make([]Attribute, len(newAttrs))
|
||||||
|
for i := range newAttrs {
|
||||||
|
p.NewAttributes[i] = *NewAttributeFromV2(&newAttrs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.ReplaceAttributes = patch.GetReplaceAttributes()
|
||||||
|
|
||||||
|
if v2patch := patch.GetPatch(); v2patch != nil {
|
||||||
|
p.PayloadPatch = new(PayloadPatch)
|
||||||
|
p.PayloadPatch.FromV2(v2patch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch is a patch that's applied for an object's payload.
|
||||||
|
type PayloadPatch struct {
|
||||||
|
// Range of the patch application.
|
||||||
|
Range *Range
|
||||||
|
|
||||||
|
// Chunk is the payload that replaces (or is appended to) the original object payload.
|
||||||
|
Chunk []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PayloadPatch) ToV2() *v2object.PatchRequestBodyPatch {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v2 := new(v2object.PatchRequestBodyPatch)
|
||||||
|
|
||||||
|
v2.Chunk = p.Chunk
|
||||||
|
v2.Range = p.Range.ToV2()
|
||||||
|
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PayloadPatch) FromV2(patch *v2object.PatchRequestBodyPatch) {
|
||||||
|
if patch == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Chunk = patch.Chunk
|
||||||
|
if patch.Range != nil {
|
||||||
|
p.Range = NewRangeFromV2(patch.Range)
|
||||||
|
}
|
||||||
|
}
|
161
object/patch_test.go
Normal file
161
object/patch_test.go
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||||
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPatch(t *testing.T) {
|
||||||
|
t.Run("to v2", func(t *testing.T) {
|
||||||
|
t.Run("only attributes", func(t *testing.T) {
|
||||||
|
var p Patch
|
||||||
|
|
||||||
|
var attr1, attr2 Attribute
|
||||||
|
attr1.SetKey("key1")
|
||||||
|
attr1.SetValue("val1")
|
||||||
|
attr2.SetKey("key2")
|
||||||
|
attr2.SetValue("val2")
|
||||||
|
|
||||||
|
p.Address = oidtest.Address()
|
||||||
|
p.NewAttributes = []Attribute{attr1, attr2}
|
||||||
|
p.ReplaceAttributes = true
|
||||||
|
|
||||||
|
v2patch := p.ToV2()
|
||||||
|
|
||||||
|
addr := new(oid.Address)
|
||||||
|
require.NotNil(t, v2patch.GetAddress())
|
||||||
|
addr.ReadFromV2(*v2patch.GetAddress())
|
||||||
|
require.True(t, p.Address.Equals(*addr))
|
||||||
|
|
||||||
|
require.Equal(t, p.ReplaceAttributes, v2patch.GetReplaceAttributes())
|
||||||
|
|
||||||
|
require.Nil(t, v2patch.GetPatch())
|
||||||
|
|
||||||
|
require.Len(t, v2patch.GetNewAttributes(), 2)
|
||||||
|
require.Equal(t, attr1.Key(), v2patch.GetNewAttributes()[0].GetKey())
|
||||||
|
require.Equal(t, attr2.Key(), v2patch.GetNewAttributes()[1].GetKey())
|
||||||
|
require.Equal(t, attr1.Value(), v2patch.GetNewAttributes()[0].GetValue())
|
||||||
|
require.Equal(t, attr2.Value(), v2patch.GetNewAttributes()[1].GetValue())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with payload patch", func(t *testing.T) {
|
||||||
|
var p Patch
|
||||||
|
|
||||||
|
var attr1, attr2 Attribute
|
||||||
|
attr1.SetKey("key1")
|
||||||
|
attr1.SetValue("val1")
|
||||||
|
attr2.SetKey("key2")
|
||||||
|
attr2.SetValue("val2")
|
||||||
|
|
||||||
|
p.Address = oidtest.Address()
|
||||||
|
p.NewAttributes = []Attribute{attr1, attr2}
|
||||||
|
p.ReplaceAttributes = true
|
||||||
|
|
||||||
|
rng := &Range{}
|
||||||
|
rng.SetOffset(100)
|
||||||
|
rng.SetLength(10)
|
||||||
|
p.PayloadPatch = &PayloadPatch{
|
||||||
|
Range: rng,
|
||||||
|
Chunk: []byte("payload_patch_chunk"),
|
||||||
|
}
|
||||||
|
|
||||||
|
v2patch := p.ToV2()
|
||||||
|
|
||||||
|
addr := new(oid.Address)
|
||||||
|
require.NotNil(t, v2patch.GetAddress())
|
||||||
|
addr.ReadFromV2(*v2patch.GetAddress())
|
||||||
|
require.True(t, p.Address.Equals(*addr))
|
||||||
|
|
||||||
|
require.Equal(t, p.ReplaceAttributes, v2patch.GetReplaceAttributes())
|
||||||
|
|
||||||
|
require.Len(t, v2patch.GetNewAttributes(), 2)
|
||||||
|
require.Equal(t, attr1.Key(), v2patch.GetNewAttributes()[0].GetKey())
|
||||||
|
require.Equal(t, attr2.Key(), v2patch.GetNewAttributes()[1].GetKey())
|
||||||
|
require.Equal(t, attr1.Value(), v2patch.GetNewAttributes()[0].GetValue())
|
||||||
|
require.Equal(t, attr2.Value(), v2patch.GetNewAttributes()[1].GetValue())
|
||||||
|
|
||||||
|
require.NotNil(t, v2patch.GetPatch())
|
||||||
|
require.NotNil(t, v2patch.GetPatch().Range)
|
||||||
|
require.Equal(t, uint64(100), v2patch.GetPatch().Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(10), v2patch.GetPatch().Range.GetLength())
|
||||||
|
require.Equal(t, []byte("payload_patch_chunk"), v2patch.GetPatch().Chunk)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("from v2", func(t *testing.T) {
|
||||||
|
t.Run("only attributes", func(t *testing.T) {
|
||||||
|
v2patch := new(v2object.PatchRequestBody)
|
||||||
|
|
||||||
|
address := oidtest.Address()
|
||||||
|
v2addr := new(refs.Address)
|
||||||
|
address.WriteToV2(v2addr)
|
||||||
|
v2patch.SetAddress(v2addr)
|
||||||
|
|
||||||
|
var attr1, attr2 Attribute
|
||||||
|
attr1.SetKey("key1")
|
||||||
|
attr1.SetValue("val1")
|
||||||
|
attr2.SetKey("key2")
|
||||||
|
attr2.SetValue("val2")
|
||||||
|
|
||||||
|
v2patch.SetNewAttributes([]v2object.Attribute{
|
||||||
|
*attr1.ToV2(), *attr2.ToV2(),
|
||||||
|
})
|
||||||
|
v2patch.SetReplaceAttributes(true)
|
||||||
|
|
||||||
|
var p Patch
|
||||||
|
p.FromV2(v2patch)
|
||||||
|
|
||||||
|
require.Equal(t, address, p.Address)
|
||||||
|
require.Equal(t, []Attribute{attr1, attr2}, p.NewAttributes)
|
||||||
|
require.Equal(t, true, p.ReplaceAttributes)
|
||||||
|
require.Nil(t, p.PayloadPatch)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with payload patch", func(t *testing.T) {
|
||||||
|
v2patchReqBody := new(v2object.PatchRequestBody)
|
||||||
|
|
||||||
|
address := oidtest.Address()
|
||||||
|
v2addr := new(refs.Address)
|
||||||
|
address.WriteToV2(v2addr)
|
||||||
|
v2patchReqBody.SetAddress(v2addr)
|
||||||
|
|
||||||
|
var attr1, attr2 Attribute
|
||||||
|
attr1.SetKey("key1")
|
||||||
|
attr1.SetValue("val1")
|
||||||
|
attr2.SetKey("key2")
|
||||||
|
attr2.SetValue("val2")
|
||||||
|
|
||||||
|
v2patchReqBody.SetNewAttributes([]v2object.Attribute{
|
||||||
|
*attr1.ToV2(), *attr2.ToV2(),
|
||||||
|
})
|
||||||
|
v2patchReqBody.SetReplaceAttributes(true)
|
||||||
|
|
||||||
|
v2Rng := &v2object.Range{}
|
||||||
|
v2Rng.SetOffset(13)
|
||||||
|
v2Rng.SetLength(10)
|
||||||
|
v2Patch := &v2object.PatchRequestBodyPatch{
|
||||||
|
Range: v2Rng,
|
||||||
|
Chunk: []byte("payload_patch_chunk"),
|
||||||
|
}
|
||||||
|
v2patchReqBody.SetPatch(v2Patch)
|
||||||
|
|
||||||
|
var p Patch
|
||||||
|
p.FromV2(v2patchReqBody)
|
||||||
|
|
||||||
|
require.Equal(t, address, p.Address)
|
||||||
|
require.Equal(t, []Attribute{attr1, attr2}, p.NewAttributes)
|
||||||
|
require.Equal(t, true, p.ReplaceAttributes)
|
||||||
|
require.NotNil(t, p.PayloadPatch)
|
||||||
|
require.NotNil(t, p.PayloadPatch.Range)
|
||||||
|
require.Equal(t, uint64(13), p.PayloadPatch.Range.GetOffset())
|
||||||
|
require.Equal(t, uint64(10), p.PayloadPatch.Range.GetLength())
|
||||||
|
require.Equal(t, []byte("payload_patch_chunk"), p.PayloadPatch.Chunk)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue