feat: Add Table-Store (aka ORM) package - `AutoUInt64Table` and `PrimaryKeyTable` (#10415)
<!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description ref: #9237, #9156 This PR is a follow-up of #9751. It introduces 2 new public table types: `AutoUInt64Table` and `PrimaryKeyTable` based on the parent `table` struct introduced by #9751. Upcoming work will include: - multi-key secondary indexes - iterator and pagination - import/export genesis --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [x] included comments for [documenting Go code](https://blog.golang.org/godoc) - [x] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
33737f4d8a
commit
d8196920aa
2
go.sum
2
go.sum
|
@ -163,8 +163,6 @@ github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coinbase/rosetta-sdk-go v0.6.10 h1:rgHD/nHjxLh0lMEdfGDqpTtlvtSBwULqrrZ2qPdNaCM=
|
||||
github.com/coinbase/rosetta-sdk-go v0.6.10/go.mod h1:J/JFMsfcePrjJZkwQFLh+hJErkAmdm9Iyy3D5Y0LfXo=
|
||||
github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg=
|
||||
github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE=
|
||||
github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
||||
|
|
|
@ -6,6 +6,10 @@ var (
|
|||
ErrTest = errors.Register("table_testdata", 2, "test")
|
||||
)
|
||||
|
||||
func (g TableModel) PrimaryKeyFields() []interface{} {
|
||||
return []interface{}{g.Id}
|
||||
}
|
||||
|
||||
func (g TableModel) ValidateBasic() error {
|
||||
if g.Name == "" {
|
||||
return errors.Wrap(ErrTest, "name")
|
||||
|
|
|
@ -323,8 +323,10 @@ func (m *BadMultiSignature) GetMaliciousField() []byte {
|
|||
}
|
||||
|
||||
type TableModel struct {
|
||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Number uint64 `protobuf:"varint,3,opt,name=number,proto3" json:"number,omitempty"`
|
||||
Metadata []byte `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TableModel) Reset() { *m = TableModel{} }
|
||||
|
@ -374,6 +376,20 @@ func (m *TableModel) GetName() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *TableModel) GetNumber() uint64 {
|
||||
if m != nil {
|
||||
return m.Number
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *TableModel) GetMetadata() []byte {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Dog)(nil), "testdata.Dog")
|
||||
proto.RegisterType((*Cat)(nil), "testdata.Cat")
|
||||
|
@ -387,32 +403,34 @@ func init() {
|
|||
func init() { proto.RegisterFile("testdata.proto", fileDescriptor_40c4782d007dfce9) }
|
||||
|
||||
var fileDescriptor_40c4782d007dfce9 = []byte{
|
||||
// 393 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xb1, 0x8e, 0xda, 0x40,
|
||||
0x14, 0x45, 0x19, 0x0c, 0x24, 0xbc, 0x58, 0x46, 0x19, 0x51, 0x38, 0x14, 0x0e, 0x72, 0x13, 0x8a,
|
||||
0x60, 0x47, 0x41, 0x69, 0xe8, 0x80, 0x28, 0xa1, 0xa1, 0x71, 0x52, 0xa5, 0x41, 0x63, 0x3c, 0xd8,
|
||||
0x23, 0xc6, 0x9e, 0x88, 0x19, 0x47, 0x90, 0xaf, 0xd8, 0x5f, 0xd8, 0xbf, 0xd9, 0x92, 0x72, 0xcb,
|
||||
0x15, 0xfc, 0xc8, 0xca, 0x63, 0xbc, 0x50, 0x6c, 0x41, 0xe5, 0x7b, 0xef, 0xf3, 0x3d, 0x7a, 0x96,
|
||||
0x1f, 0x58, 0x8a, 0x4a, 0x15, 0x11, 0x45, 0xbc, 0xbf, 0x5b, 0xa1, 0x04, 0x7e, 0x5b, 0xf9, 0x5e,
|
||||
0x37, 0x16, 0xb1, 0xd0, 0xa1, 0x5f, 0xa8, 0x72, 0xde, 0xfb, 0x10, 0x0b, 0x11, 0x73, 0xea, 0x6b,
|
||||
0x17, 0xe6, 0x6b, 0x9f, 0x64, 0xfb, 0x72, 0xe4, 0x0e, 0xc1, 0xf8, 0x2e, 0x62, 0x8c, 0xa1, 0x21,
|
||||
0xd9, 0x7f, 0x6a, 0xa3, 0x3e, 0x1a, 0xb4, 0x03, 0xad, 0x8b, 0x2c, 0x23, 0x29, 0xb5, 0xeb, 0x65,
|
||||
0x56, 0x68, 0xf7, 0x1b, 0x18, 0x33, 0xa2, 0xb0, 0x0d, 0x6f, 0x52, 0x91, 0xb1, 0x0d, 0xdd, 0x9e,
|
||||
0x1b, 0x95, 0xc5, 0x5d, 0x68, 0x72, 0xf6, 0x8f, 0x4a, 0xdd, 0x6a, 0x06, 0xa5, 0x71, 0x7f, 0x42,
|
||||
0x7b, 0x4e, 0xe4, 0x24, 0x63, 0x29, 0xe1, 0xf8, 0x33, 0xb4, 0x88, 0x56, 0xba, 0xfb, 0xee, 0x6b,
|
||||
0xd7, 0x2b, 0xd7, 0xf3, 0xaa, 0xf5, 0xbc, 0x49, 0xb6, 0x0f, 0xce, 0xef, 0x60, 0x13, 0xd0, 0x4e,
|
||||
0xc3, 0x8c, 0x00, 0xed, 0xdc, 0x19, 0x98, 0x73, 0x22, 0x2f, 0xac, 0x11, 0x40, 0x42, 0xe4, 0xf2,
|
||||
0x06, 0x5e, 0x3b, 0xa9, 0x4a, 0xee, 0x02, 0x3a, 0x25, 0xe4, 0xc2, 0x19, 0x83, 0x55, 0x70, 0x6e,
|
||||
0x64, 0x99, 0xc9, 0x55, 0xd7, 0x0d, 0xe1, 0xfd, 0x94, 0x44, 0x8b, 0x9c, 0x2b, 0xf6, 0x8b, 0xc5,
|
||||
0x19, 0x51, 0xf9, 0x96, 0x62, 0x07, 0x40, 0x56, 0x46, 0xda, 0xa8, 0x6f, 0x0c, 0xcc, 0xe0, 0x2a,
|
||||
0xc1, 0x9f, 0xa0, 0x93, 0x12, 0xce, 0x56, 0x4c, 0xe4, 0x72, 0xb9, 0x66, 0x94, 0x47, 0x76, 0xb3,
|
||||
0x8f, 0x06, 0x66, 0x60, 0xbd, 0xc4, 0x3f, 0x8a, 0x74, 0xdc, 0x38, 0xdc, 0x7f, 0x44, 0xee, 0x17,
|
||||
0x80, 0xdf, 0x24, 0xe4, 0x74, 0x21, 0x22, 0xca, 0xb1, 0x05, 0x75, 0x16, 0xe9, 0x0d, 0x1b, 0x41,
|
||||
0x9d, 0x45, 0xaf, 0xfd, 0xa9, 0xe9, 0xfc, 0xe1, 0xe8, 0xa0, 0xc3, 0xd1, 0x41, 0x4f, 0x47, 0x07,
|
||||
0xdd, 0x9d, 0x9c, 0xda, 0xe1, 0xe4, 0xd4, 0x1e, 0x4f, 0x4e, 0xed, 0x8f, 0x17, 0x33, 0x95, 0xe4,
|
||||
0xa1, 0xb7, 0x12, 0xa9, 0xbf, 0x12, 0x32, 0x15, 0xf2, 0xfc, 0x18, 0xca, 0x68, 0xe3, 0x17, 0xa7,
|
||||
0x94, 0x2b, 0xc6, 0xfd, 0xea, 0xa6, 0xc2, 0x96, 0xfe, 0xf6, 0xd1, 0x73, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0x7a, 0x9a, 0x17, 0x6f, 0x76, 0x02, 0x00, 0x00,
|
||||
// 419 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xb1, 0x6e, 0xdb, 0x30,
|
||||
0x10, 0x35, 0x2d, 0xd9, 0x8d, 0xaf, 0x82, 0x82, 0x12, 0x46, 0xa1, 0x7a, 0x50, 0x0d, 0x2d, 0xf5,
|
||||
0xd0, 0x48, 0x40, 0x83, 0x2e, 0xd9, 0x92, 0x14, 0xad, 0x17, 0x2f, 0x6a, 0xa7, 0x2e, 0x01, 0x65,
|
||||
0x32, 0x12, 0x11, 0x52, 0x2c, 0x44, 0xaa, 0x48, 0xfa, 0x15, 0xfd, 0x85, 0xfe, 0x4d, 0x47, 0x8f,
|
||||
0x1d, 0x0b, 0xfb, 0x47, 0x0a, 0x51, 0x92, 0xed, 0xa1, 0x83, 0x27, 0xbe, 0xf7, 0xee, 0xde, 0xe3,
|
||||
0x81, 0x3c, 0xf0, 0x0d, 0xd3, 0x86, 0x12, 0x43, 0xe2, 0x6f, 0x95, 0x32, 0x0a, 0x9f, 0xf5, 0x7c,
|
||||
0x36, 0xcd, 0x55, 0xae, 0xac, 0x98, 0x34, 0xa8, 0xad, 0xcf, 0x5e, 0xe5, 0x4a, 0xe5, 0x82, 0x25,
|
||||
0x96, 0x65, 0xf5, 0x7d, 0x42, 0xca, 0xa7, 0xb6, 0x14, 0x5d, 0x80, 0xf3, 0x41, 0xe5, 0x18, 0x83,
|
||||
0xab, 0xf9, 0x0f, 0x16, 0xa0, 0x39, 0x5a, 0x4c, 0x52, 0x8b, 0x1b, 0xad, 0x24, 0x92, 0x05, 0xc3,
|
||||
0x56, 0x6b, 0x70, 0xf4, 0x1e, 0x9c, 0x5b, 0x62, 0x70, 0x00, 0xcf, 0xa4, 0x2a, 0xf9, 0x03, 0xab,
|
||||
0x3a, 0x47, 0x4f, 0xf1, 0x14, 0x46, 0x82, 0x7f, 0x67, 0xda, 0xba, 0x46, 0x69, 0x4b, 0xa2, 0x4f,
|
||||
0x30, 0x59, 0x12, 0x7d, 0x5d, 0x72, 0x49, 0x04, 0x7e, 0x0b, 0x63, 0x62, 0x91, 0xf5, 0x3e, 0x7f,
|
||||
0x37, 0x8d, 0xdb, 0xf1, 0xe2, 0x7e, 0xbc, 0xf8, 0xba, 0x7c, 0x4a, 0xbb, 0x1e, 0xec, 0x01, 0x7a,
|
||||
0xb4, 0x61, 0x4e, 0x8a, 0x1e, 0xa3, 0x5b, 0xf0, 0x96, 0x44, 0x1f, 0xb2, 0x2e, 0x01, 0x0a, 0xa2,
|
||||
0xef, 0x4e, 0xc8, 0x9b, 0x14, 0xbd, 0x29, 0x5a, 0xc1, 0x79, 0x1b, 0x72, 0xc8, 0xb9, 0x02, 0xbf,
|
||||
0xc9, 0x39, 0x31, 0xcb, 0x2b, 0x8e, 0xbc, 0x51, 0x06, 0x2f, 0x6e, 0x08, 0x5d, 0xd5, 0xc2, 0xf0,
|
||||
0xcf, 0x3c, 0x2f, 0x89, 0xa9, 0x2b, 0x86, 0x43, 0x00, 0xdd, 0x13, 0x1d, 0xa0, 0xb9, 0xb3, 0xf0,
|
||||
0xd2, 0x23, 0x05, 0xbf, 0x81, 0x73, 0x49, 0x04, 0x5f, 0x73, 0x55, 0xeb, 0xbb, 0x7b, 0xce, 0x04,
|
||||
0x0d, 0x46, 0x73, 0xb4, 0xf0, 0x52, 0x7f, 0x2f, 0x7f, 0x6c, 0xd4, 0x2b, 0x77, 0xf3, 0xeb, 0x35,
|
||||
0x8a, 0x28, 0xc0, 0x17, 0x92, 0x09, 0xb6, 0x52, 0x94, 0x09, 0xec, 0xc3, 0x90, 0x53, 0x3b, 0xa1,
|
||||
0x9b, 0x0e, 0x39, 0xfd, 0xdf, 0x4f, 0xe1, 0x97, 0x30, 0x2e, 0x6b, 0x99, 0xb1, 0x2a, 0x70, 0x6c,
|
||||
0x5f, 0xc7, 0xf0, 0x0c, 0xce, 0x24, 0x33, 0xa4, 0xd9, 0x96, 0xc0, 0xb5, 0x37, 0xee, 0xf9, 0xcd,
|
||||
0xf2, 0xf7, 0x36, 0x44, 0x9b, 0x6d, 0x88, 0xfe, 0x6e, 0x43, 0xf4, 0x73, 0x17, 0x0e, 0x36, 0xbb,
|
||||
0x70, 0xf0, 0x67, 0x17, 0x0e, 0xbe, 0xc6, 0x39, 0x37, 0x45, 0x9d, 0xc5, 0x6b, 0x25, 0x93, 0xb5,
|
||||
0xd2, 0x52, 0xe9, 0xee, 0xb8, 0xd0, 0xf4, 0x21, 0x69, 0xd6, 0xaf, 0x36, 0x5c, 0x24, 0xfd, 0x1e,
|
||||
0x66, 0x63, 0xfb, 0x5e, 0x97, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xb5, 0x8f, 0xef, 0x9c, 0xaa,
|
||||
0x02, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Dog) Marshal() (dAtA []byte, err error) {
|
||||
|
@ -660,6 +678,18 @@ func (m *TableModel) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Metadata) > 0 {
|
||||
i -= len(m.Metadata)
|
||||
copy(dAtA[i:], m.Metadata)
|
||||
i = encodeVarintTestdata(dAtA, i, uint64(len(m.Metadata)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if m.Number != 0 {
|
||||
i = encodeVarintTestdata(dAtA, i, uint64(m.Number))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
|
@ -796,6 +826,13 @@ func (m *TableModel) Size() (n int) {
|
|||
if l > 0 {
|
||||
n += 1 + l + sovTestdata(uint64(l))
|
||||
}
|
||||
if m.Number != 0 {
|
||||
n += 1 + sovTestdata(uint64(m.Number))
|
||||
}
|
||||
l = len(m.Metadata)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTestdata(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -1494,6 +1531,59 @@ func (m *TableModel) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Number", wireType)
|
||||
}
|
||||
m.Number = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdata
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Number |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTestdata
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthTestdata
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTestdata
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Metadata = append(m.Metadata[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Metadata == nil {
|
||||
m.Metadata = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTestdata(dAtA[iNdEx:])
|
||||
|
|
|
@ -39,4 +39,6 @@ message BadMultiSignature {
|
|||
message TableModel {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
uint64 number = 3;
|
||||
bytes metadata = 4;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ var (
|
|||
ErrORMEmptyModel = Register(ormCodespace, 45, "invalid argument")
|
||||
|
||||
// ErrORMKeyMaxLength defines an error when a key exceeds max length
|
||||
ErrORMKeyMaxLength = Register(ormCodespace, 46, "index key exceeds max length")
|
||||
ErrORMKeyMaxLength = Register(ormCodespace, 46, "key exceeds max length")
|
||||
|
||||
// ErrORMEmptyKey defines an error for an empty key
|
||||
ErrORMEmptyKey = Register(ormCodespace, 47, "cannot use empty key")
|
||||
|
|
|
@ -17,7 +17,7 @@ require github.com/tendermint/tm-db v0.6.4
|
|||
|
||||
require (
|
||||
github.com/DataDog/zstd v1.4.5 // indirect
|
||||
github.com/armon/go-metrics v0.3.9 // indirect
|
||||
github.com/armon/go-metrics v0.3.10 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/btcsuite/btcd v0.22.0-beta // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
|
@ -27,12 +27,13 @@ require (
|
|||
github.com/cosmos/iavl v0.17.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.3 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-kit/kit v0.10.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
|
@ -44,6 +45,7 @@ require (
|
|||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/lazyledger/smt v0.2.1-0.20210709230900-03ea40719554 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
|
@ -56,7 +58,7 @@ require (
|
|||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.31.1 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
|
@ -69,7 +71,7 @@ require (
|
|||
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect
|
||||
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
|
||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||
github.com/tendermint/tendermint v0.34.13 // indirect
|
||||
github.com/tendermint/tendermint v0.34.14 // indirect
|
||||
go.etcd.io/bbolt v1.3.5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect
|
||||
|
@ -87,3 +89,5 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
|
|||
replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk => ../../
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk/db => ../../db
|
||||
|
|
|
@ -101,8 +101,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:
|
|||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18=
|
||||
github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo=
|
||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||
|
@ -162,8 +162,8 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80
|
|||
github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coinbase/rosetta-sdk-go v0.6.10 h1:rgHD/nHjxLh0lMEdfGDqpTtlvtSBwULqrrZ2qPdNaCM=
|
||||
github.com/coinbase/rosetta-sdk-go v0.6.10/go.mod h1:J/JFMsfcePrjJZkwQFLh+hJErkAmdm9Iyy3D5Y0LfXo=
|
||||
github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg=
|
||||
github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE=
|
||||
github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
||||
github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
||||
github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8=
|
||||
|
@ -217,9 +217,11 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM
|
|||
github.com/dgraph-io/badger/v2 v2.2007.1/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/badger/v3 v3.2103.1/go.mod h1:dULbq6ehJ5K0cGW/1TQ9iSfUk0gbSiToDWmWmTsJ53E=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI=
|
||||
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
|
||||
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||
|
@ -300,6 +302,7 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6
|
|||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0=
|
||||
github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -342,6 +345,7 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
|
@ -480,7 +484,7 @@ github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH
|
|||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jhump/protoreflect v1.10.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
|
||||
github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
|
||||
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
|
||||
|
@ -506,8 +510,9 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
|
@ -520,6 +525,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lazyledger/smt v0.2.1-0.20210709230900-03ea40719554 h1:nDOkLO7klmnEw1s4AyKt1Arvpgyh33uj1JmkYlJaDsk=
|
||||
github.com/lazyledger/smt v0.2.1-0.20210709230900-03ea40719554/go.mod h1:9+Pb2/tg1PvEgW7aFx4bFhDE4bvbI03zuJ8kb7nJ9Jc=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
|
@ -689,8 +696,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
|
|||
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.31.1 h1:d18hG4PkHnNAKNMOmFuXFaiY8Us0nird/2m60uS1AMs=
|
||||
github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
|
@ -809,8 +816,9 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM
|
|||
github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4=
|
||||
github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg=
|
||||
github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ=
|
||||
github.com/tendermint/tendermint v0.34.13 h1:fu+tsHudbOr5PvepjH0q47Jae59hQAvn3IqAHv2EbC8=
|
||||
github.com/tendermint/tendermint v0.34.13/go.mod h1:6RVVRBqwtKhA+H59APKumO+B7Nye4QXSFc6+TYxAxCI=
|
||||
github.com/tendermint/tendermint v0.34.14 h1:GCXmlS8Bqd2Ix3TQCpwYLUNHe+Y+QyJsm5YE+S/FkPo=
|
||||
github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0=
|
||||
github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI=
|
||||
github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8=
|
||||
github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ=
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var _ Indexable = &AutoUInt64Table{}
|
||||
|
||||
// AutoUInt64Table is the table type with an auto incrementing ID.
|
||||
type AutoUInt64Table struct {
|
||||
*table
|
||||
seq Sequence
|
||||
}
|
||||
|
||||
// NewAutoUInt64Table creates a new AutoUInt64Table.
|
||||
func NewAutoUInt64Table(prefixData [2]byte, prefixSeq byte, model codec.ProtoMarshaler, cdc codec.Codec) (*AutoUInt64Table, error) {
|
||||
table, err := newTable(prefixData, model, cdc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &AutoUInt64Table{
|
||||
table: table,
|
||||
seq: NewSequence(prefixSeq),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create a new persistent object with an auto generated uint64 primary key. The
|
||||
// key is returned.
|
||||
//
|
||||
// Create iterates through the registered callbacks that may add secondary index
|
||||
// keys.
|
||||
func (a AutoUInt64Table) Create(store sdk.KVStore, obj codec.ProtoMarshaler) (uint64, error) {
|
||||
autoIncID := a.seq.NextVal(store)
|
||||
err := a.table.Create(store, EncodeSequence(autoIncID), obj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return autoIncID, nil
|
||||
}
|
||||
|
||||
// Update updates the given object under the rowID key. It expects the key to
|
||||
// exists already and fails with an `ErrNotFound` otherwise. Any caller must
|
||||
// therefore make sure that this contract is fulfilled. Parameters must not be
|
||||
// nil.
|
||||
//
|
||||
// Update iterates through the registered callbacks that may add or remove
|
||||
// secondary index keys.
|
||||
func (a AutoUInt64Table) Update(store sdk.KVStore, rowID uint64, newValue codec.ProtoMarshaler) error {
|
||||
return a.table.Update(store, EncodeSequence(rowID), newValue)
|
||||
}
|
||||
|
||||
// Delete removes the object under the rowID key. It expects the key to exists already
|
||||
// and fails with a `ErrNotFound` otherwise. Any caller must therefore make sure that this contract
|
||||
// is fulfilled.
|
||||
//
|
||||
// Delete iterates though the registered callbacks and removes secondary index keys by them.
|
||||
func (a AutoUInt64Table) Delete(store sdk.KVStore, rowID uint64) error {
|
||||
return a.table.Delete(store, EncodeSequence(rowID))
|
||||
}
|
||||
|
||||
// Has checks if a rowID exists.
|
||||
func (a AutoUInt64Table) Has(store sdk.KVStore, rowID uint64) bool {
|
||||
return a.table.Has(store, EncodeSequence(rowID))
|
||||
}
|
||||
|
||||
// GetOne load the object persisted for the given RowID into the dest parameter.
|
||||
// If none exists `ErrNotFound` is returned instead. Parameters must not be nil.
|
||||
func (a AutoUInt64Table) GetOne(store sdk.KVStore, rowID uint64, dest codec.ProtoMarshaler) (RowID, error) {
|
||||
rawRowID := EncodeSequence(rowID)
|
||||
if err := a.table.GetOne(store, rawRowID, dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rawRowID, nil
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
)
|
||||
|
||||
type TestKeeper struct {
|
||||
autoUInt64Table *AutoUInt64Table
|
||||
primaryKeyTable *PrimaryKeyTable
|
||||
}
|
||||
|
||||
var (
|
||||
AutoUInt64TableTablePrefix [2]byte = [2]byte{0x0}
|
||||
PrimaryKeyTablePrefix [2]byte = [2]byte{0x1}
|
||||
AutoUInt64TableSeqPrefix byte = 0x2
|
||||
)
|
||||
|
||||
func NewTestKeeper(cdc codec.Codec) TestKeeper {
|
||||
k := TestKeeper{}
|
||||
|
||||
autoUInt64Table, err := NewAutoUInt64Table(AutoUInt64TableTablePrefix, AutoUInt64TableSeqPrefix, &testdata.TableModel{}, cdc)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
k.autoUInt64Table = autoUInt64Table
|
||||
|
||||
primaryKeyTable, err := NewPrimaryKeyTable(PrimaryKeyTablePrefix, &testdata.TableModel{}, cdc)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
k.primaryKeyTable = primaryKeyTable
|
||||
|
||||
return k
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
)
|
||||
|
||||
// genTableModel generates a new table model. At the moment it doesn't
|
||||
// generate empty strings for Name.
|
||||
var genTableModel = rapid.Custom(func(t *rapid.T) *testdata.TableModel {
|
||||
return &testdata.TableModel{
|
||||
Id: rapid.Uint64().Draw(t, "id").(uint64),
|
||||
Name: rapid.StringN(1, 100, 150).Draw(t, "name").(string),
|
||||
Number: rapid.Uint64().Draw(t, "number ").(uint64),
|
||||
Metadata: []byte(rapid.StringN(1, 100, 150).Draw(t, "metadata").(string)),
|
||||
}
|
||||
})
|
|
@ -0,0 +1,75 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// MaxBytesLen is the maximum allowed length for a key part of type []byte
|
||||
const MaxBytesLen = 255
|
||||
|
||||
// buildKeyFromParts encodes and concatenates primary key and index parts.
|
||||
// They can be []byte, string, and integer types. The function will return
|
||||
// an error if there is a part of any other type.
|
||||
// Key parts, except the last part, follow these rules:
|
||||
// - []byte is encoded with a single byte length prefix
|
||||
// - strings are null-terminated
|
||||
// - integers are encoded using 8 byte big endian.
|
||||
func buildKeyFromParts(parts []interface{}) ([]byte, error) {
|
||||
bytesSlice := make([][]byte, len(parts))
|
||||
totalLen := 0
|
||||
var err error
|
||||
for i, part := range parts {
|
||||
bytesSlice[i], err = keyPartBytes(part, len(parts) > 1 && i == len(parts)-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalLen += len(bytesSlice[i])
|
||||
}
|
||||
key := make([]byte, 0, totalLen)
|
||||
for _, bs := range bytesSlice {
|
||||
key = append(key, bs...)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func keyPartBytes(part interface{}, last bool) ([]byte, error) {
|
||||
switch v := part.(type) {
|
||||
case []byte:
|
||||
if last || len(v) == 0 {
|
||||
return v, nil
|
||||
}
|
||||
return AddLengthPrefix(v), nil
|
||||
case string:
|
||||
if last || len(v) == 0 {
|
||||
return []byte(v), nil
|
||||
}
|
||||
return NullTerminatedBytes(v), nil
|
||||
case uint64:
|
||||
return EncodeSequence(v), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("type %T not allowed as key part", v)
|
||||
}
|
||||
}
|
||||
|
||||
// AddLengthPrefix prefixes the byte array with its length as 8 bytes. The function will panic
|
||||
// if the bytes length is bigger than 255.
|
||||
func AddLengthPrefix(bytes []byte) []byte {
|
||||
byteLen := len(bytes)
|
||||
if byteLen > MaxBytesLen {
|
||||
panic(errors.Wrap(errors.ErrORMKeyMaxLength, "Cannot create key part with an []byte of length greater than 255 bytes. Try again with a smaller []byte."))
|
||||
}
|
||||
|
||||
prefixedBytes := make([]byte, 1+len(bytes))
|
||||
copy(prefixedBytes, []byte{uint8(byteLen)})
|
||||
copy(prefixedBytes[1:], bytes)
|
||||
return prefixedBytes
|
||||
}
|
||||
|
||||
// NullTerminatedBytes converts string to byte array and null terminate it
|
||||
func NullTerminatedBytes(s string) []byte {
|
||||
bytes := make([]byte, len(s)+1)
|
||||
copy(bytes, s)
|
||||
return bytes
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAddLengthPrefix(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
in []byte
|
||||
expected []byte
|
||||
}{
|
||||
{"empty", []byte{}, []byte{0}},
|
||||
{"nil", nil, []byte{0}},
|
||||
{"some data", []byte{0, 1, 100, 200}, []byte{4, 0, 1, 100, 200}},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
out := AddLengthPrefix(tc.in)
|
||||
require.Equal(t, tc.expected, out)
|
||||
})
|
||||
}
|
||||
|
||||
require.Panics(t, func() {
|
||||
AddLengthPrefix(make([]byte, 256))
|
||||
})
|
||||
}
|
||||
|
||||
func TestNullTerminatedBytes(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
in string
|
||||
expected []byte
|
||||
}{
|
||||
{"empty", "", []byte{0}},
|
||||
{"some data", "abc", []byte{0x61, 0x62, 0x63, 0}},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
out := NullTerminatedBytes(tc.in)
|
||||
require.Equal(t, tc.expected, out)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
)
|
||||
|
||||
func TestKeeperEndToEndWithAutoUInt64Table(t *testing.T) {
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
|
||||
ctx := NewMockContext()
|
||||
store := ctx.KVStore(sdk.NewKVStoreKey("test"))
|
||||
|
||||
k := NewTestKeeper(cdc)
|
||||
|
||||
tm := testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "name",
|
||||
Number: 123,
|
||||
Metadata: []byte("metadata"),
|
||||
}
|
||||
// when stored
|
||||
rowID, err := k.autoUInt64Table.Create(store, &tm)
|
||||
require.NoError(t, err)
|
||||
// then we should find it
|
||||
exists := k.autoUInt64Table.Has(store, rowID)
|
||||
require.True(t, exists)
|
||||
|
||||
// and load it
|
||||
var loaded testdata.TableModel
|
||||
|
||||
binKey, err := k.autoUInt64Table.GetOne(store, rowID, &loaded)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, rowID, binary.BigEndian.Uint64(binKey))
|
||||
require.Equal(t, tm, loaded)
|
||||
|
||||
// when updated
|
||||
tm.Name = "new name"
|
||||
err = k.autoUInt64Table.Update(store, rowID, &tm)
|
||||
require.NoError(t, err)
|
||||
|
||||
binKey, err = k.autoUInt64Table.GetOne(store, rowID, &loaded)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, rowID, binary.BigEndian.Uint64(binKey))
|
||||
require.Equal(t, tm, loaded)
|
||||
|
||||
// when deleted
|
||||
err = k.autoUInt64Table.Delete(store, rowID)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists = k.autoUInt64Table.Has(store, rowID)
|
||||
require.False(t, exists)
|
||||
}
|
||||
|
||||
func TestKeeperEndToEndWithPrimaryKeyTable(t *testing.T) {
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
|
||||
ctx := NewMockContext()
|
||||
store := ctx.KVStore(sdk.NewKVStoreKey("test"))
|
||||
|
||||
k := NewTestKeeper(cdc)
|
||||
|
||||
tm := testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "name",
|
||||
Number: 123,
|
||||
Metadata: []byte("metadata"),
|
||||
}
|
||||
// when stored
|
||||
err := k.primaryKeyTable.Create(store, &tm)
|
||||
require.NoError(t, err)
|
||||
// then we should find it by primary key
|
||||
primaryKey := PrimaryKey(&tm)
|
||||
exists := k.primaryKeyTable.Has(store, primaryKey)
|
||||
require.True(t, exists)
|
||||
|
||||
// and load it by primary key
|
||||
var loaded testdata.TableModel
|
||||
err = k.primaryKeyTable.GetOne(store, primaryKey, &loaded)
|
||||
require.NoError(t, err)
|
||||
|
||||
// then values should match expectations
|
||||
require.Equal(t, tm, loaded)
|
||||
|
||||
// and when we create another entry with the same primary key
|
||||
err = k.primaryKeyTable.Create(store, &tm)
|
||||
// then it should fail as the primary key must be unique
|
||||
require.True(t, errors.ErrORMUniqueConstraint.Is(err), err)
|
||||
|
||||
// and when entity updated with new primary key
|
||||
updatedMember := &testdata.TableModel{
|
||||
Id: 2,
|
||||
Name: tm.Name,
|
||||
Number: tm.Number,
|
||||
Metadata: tm.Metadata,
|
||||
}
|
||||
// then it should fail as the primary key is immutable
|
||||
err = k.primaryKeyTable.Update(store, updatedMember)
|
||||
require.Error(t, err)
|
||||
|
||||
// and when entity updated with non primary key attribute modified
|
||||
updatedMember = &testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "new name",
|
||||
Number: tm.Number,
|
||||
Metadata: tm.Metadata,
|
||||
}
|
||||
// then it should not fail
|
||||
err = k.primaryKeyTable.Update(store, updatedMember)
|
||||
require.NoError(t, err)
|
||||
|
||||
// and when entity deleted
|
||||
err = k.primaryKeyTable.Delete(store, &tm)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists = k.primaryKeyTable.Has(store, primaryKey)
|
||||
require.False(t, exists)
|
||||
}
|
||||
|
||||
func TestGasCostsPrimaryKeyTable(t *testing.T) {
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
|
||||
ctx := NewMockContext()
|
||||
store := ctx.KVStore(sdk.NewKVStoreKey("test"))
|
||||
|
||||
k := NewTestKeeper(cdc)
|
||||
|
||||
tm := testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "name",
|
||||
Number: 123,
|
||||
Metadata: []byte("metadata"),
|
||||
}
|
||||
rowID, err := k.autoUInt64Table.Create(store, &tm)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(1), rowID)
|
||||
|
||||
gCtx := NewGasCountingMockContext()
|
||||
err = k.primaryKeyTable.Create(gCtx.KVStore(store), &tm)
|
||||
require.NoError(t, err)
|
||||
t.Logf("gas consumed on create: %d", gCtx.GasConsumed())
|
||||
|
||||
// get by primary key
|
||||
gCtx.ResetGasMeter()
|
||||
var loaded testdata.TableModel
|
||||
err = k.primaryKeyTable.GetOne(gCtx.KVStore(store), PrimaryKey(&tm), &loaded)
|
||||
require.NoError(t, err)
|
||||
t.Logf("gas consumed on get by primary key: %d", gCtx.GasConsumed())
|
||||
|
||||
// delete
|
||||
gCtx.ResetGasMeter()
|
||||
err = k.primaryKeyTable.Delete(gCtx.KVStore(store), &tm)
|
||||
require.NoError(t, err)
|
||||
t.Logf("gas consumed on delete by primary key: %d", gCtx.GasConsumed())
|
||||
|
||||
// with 3 elements
|
||||
var tms []testdata.TableModel
|
||||
for i := 1; i < 4; i++ {
|
||||
gCtx.ResetGasMeter()
|
||||
tm := testdata.TableModel{
|
||||
Id: uint64(i),
|
||||
Name: fmt.Sprintf("name%d", i),
|
||||
Number: 123,
|
||||
Metadata: []byte("metadata"),
|
||||
}
|
||||
err = k.primaryKeyTable.Create(gCtx.KVStore(store), &tm)
|
||||
require.NoError(t, err)
|
||||
t.Logf("%d: gas consumed on create: %d", i, gCtx.GasConsumed())
|
||||
tms = append(tms, tm)
|
||||
}
|
||||
|
||||
for i := 1; i < 4; i++ {
|
||||
gCtx.ResetGasMeter()
|
||||
tm := testdata.TableModel{
|
||||
Id: uint64(i),
|
||||
Name: fmt.Sprintf("name%d", i),
|
||||
Number: 123,
|
||||
Metadata: []byte("metadata"),
|
||||
}
|
||||
err = k.primaryKeyTable.GetOne(gCtx.KVStore(store), PrimaryKey(&tm), &loaded)
|
||||
require.NoError(t, err)
|
||||
t.Logf("%d: gas consumed on get by primary key: %d", i, gCtx.GasConsumed())
|
||||
}
|
||||
|
||||
// delete
|
||||
for i, m := range tms {
|
||||
gCtx.ResetGasMeter()
|
||||
|
||||
err = k.primaryKeyTable.Delete(gCtx.KVStore(store), &m)
|
||||
require.NoError(t, err)
|
||||
t.Logf("%d: gas consumed on delete: %d", i, gCtx.GasConsumed())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var _ Indexable = &PrimaryKeyTable{}
|
||||
|
||||
// PrimaryKeyTable provides simpler object style orm methods without passing database RowIDs.
|
||||
// Entries are persisted and loaded with a reference to their unique primary key.
|
||||
type PrimaryKeyTable struct {
|
||||
*table
|
||||
}
|
||||
|
||||
// NewPrimaryKeyTable creates a new PrimaryKeyTable.
|
||||
func NewPrimaryKeyTable(prefixData [2]byte, model PrimaryKeyed, cdc codec.Codec) (*PrimaryKeyTable, error) {
|
||||
table, err := newTable(prefixData, model, cdc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PrimaryKeyTable{
|
||||
table: table,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PrimaryKeyed defines an object type that is aware of its immutable primary key.
|
||||
type PrimaryKeyed interface {
|
||||
// PrimaryKeyFields returns the fields of the object that will make up
|
||||
// the primary key. The PrimaryKey function will encode and concatenate
|
||||
// the fields to build the primary key.
|
||||
//
|
||||
// PrimaryKey parts can be []byte, string, and integer types. []byte is
|
||||
// encoded with a length prefix, strings are null-terminated, and
|
||||
// integers are encoded using 8 byte big endian.
|
||||
//
|
||||
// IMPORTANT: []byte parts are encoded with a single byte length prefix,
|
||||
// so cannot be longer than 255 bytes.
|
||||
PrimaryKeyFields() []interface{}
|
||||
codec.ProtoMarshaler
|
||||
}
|
||||
|
||||
// PrimaryKey returns the immutable and serialized primary key of this object.
|
||||
// The primary key has to be unique within it's domain so that not two with same
|
||||
// value can exist in the same table. This means PrimaryKeyFields() has to
|
||||
// return a unique value for each object.
|
||||
func PrimaryKey(obj PrimaryKeyed) []byte {
|
||||
fields := obj.PrimaryKeyFields()
|
||||
key, err := buildKeyFromParts(fields)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// Create persists the given object under their primary key. It checks if the
|
||||
// key already exists and may return an `ErrUniqueConstraint`.
|
||||
//
|
||||
// Create iterates through the registered callbacks that may add secondary
|
||||
// index keys.
|
||||
func (a PrimaryKeyTable) Create(store sdk.KVStore, obj PrimaryKeyed) error {
|
||||
rowID := PrimaryKey(obj)
|
||||
return a.table.Create(store, rowID, obj)
|
||||
}
|
||||
|
||||
// Update updates the given object under the primary key. It expects the key to
|
||||
// exists already and fails with an `ErrNotFound` otherwise. Any caller must
|
||||
// therefore make sure that this contract is fulfilled. Parameters must not be
|
||||
// nil.
|
||||
//
|
||||
// Update iterates through the registered callbacks that may add or remove
|
||||
// secondary index keys.
|
||||
func (a PrimaryKeyTable) Update(store sdk.KVStore, newValue PrimaryKeyed) error {
|
||||
return a.table.Update(store, PrimaryKey(newValue), newValue)
|
||||
}
|
||||
|
||||
// Set persists the given object under the rowID key. It does not check if the
|
||||
// key already exists and overwrites the value if it does.
|
||||
//
|
||||
// Set iterates through the registered callbacks that may add secondary index
|
||||
// keys.
|
||||
func (a PrimaryKeyTable) Set(store sdk.KVStore, newValue PrimaryKeyed) error {
|
||||
return a.table.Set(store, PrimaryKey(newValue), newValue)
|
||||
}
|
||||
|
||||
// Delete removes the object. It expects the primary key to exists already and
|
||||
// fails with a `ErrNotFound` otherwise. Any caller must therefore make sure
|
||||
// that this contract is fulfilled.
|
||||
//
|
||||
// Delete iterates through the registered callbacks that remove secondary index
|
||||
// keys.
|
||||
func (a PrimaryKeyTable) Delete(store sdk.KVStore, obj PrimaryKeyed) error {
|
||||
return a.table.Delete(store, PrimaryKey(obj))
|
||||
}
|
||||
|
||||
// Has checks if a key exists. Always returns false on nil or empty key.
|
||||
func (a PrimaryKeyTable) Has(store sdk.KVStore, primaryKey RowID) bool {
|
||||
return a.table.Has(store, primaryKey)
|
||||
}
|
||||
|
||||
// Contains returns true when an object with same type and primary key is persisted in this table.
|
||||
func (a PrimaryKeyTable) Contains(store sdk.KVStore, obj PrimaryKeyed) bool {
|
||||
if err := assertCorrectType(a.table.model, obj); err != nil {
|
||||
return false
|
||||
}
|
||||
return a.table.Has(store, PrimaryKey(obj))
|
||||
}
|
||||
|
||||
// GetOne loads the object persisted for the given primary Key into the dest parameter.
|
||||
// If none exists `ErrNotFound` is returned instead. Parameters must not be nil.
|
||||
func (a PrimaryKeyTable) GetOne(store sdk.KVStore, primKey RowID, dest codec.ProtoMarshaler) error {
|
||||
return a.table.GetOne(store, primKey, dest)
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
)
|
||||
|
||||
func TestPrimaryKeyTable(t *testing.T) {
|
||||
rapid.Check(t, rapid.Run(&primaryKeyMachine{}))
|
||||
}
|
||||
|
||||
// primaryKeyMachine is a state machine model of the PrimaryKeyTable. The state
|
||||
// is modelled as a map of strings to TableModels.
|
||||
type primaryKeyMachine struct {
|
||||
store sdk.KVStore
|
||||
table *PrimaryKeyTable
|
||||
state map[string]*testdata.TableModel
|
||||
}
|
||||
|
||||
// stateKeys gets all the keys in the model map
|
||||
func (m *primaryKeyMachine) stateKeys() []string {
|
||||
keys := make([]string, len(m.state))
|
||||
|
||||
i := 0
|
||||
for k := range m.state {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// Generate a TableModel that has a 50% chance of being a part of the existing
|
||||
// state
|
||||
func (m *primaryKeyMachine) genTableModel() *rapid.Generator {
|
||||
genStateTableModel := rapid.Custom(func(t *rapid.T) *testdata.TableModel {
|
||||
pk := rapid.SampledFrom(m.stateKeys()).Draw(t, "key").(string)
|
||||
return m.state[pk]
|
||||
})
|
||||
|
||||
if len(m.stateKeys()) == 0 {
|
||||
return genTableModel
|
||||
} else {
|
||||
return rapid.OneOf(genTableModel, genStateTableModel)
|
||||
}
|
||||
}
|
||||
|
||||
// Init creates a new instance of the state machine model by building the real
|
||||
// table and making the empty model map
|
||||
func (m *primaryKeyMachine) Init(t *rapid.T) {
|
||||
// Create context
|
||||
ctx := NewMockContext()
|
||||
m.store = ctx.KVStore(sdk.NewKVStoreKey("test"))
|
||||
|
||||
// Create primary key table
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
table, err := NewPrimaryKeyTable(
|
||||
[2]byte{0x1},
|
||||
&testdata.TableModel{},
|
||||
cdc,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
m.table = table
|
||||
|
||||
// Create model state
|
||||
m.state = make(map[string]*testdata.TableModel)
|
||||
}
|
||||
|
||||
// Check that the real values match the state values.
|
||||
func (m *primaryKeyMachine) Check(t *rapid.T) {
|
||||
for i := range m.state {
|
||||
has := m.table.Has(m.store, []byte(i))
|
||||
require.Equal(t, true, has)
|
||||
}
|
||||
}
|
||||
|
||||
// Create is one of the model commands. It adds an object to the table, creating
|
||||
// an error if it already exists.
|
||||
func (m *primaryKeyMachine) Create(t *rapid.T) {
|
||||
g := genTableModel.Draw(t, "g").(*testdata.TableModel)
|
||||
pk := string(PrimaryKey(g))
|
||||
|
||||
t.Logf("pk: %v", pk)
|
||||
t.Logf("m.state: %v", m.state)
|
||||
|
||||
err := m.table.Create(m.store, g)
|
||||
|
||||
if m.state[pk] != nil {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
m.state[pk] = g
|
||||
}
|
||||
}
|
||||
|
||||
// Update is one of the model commands. It updates the value at a given primary
|
||||
// key and fails if that primary key doesn't already exist in the table.
|
||||
func (m *primaryKeyMachine) Update(t *rapid.T) {
|
||||
tm := m.genTableModel().Draw(t, "tm").(*testdata.TableModel)
|
||||
|
||||
newName := rapid.StringN(1, 100, 150).Draw(t, "newName").(string)
|
||||
tm.Name = newName
|
||||
|
||||
// Perform the real Update
|
||||
err := m.table.Update(m.store, tm)
|
||||
|
||||
if m.state[string(PrimaryKey(tm))] == nil {
|
||||
// If there's no value in the model, we expect an error
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
// If we have a value in the model, expect no error
|
||||
require.NoError(t, err)
|
||||
|
||||
// Update the model with the new value
|
||||
m.state[string(PrimaryKey(tm))] = tm
|
||||
}
|
||||
}
|
||||
|
||||
// Set is one of the model commands. It sets the value at a key in the table
|
||||
// whether it exists or not.
|
||||
func (m *primaryKeyMachine) Set(t *rapid.T) {
|
||||
g := genTableModel.Draw(t, "g").(*testdata.TableModel)
|
||||
pk := string(PrimaryKey(g))
|
||||
|
||||
err := m.table.Set(m.store, g)
|
||||
|
||||
require.NoError(t, err)
|
||||
m.state[pk] = g
|
||||
}
|
||||
|
||||
// Delete is one of the model commands. It removes the object with the given
|
||||
// primary key from the table and returns an error if that primary key doesn't
|
||||
// already exist in the table.
|
||||
func (m *primaryKeyMachine) Delete(t *rapid.T) {
|
||||
tm := m.genTableModel().Draw(t, "tm").(*testdata.TableModel)
|
||||
|
||||
// Perform the real Delete
|
||||
err := m.table.Delete(m.store, tm)
|
||||
|
||||
if m.state[string(PrimaryKey(tm))] == nil {
|
||||
// If there's no value in the model, we expect an error
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
// If we have a value in the model, expect no error
|
||||
require.NoError(t, err)
|
||||
|
||||
// Delete the value from the model
|
||||
delete(m.state, string(PrimaryKey(tm)))
|
||||
}
|
||||
}
|
||||
|
||||
// Has is one of the model commands. It checks whether a key already exists in
|
||||
// the table.
|
||||
func (m *primaryKeyMachine) Has(t *rapid.T) {
|
||||
pk := PrimaryKey(m.genTableModel().Draw(t, "g").(*testdata.TableModel))
|
||||
|
||||
realHas := m.table.Has(m.store, pk)
|
||||
modelHas := m.state[string(pk)] != nil
|
||||
|
||||
require.Equal(t, realHas, modelHas)
|
||||
}
|
||||
|
||||
// GetOne is one of the model commands. It fetches an object from the table by
|
||||
// its primary key and returns an error if that primary key isn't in the table.
|
||||
func (m *primaryKeyMachine) GetOne(t *rapid.T) {
|
||||
pk := PrimaryKey(m.genTableModel().Draw(t, "tm").(*testdata.TableModel))
|
||||
|
||||
var tm testdata.TableModel
|
||||
|
||||
err := m.table.GetOne(m.store, pk, &tm)
|
||||
t.Logf("tm: %v", tm)
|
||||
|
||||
if m.state[string(pk)] == nil {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *m.state[string(pk)], tm)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
)
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
|
||||
ctx := NewMockContext()
|
||||
store := ctx.KVStore(sdk.NewKVStoreKey("test"))
|
||||
|
||||
tb, err := NewPrimaryKeyTable([2]byte{0x1}, &testdata.TableModel{}, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
obj := testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "Some name",
|
||||
}
|
||||
err = tb.Create(store, &obj)
|
||||
require.NoError(t, err)
|
||||
|
||||
specs := map[string]struct {
|
||||
src PrimaryKeyed
|
||||
exp bool
|
||||
}{
|
||||
|
||||
"same object": {src: &obj, exp: true},
|
||||
"clone": {
|
||||
src: &testdata.TableModel{
|
||||
Id: 1,
|
||||
Name: "Some name",
|
||||
},
|
||||
exp: true,
|
||||
},
|
||||
"different primary key": {
|
||||
src: &testdata.TableModel{
|
||||
Id: 2,
|
||||
Name: "Some name",
|
||||
},
|
||||
exp: false,
|
||||
},
|
||||
"different type, same key": {
|
||||
src: mockPrimaryKeyed{&obj},
|
||||
exp: false,
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
got := tb.Contains(store, spec.src)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockPrimaryKeyed struct {
|
||||
*testdata.TableModel
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
# Table
|
||||
|
||||
A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/9f78f16ae75cc42fc5fe636bde18a453ba74831f/x/group/internal/orm/table.go#L24-L30
|
||||
|
||||
In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes.
|
||||
Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store.
|
||||
|
||||
The `table` struct does not:
|
||||
- enforce uniqueness of the `RowID`
|
||||
- enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix
|
||||
of another
|
||||
- optimize Gas usage conditions
|
||||
The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements.
|
||||
|
||||
## AutoUInt64Table
|
||||
|
||||
`AutoUInt64Table` is a table type with an auto incrementing `uint64` ID.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/9f78f16ae75cc42fc5fe636bde18a453ba74831f/x/group/internal/orm/auto_uint64.go#L11-L14
|
||||
|
||||
It's based on the `Sequence` struct which is a persistent unique key generator based on a counter encoded using 8 byte big endian.
|
||||
|
||||
## PrimaryKeyTable
|
||||
|
||||
`PrimaryKeyTable` provides simpler object style orm methods where are persisted and loaded with a reference to their unique primary key.
|
||||
|
||||
The model provided for creating a `PrimaryKeyTable` should implement the `PrimaryKeyed` interface:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/9f78f16ae75cc42fc5fe636bde18a453ba74831f/x/group/internal/orm/primary_key.go#L28-L41
|
||||
|
||||
`PrimaryKeyFields()` method returns the list of key parts for a given object.
|
||||
The primary key parts can be []byte, string, and `uint64` types.
|
||||
Key parts, except the last part, follow these rules:
|
||||
- []byte is encoded with a single byte length prefix
|
||||
- strings are null-terminated
|
||||
- `uint64` are encoded using 8 byte big endian.
|
|
@ -1,26 +1,9 @@
|
|||
## Abstract
|
||||
# Abstract
|
||||
|
||||
The orm package provides a framework for creating relational database tables with primary and secondary keys.
|
||||
|
||||
### Tables
|
||||
## Contents
|
||||
|
||||
```go
|
||||
type table struct {
|
||||
model reflect.Type
|
||||
prefix [2]byte
|
||||
afterSet []AfterSetInterceptor
|
||||
afterDelete []AfterDeleteInterceptor
|
||||
cdc codec.Codec
|
||||
}
|
||||
```
|
||||
|
||||
A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling.
|
||||
In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes.
|
||||
Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store.
|
||||
|
||||
The `table` struct does not:
|
||||
- enforce uniqueness of the `RowID`
|
||||
- enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix
|
||||
of another
|
||||
- optimize Gas usage conditions
|
||||
The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements.
|
||||
1. **[Table](01_table.md)**
|
||||
- [AutoUInt64Table](01_table.md#autouint64table)
|
||||
- [PrimaryKeyTable](01_table.md#primarykeytable)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package orm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
"github.com/cosmos/cosmos-sdk/store/gaskv"
|
||||
"github.com/cosmos/cosmos-sdk/store/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -31,3 +34,70 @@ func (m MockContext) KVStore(key storetypes.StoreKey) sdk.KVStore {
|
|||
}
|
||||
return m.store.GetCommitKVStore(key)
|
||||
}
|
||||
|
||||
type debuggingGasMeter struct {
|
||||
g types.GasMeter
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) GasConsumed() types.Gas {
|
||||
return d.g.GasConsumed()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) GasRemaining() types.Gas {
|
||||
return d.g.GasRemaining()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) GasConsumedToLimit() types.Gas {
|
||||
return d.g.GasConsumedToLimit()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) RefundGas(amount uint64, descriptor string) {
|
||||
d.g.RefundGas(amount, descriptor)
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) Limit() types.Gas {
|
||||
return d.g.Limit()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) ConsumeGas(amount types.Gas, descriptor string) {
|
||||
fmt.Printf("++ Consuming gas: %q :%d\n", descriptor, amount)
|
||||
d.g.ConsumeGas(amount, descriptor)
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) IsPastLimit() bool {
|
||||
return d.g.IsPastLimit()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) IsOutOfGas() bool {
|
||||
return d.g.IsOutOfGas()
|
||||
}
|
||||
|
||||
func (d debuggingGasMeter) String() string {
|
||||
return d.g.String()
|
||||
}
|
||||
|
||||
type GasCountingMockContext struct {
|
||||
GasMeter sdk.GasMeter
|
||||
}
|
||||
|
||||
func NewGasCountingMockContext() *GasCountingMockContext {
|
||||
return &GasCountingMockContext{
|
||||
GasMeter: &debuggingGasMeter{sdk.NewInfiniteGasMeter()},
|
||||
}
|
||||
}
|
||||
|
||||
func (g GasCountingMockContext) KVStore(store sdk.KVStore) sdk.KVStore {
|
||||
return gaskv.NewStore(store, g.GasMeter, types.KVGasConfig())
|
||||
}
|
||||
|
||||
func (g GasCountingMockContext) GasConsumed() types.Gas {
|
||||
return g.GasMeter.GasConsumed()
|
||||
}
|
||||
|
||||
func (g GasCountingMockContext) GasRemaining() types.Gas {
|
||||
return g.GasMeter.GasRemaining()
|
||||
}
|
||||
|
||||
func (g *GasCountingMockContext) ResetGasMeter() {
|
||||
g.GasMeter = sdk.NewInfiniteGasMeter()
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ type Iterator interface {
|
|||
// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there
|
||||
// are no more items the ErrORMIteratorDone error is returned
|
||||
// The key is the rowID.
|
||||
LoadNext(dest codec.ProtoMarshaler) (RowID, error)
|
||||
LoadNext(store sdk.KVStore, dest codec.ProtoMarshaler) (RowID, error)
|
||||
// Close releases the iterator and should be called at the end of iteration
|
||||
io.Closer
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue