Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(collections): add optional key and value naming methods #20538

Merged
merged 12 commits into from
Sep 24, 2024
1 change: 1 addition & 0 deletions collections/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#18933](https://github.com/cosmos/cosmos-sdk/pull/18933) Add LookupMap implementation. It is basic wrapping of the standard Map methods but is not iterable.
* [#17656](https://github.com/cosmos/cosmos-sdk/pull/17656) Introduces `Vec`, a collection type that allows to represent a growable array on top of a KVStore.
* [#19861](https://github.com/cosmos/cosmos-sdk/pull/19861) Add `NewJSONValueCodec` value codec as an alternative for `codec.CollValue` from the SDK for non protobuf types.
* [#20538](https://github.com/cosmos/cosmos-sdk/pull/20538) Add `Nameable` and `Named` variations to `KeyCodec` and `ValueCodec` to allow for better indexing of collections types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be marked as API breaking

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it API breaking?


## [v0.4.0](https://github.com/cosmos/cosmos-sdk/releases/tag/collections%2Fv0.4.0)

Expand Down
2 changes: 1 addition & 1 deletion collections/codec/alternative_value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type altValue struct {
func TestAltValueCodec(t *testing.T) {
// we assume we want to migrate the value from json(altValue) to just be
// the raw value uint64.
canonical := codec.KeyToValueCodec(codec.NewUint64Key[uint64]())
canonical := codec.KeyToValueCodec(codec.KeyCodec[uint64](codec.NewUint64Key[uint64]()))
aaronc marked this conversation as resolved.
Show resolved Hide resolved
alternative := func(v []byte) (uint64, error) {
var alt altValue
err := json.Unmarshal(v, &alt)
Expand Down
15 changes: 13 additions & 2 deletions collections/codec/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"strconv"
)

func NewBoolKey[T ~bool]() KeyCodec[T] { return boolKey[T]{} }
func NewBoolKey[T ~bool]() NameableKeyCodec[T] { return boolKey[T]{} }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined interfaces NameableKeyCodec and NamedKeyCodec.

Please ensure that NameableKeyCodec and NamedKeyCodec are defined and correctly imported. This issue affects the definition of NewBoolKey and the method WithName.

Also applies to: 70-70

Tools
golangci-lint

9-9: undefined: NameableKeyCodec (typecheck)


type boolKey[T ~bool] struct{}
type boolKey[T ~bool] struct {
name string
}

func (b boolKey[T]) Encode(buffer []byte, key T) (int, error) {
if key {
Expand Down Expand Up @@ -64,3 +66,12 @@ func (b boolKey[T]) DecodeNonTerminal(buffer []byte) (int, T, error) {
func (b boolKey[T]) SizeNonTerminal(key T) int {
return b.Size(key)
}

func (b boolKey[T]) WithName(name string) NamedKeyCodec[T] {
b.name = name
return b
}

func (b boolKey[T]) Name() string {
return b.name
}
15 changes: 13 additions & 2 deletions collections/codec/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
// using the BytesKey KeyCodec.
const MaxBytesKeyNonTerminalSize = math.MaxUint8

func NewBytesKey[T ~[]byte]() KeyCodec[T] { return bytesKey[T]{} }
func NewBytesKey[T ~[]byte]() NameableKeyCodec[T] { return bytesKey[T]{} }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NameableKeyCodec.

The type NameableKeyCodec is not defined in the provided context. Ensure that it is correctly defined and imported to avoid compilation errors.

Tools
golangci-lint

13-13: undefined: NameableKeyCodec (typecheck)


type bytesKey[T ~[]byte] struct{}
type bytesKey[T ~[]byte] struct {
name string
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper encapsulation of the name field in bytesKey.

Consider making the name field private to encapsulate the internal state of bytesKey unless there is a specific reason for it to be public.

- name string
+ name string

Committable suggestion was skipped due to low confidence.


func (b bytesKey[T]) Encode(buffer []byte, key T) (int, error) {
return copy(buffer, key), nil
Expand Down Expand Up @@ -77,3 +79,12 @@ func (bytesKey[T]) DecodeNonTerminal(buffer []byte) (int, T, error) {
func (bytesKey[T]) SizeNonTerminal(key T) int {
return len(key) + 1
}

func (b bytesKey[T]) WithName(name string) NamedKeyCodec[T] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NamedKeyCodec.

The type NamedKeyCodec is not defined. Ensure that it is correctly defined and imported to avoid compilation errors.

Tools
golangci-lint

83-83: undefined: NamedKeyCodec (typecheck)

b.name = name
return b
}

func (b bytesKey[T]) Name() string {
return b.name
}
16 changes: 14 additions & 2 deletions collections/codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,14 @@ type UntypedValueCodec struct {
}

// KeyToValueCodec converts a KeyCodec into a ValueCodec.
func KeyToValueCodec[K any](keyCodec KeyCodec[K]) ValueCodec[K] { return keyToValueCodec[K]{keyCodec} }
func KeyToValueCodec[K any](keyCodec KeyCodec[K]) NameableValueCodec[K] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined types NameableValueCodec and NamedValueCodec.

The types NameableValueCodec and NamedValueCodec are not defined in the provided context. Ensure that they are correctly defined and imported to avoid compilation errors.

Also applies to: 174-174

Tools
golangci-lint

128-128: undefined: NameableValueCodec (typecheck)

return keyToValueCodec[K]{kc: keyCodec}
}

// keyToValueCodec is a ValueCodec that wraps a KeyCodec to make it behave like a ValueCodec.
type keyToValueCodec[K any] struct {
kc KeyCodec[K]
name string
kc KeyCodec[K]
}

func (k keyToValueCodec[K]) EncodeJSON(value K) ([]byte, error) {
Expand Down Expand Up @@ -167,3 +170,12 @@ func (k keyToValueCodec[K]) Stringify(value K) string {
func (k keyToValueCodec[K]) ValueType() string {
return k.kc.KeyType()
}

func (k keyToValueCodec[K]) WithName(name string) NamedValueCodec[K] {
k.name = name
return k
}

func (k keyToValueCodec[K]) Name() string {
return k.name
}
2 changes: 1 addition & 1 deletion collections/codec/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestUntypedValueCodec(t *testing.T) {
vc := NewUntypedValueCodec(KeyToValueCodec(NewStringKeyCodec[string]()))
vc := NewUntypedValueCodec(ValueCodec[string](KeyToValueCodec(KeyCodec[string](NewStringKeyCodec[string]()))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined function NewUntypedValueCodec.

Please ensure that NewUntypedValueCodec is defined and correctly imported.

Tools
golangci-lint

10-10: undefined: NewUntypedValueCodec (typecheck)


t.Run("encode/decode", func(t *testing.T) {
_, err := vc.Encode(0)
Expand Down
30 changes: 26 additions & 4 deletions collections/codec/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"strconv"
)

func NewInt64Key[T ~int64]() KeyCodec[T] { return int64Key[T]{} }
func NewInt64Key[T ~int64]() NameableKeyCodec[T] { return int64Key[T]{} }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NameableKeyCodec.

The type NameableKeyCodec is not defined in the provided context. Ensure that it is correctly defined and imported to avoid compilation errors.

Also applies to: 78-78

Tools
golangci-lint

10-10: undefined: NameableKeyCodec (typecheck)


type int64Key[T ~int64] struct{}
type int64Key[T ~int64] struct {
name string
}
aaronc marked this conversation as resolved.
Show resolved Hide resolved

func (i int64Key[T]) Encode(buffer []byte, key T) (int, error) {
binary.BigEndian.PutUint64(buffer, (uint64)(key))
Expand Down Expand Up @@ -64,11 +66,22 @@ func (i int64Key[T]) SizeNonTerminal(_ T) int {
return 8
}

func NewInt32Key[T ~int32]() KeyCodec[T] {
func (i int64Key[T]) WithName(name string) NamedKeyCodec[T] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NamedKeyCodec.

The type NamedKeyCodec is not defined. Ensure that it is correctly defined and imported to avoid compilation errors.

Also applies to: 138-138

Tools
golangci-lint

69-69: undefined: NamedKeyCodec (typecheck)

i.name = name
return i
}

func (i int64Key[T]) Name() string {
return i.name
}

func NewInt32Key[T ~int32]() NameableKeyCodec[T] {
return int32Key[T]{}
}

type int32Key[T ~int32] struct{}
type int32Key[T ~int32] struct {
name string
}

func (i int32Key[T]) Encode(buffer []byte, key T) (int, error) {
binary.BigEndian.PutUint32(buffer, (uint32)(key))
Expand Down Expand Up @@ -121,3 +134,12 @@ func (i int32Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) {
func (i int32Key[T]) SizeNonTerminal(_ T) int {
return 4
}

func (i int32Key[T]) WithName(name string) NamedKeyCodec[T] {
i.name = name
return i
}

func (i int32Key[T]) Name() string {
return i.name
}
35 changes: 35 additions & 0 deletions collections/codec/naming.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package codec

// NameableKeyCodec is a KeyCodec that can be named.
type NameableKeyCodec[T any] interface {
KeyCodec[T]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined interface KeyCodec.

Please ensure that KeyCodec is defined and correctly imported. This issue affects both NameableKeyCodec and NamedKeyCodec.

Also applies to: 13-13

Tools
golangci-lint

5-5: undefined: KeyCodec (typecheck)


// WithName returns the KeyCodec with the provided name.
WithName(name string) NamedKeyCodec[T]
}

// NamedKeyCodec is a KeyCodec that has a name.
type NamedKeyCodec[T any] interface {
KeyCodec[T]

// Name returns the name of key in the schema if one is defined or the empty string.
// Multipart keys should separate names with commas, i.e. "name1,name2".
Name() string
}

// NameableValueCodec is a ValueCodec that can be named.
type NameableValueCodec[T any] interface {
ValueCodec[T]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined interface ValueCodec.

Please ensure that ValueCodec is defined and correctly imported. This issue affects both NameableValueCodec and NamedValueCodec.

Also applies to: 30-30

Tools
golangci-lint

22-22: undefined: ValueCodec (typecheck)


// WithName returns the ValueCodec with the provided name.
WithName(name string) NamedValueCodec[T]
}

// NamedValueCodec is a ValueCodec that has a name.
type NamedValueCodec[T any] interface {
ValueCodec[T]

// Name returns the name of key in the schema if one is defined or the empty string.
// Multipart keys should separate names with commas, i.e. "name1,name2".
Name() string
}
15 changes: 13 additions & 2 deletions collections/codec/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import (
"fmt"
)

func NewStringKeyCodec[T ~string]() KeyCodec[T] { return stringKey[T]{} }
func NewStringKeyCodec[T ~string]() NameableKeyCodec[T] { return stringKey[T]{} }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined interfaces NameableKeyCodec and NamedKeyCodec.

Please ensure that NameableKeyCodec and NamedKeyCodec are defined and correctly imported. This issue affects the definition of NewStringKeyCodec and the method WithName.

Also applies to: 72-72

Tools
golangci-lint

9-9: undefined: NameableKeyCodec (typecheck)


const (
// StringDelimiter defines the delimiter of a string key when used in non-terminal encodings.
StringDelimiter uint8 = 0x0
)

type stringKey[T ~string] struct{}
type stringKey[T ~string] struct {
name string
}

func (stringKey[T]) Encode(buffer []byte, key T) (int, error) {
return copy(buffer, key), nil
Expand Down Expand Up @@ -66,3 +68,12 @@ func (stringKey[T]) Stringify(key T) string {
func (stringKey[T]) KeyType() string {
return "string"
}

func (s stringKey[T]) WithName(name string) NamedKeyCodec[T] {
s.name = name
return s
}

func (s stringKey[T]) Name() string {
return s.name
}
45 changes: 39 additions & 6 deletions collections/codec/uint.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import (
"strconv"
)

func NewUint64Key[T ~uint64]() KeyCodec[T] { return uint64Key[T]{} }
func NewUint64Key[T ~uint64]() NameableKeyCodec[T] { return uint64Key[T]{} }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NameableKeyCodec.

The type NameableKeyCodec is not defined in the provided context. Ensure that it is correctly defined and imported to avoid compilation errors.

Also applies to: 69-69, 120-120

Tools
golangci-lint

10-10: undefined: NameableKeyCodec (typecheck)


type uint64Key[T ~uint64] struct{}
type uint64Key[T ~uint64] struct {
name string
}
aaronc marked this conversation as resolved.
Show resolved Hide resolved

func (uint64Key[T]) Encode(buffer []byte, key T) (int, error) {
binary.BigEndian.PutUint64(buffer, (uint64)(key))
Expand Down Expand Up @@ -55,9 +57,20 @@ func (uint64Key[T]) KeyType() string {
return "uint64"
}

func NewUint32Key[T ~uint32]() KeyCodec[T] { return uint32Key[T]{} }
func (u uint64Key[T]) WithName(name string) NamedKeyCodec[T] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolve the undefined type NamedKeyCodec.

The type NamedKeyCodec is not defined. Ensure that it is correctly defined and imported to avoid compilation errors.

Also applies to: 111-111, 162-162

Tools
golangci-lint

60-60: undefined: NamedKeyCodec (typecheck)

u.name = name
return u
}

func (u uint64Key[T]) Name() string {
return u.name
}

func NewUint32Key[T ~uint32]() NameableKeyCodec[T] { return uint32Key[T]{} }

type uint32Key[T ~uint32] struct{}
type uint32Key[T ~uint32] struct {
name string
}

func (uint32Key[T]) Encode(buffer []byte, key T) (int, error) {
binary.BigEndian.PutUint32(buffer, (uint32)(key))
Expand Down Expand Up @@ -95,9 +108,20 @@ func (u uint32Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { return

func (uint32Key[T]) SizeNonTerminal(_ T) int { return 4 }

func NewUint16Key[T ~uint16]() KeyCodec[T] { return uint16Key[T]{} }
func (u uint32Key[T]) WithName(name string) NamedKeyCodec[T] {
u.name = name
return u
}

type uint16Key[T ~uint16] struct{}
func (u uint32Key[T]) Name() string {
return u.name
}

func NewUint16Key[T ~uint16]() NameableKeyCodec[T] { return uint16Key[T]{} }

type uint16Key[T ~uint16] struct {
name string
}

func (uint16Key[T]) Encode(buffer []byte, key T) (int, error) {
binary.BigEndian.PutUint16(buffer, (uint16)(key))
Expand Down Expand Up @@ -135,6 +159,15 @@ func (u uint16Key[T]) DecodeNonTerminal(buffer []byte) (int, T, error) { return

func (u uint16Key[T]) SizeNonTerminal(key T) int { return u.Size(key) }

func (u uint16Key[T]) WithName(name string) NamedKeyCodec[T] {
u.name = name
return u
}

func (u uint16Key[T]) Name() string {
return u.name
}

func uintEncodeJSON(value uint64) ([]byte, error) {
str := `"` + strconv.FormatUint(value, 10) + `"`
return []byte(str), nil
Expand Down
16 changes: 8 additions & 8 deletions collections/collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ var (

var (
// BoolValue implements a ValueCodec for bool.
BoolValue = codec.KeyToValueCodec(BoolKey)
BoolValue = codec.KeyToValueCodec(codec.KeyCodec[bool](BoolKey))
// Uint16Value implements a ValueCodec for uint16.
Uint16Value = codec.KeyToValueCodec(Uint16Key)
Uint16Value = codec.KeyToValueCodec(codec.KeyCodec[uint16](Uint16Key))
// Uint32Value implements a ValueCodec for uint32.
Uint32Value = codec.KeyToValueCodec(Uint32Key)
Uint32Value = codec.KeyToValueCodec(codec.KeyCodec[uint32](Uint32Key))
// Uint64Value implements a ValueCodec for uint64.
Uint64Value = codec.KeyToValueCodec(Uint64Key)
Uint64Value = codec.KeyToValueCodec(codec.KeyCodec[uint64](Uint64Key))
// Int32Value implements a ValueCodec for int32.
Int32Value = codec.KeyToValueCodec(Int32Key)
Int32Value = codec.KeyToValueCodec(codec.KeyCodec[int32](Int32Key))
// Int64Value implements a ValueCodec for int64.
Int64Value = codec.KeyToValueCodec(Int64Key)
Int64Value = codec.KeyToValueCodec(codec.KeyCodec[int64](Int64Key))
// StringValue implements a ValueCodec for string.
StringValue = codec.KeyToValueCodec(StringKey)
StringValue = codec.KeyToValueCodec(codec.KeyCodec[string](StringKey))
// BytesValue implements a ValueCodec for bytes.
BytesValue = codec.KeyToValueCodec(BytesKey)
BytesValue = codec.KeyToValueCodec(codec.KeyCodec[[]byte](BytesKey))
aaronc marked this conversation as resolved.
Show resolved Hide resolved
)

// Collection is the interface that all collections implement. It will eventually
Expand Down
30 changes: 30 additions & 0 deletions collections/naming_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package collections

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestNaming(t *testing.T) {
require.Equal(t, "u16", Uint16Key.WithName("u16").Name())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undefined variables used in tests.

Please ensure that all keys and values (Uint16Key, Uint32Key, etc.) and functions (NamedPairKeyCodec, NamedTripleKeyCodec) are defined and correctly imported. This issue affects multiple lines in the test cases.

Also applies to: 11-11, 12-12, 13-13, 14-14, 15-15, 16-16, 17-17, 19-19, 20-20, 21-21, 22-22, 23-23, 24-24, 25-25, 26-26, 28-28, 29-29

Tools
golangci-lint

10-10: undefined: Uint16Key (typecheck)

require.Equal(t, "u32", Uint32Key.WithName("u32").Name())
require.Equal(t, "u64", Uint64Key.WithName("u64").Name())
require.Equal(t, "i32", Int32Key.WithName("i32").Name())
require.Equal(t, "i64", Int64Key.WithName("i64").Name())
require.Equal(t, "str", StringKey.WithName("str").Name())
require.Equal(t, "bytes", BytesKey.WithName("bytes").Name())
require.Equal(t, "bool", BoolKey.WithName("bool").Name())

require.Equal(t, "vu16", Uint16Value.WithName("vu16").Name())
require.Equal(t, "vu32", Uint32Value.WithName("vu32").Name())
require.Equal(t, "vu64", Uint64Value.WithName("vu64").Name())
require.Equal(t, "vi32", Int32Value.WithName("vi32").Name())
require.Equal(t, "vi64", Int64Value.WithName("vi64").Name())
require.Equal(t, "vstr", StringValue.WithName("vstr").Name())
require.Equal(t, "vbytes", BytesValue.WithName("vbytes").Name())
require.Equal(t, "vbool", BoolValue.WithName("vbool").Name())

require.Equal(t, "abc,def", NamedPairKeyCodec[bool, string]("abc", BoolKey, "def", StringKey).Name())
require.Equal(t, "abc,def,ghi", NamedTripleKeyCodec[bool, string, int32]("abc", BoolKey, "def", StringKey, "ghi", Int32Key).Name())
}
Loading
Loading