From f8b4ed4c18df766809c0b3c56afd03a26337ade5 Mon Sep 17 00:00:00 2001 From: Victor Nosov Date: Tue, 20 Jul 2021 09:40:27 +0300 Subject: [PATCH] using []string part in complex id (#65) * using []string part in complex id --- state/mapping/mapping_test.go | 16 +++++++-- state/mapping/state_mapping.go | 2 ++ state/mapping/state_mapping_opt.go | 17 +++++---- .../testdata/schema/with_complex_id.pb.go | 36 ++++++++++++------- .../testdata/schema/with_complex_id.proto | 3 +- 5 files changed, 52 insertions(+), 22 deletions(-) diff --git a/state/mapping/mapping_test.go b/state/mapping/mapping_test.go index 2a6eaaf8..f3419f7e 100644 --- a/state/mapping/mapping_test.go +++ b/state/mapping/mapping_test.go @@ -3,6 +3,7 @@ package mapping_test import ( "strings" "testing" + "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -10,6 +11,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric-protos-go/peer" + identitytestdata "github.com/s7techlab/cckit/identity/testdata" "github.com/s7techlab/cckit/state" "github.com/s7techlab/cckit/state/mapping" @@ -168,7 +170,11 @@ var _ = Describe(`Mapping`, func() { Describe(`Entity with complex id`, func() { - ent1 := &schema.EntityWithComplexId{Id: &schema.EntityComplexId{IdPart1: `aaa`, IdPart2: `bbb`}} + ent1 := &schema.EntityWithComplexId{Id: &schema.EntityComplexId{ + IdPart1: []string{`aaa`, `bb`}, + IdPart2: `ccc`, + IdPart3: testcc.MustTime(`2020-01-28T17:00:00Z`), + }} It("Allow to add data to chaincode state", func() { expectcc.ResponseOk(complexIDCC.Invoke(`entityInsert`, ent1)) @@ -176,9 +182,15 @@ var _ = Describe(`Mapping`, func() { `debugStateKeys`, `EntityWithComplexId`), &[]string{}).([]string) Expect(len(keys)).To(Equal(1)) + timeStr := time.Unix(ent1.Id.IdPart3.GetSeconds(), int64(ent1.Id.IdPart3.GetNanos())).Format(`2006-01-02`) // from hyperledger/fabric/core/chaincode/shim/chaincode.go Expect(keys[0]).To(Equal( - "\x00" + `EntityWithComplexId` + string(rune(0)) + ent1.Id.IdPart1 + string(rune(0)) + ent1.Id.IdPart2 + string(rune(0)))) + string(rune(0)) + + `EntityWithComplexId` + string(rune(0)) + + ent1.Id.IdPart1[0] + string(rune(0)) + + ent1.Id.IdPart1[1] + string(rune(0)) + + ent1.Id.IdPart2 + string(rune(0)) + + timeStr + string(rune(0)))) }) It("Allow to get entity", func() { diff --git a/state/mapping/state_mapping.go b/state/mapping/state_mapping.go index aad00946..56942068 100644 --- a/state/mapping/state_mapping.go +++ b/state/mapping/state_mapping.go @@ -7,6 +7,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/pkg/errors" + "github.com/s7techlab/cckit/state" ) @@ -60,6 +61,7 @@ type ( Keyer InstanceMultiKeyer // index can have multiple keys } + // StateIndexDef additional index definition StateIndexDef struct { Name string Fields []string diff --git a/state/mapping/state_mapping_opt.go b/state/mapping/state_mapping_opt.go index f0b98c24..c2b3bccd 100644 --- a/state/mapping/state_mapping_opt.go +++ b/state/mapping/state_mapping_opt.go @@ -65,6 +65,7 @@ func WithIndex(idx *StateIndexDef) StateMappingOpt { aa = idx.Fields } + // multiple external ids refers to one entry if idx.Multi { keyer = attrMultiKeyer(aa[0]) } else { @@ -222,8 +223,6 @@ func keysFromValue(v reflect.Value) ([]state.Key, error) { // keyFromValue creates string representation of value for state key func keyFromValue(v reflect.Value) (state.Key, error) { - var key state.Key - switch v.Kind() { // enum in protobuf @@ -244,7 +243,7 @@ func keyFromValue(v reflect.Value) (state.Key, error) { return state.Key{t.Format(TimestampKeyLayout)}, nil default: - + key := state.Key{} s := reflect.ValueOf(v.Interface()).Elem() fs := s.Type() // get all field values from struct @@ -253,7 +252,11 @@ func keyFromValue(v reflect.Value) (state.Key, error) { if skipField(fs.Field(i).Name, field) { continue } else { - key = append(key, reflect.Indirect(v).Field(i).String()) + subKey, err := keyFromValue(reflect.Indirect(v).Field(i)) + if err != nil { + return nil, fmt.Errorf(`sub key=%s: %w`, fs.Field(i).Name, err) + } + key = key.Append(subKey) } } @@ -265,17 +268,17 @@ func keyFromValue(v reflect.Value) (state.Key, error) { case `string`, `int32`, `bool`: // multi key possible - key = state.Key{v.String()} + return state.Key{v.String()}, nil case `[]string`: + key := state.Key{} // every slice element is a part of one key for i := 0; i < v.Len(); i++ { key = append(key, v.Index(i).String()) } + return key, nil default: return nil, ErrFieldTypeNotSupportedForKeyExtraction } - - return key, nil } diff --git a/state/mapping/testdata/schema/with_complex_id.pb.go b/state/mapping/testdata/schema/with_complex_id.pb.go index 8a9471cd..3820e848 100644 --- a/state/mapping/testdata/schema/with_complex_id.pb.go +++ b/state/mapping/testdata/schema/with_complex_id.pb.go @@ -87,8 +87,9 @@ type EntityComplexId struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdPart1 string `protobuf:"bytes,1,opt,name=idPart1,proto3" json:"idPart1,omitempty"` - IdPart2 string `protobuf:"bytes,2,opt,name=idPart2,proto3" json:"idPart2,omitempty"` + IdPart1 []string `protobuf:"bytes,1,rep,name=idPart1,proto3" json:"idPart1,omitempty"` + IdPart2 string `protobuf:"bytes,2,opt,name=idPart2,proto3" json:"idPart2,omitempty"` + IdPart3 *timestamp.Timestamp `protobuf:"bytes,3,opt,name=idPart3,proto3" json:"idPart3,omitempty"` } func (x *EntityComplexId) Reset() { @@ -123,11 +124,11 @@ func (*EntityComplexId) Descriptor() ([]byte, []int) { return file_with_complex_id_proto_rawDescGZIP(), []int{1} } -func (x *EntityComplexId) GetIdPart1() string { +func (x *EntityComplexId) GetIdPart1() []string { if x != nil { return x.IdPart1 } - return "" + return nil } func (x *EntityComplexId) GetIdPart2() string { @@ -137,6 +138,13 @@ func (x *EntityComplexId) GetIdPart2() string { return "" } +func (x *EntityComplexId) GetIdPart3() *timestamp.Timestamp { + if x != nil { + return x.IdPart3 + } + return nil +} + var File_with_complex_id_proto protoreflect.FileDescriptor var file_with_complex_id_proto_rawDesc = []byte{ @@ -151,12 +159,15 @@ var file_with_complex_id_proto_rawDesc = []byte{ 0x12, 0x37, 0x0a, 0x09, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x08, 0x73, 0x6f, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x45, 0x0a, 0x0f, 0x45, 0x6e, 0x74, + 0x08, 0x73, 0x6f, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x7b, 0x0a, 0x0f, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, + 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x31, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x31, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x32, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x34, 0x0a, 0x07, 0x69, 0x64, 0x50, 0x61, 0x72, 0x74, 0x33, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x69, + 0x64, 0x50, 0x61, 0x72, 0x74, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -180,11 +191,12 @@ var file_with_complex_id_proto_goTypes = []interface{}{ var file_with_complex_id_proto_depIdxs = []int32{ 1, // 0: schema.EntityWithComplexId.Id:type_name -> schema.EntityComplexId 2, // 1: schema.EntityWithComplexId.some_date:type_name -> google.protobuf.Timestamp - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 2, // 2: schema.EntityComplexId.idPart3:type_name -> google.protobuf.Timestamp + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_with_complex_id_proto_init() } diff --git a/state/mapping/testdata/schema/with_complex_id.proto b/state/mapping/testdata/schema/with_complex_id.proto index a7a6f53d..d7241d76 100644 --- a/state/mapping/testdata/schema/with_complex_id.proto +++ b/state/mapping/testdata/schema/with_complex_id.proto @@ -10,6 +10,7 @@ message EntityWithComplexId { // EntityComplexId message EntityComplexId { - string idPart1 = 1; + repeated string idPart1 = 1; string idPart2 = 2; + google.protobuf.Timestamp idPart3 = 3; }