-
Notifications
You must be signed in to change notification settings - Fork 117
/
store.go
192 lines (161 loc) · 5.3 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package utils
import (
"bytes"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/tendermint/tendermint/libs/log"
)
const defaultDelimiter = "_"
// Key represents a store key to interact with the KVStore
type Key interface {
// AsKey returns the byte representation of the key. If given, uses a delimiter string to separate prefixes
AsKey(delimiter ...string) []byte
Prepend(prefix Key) Key
Append(key Key) Key
Equals(key Key) bool
}
// StringKey extends the Key interface for simplified appending and prepending
type StringKey interface {
Key
AppendStr(key string, stringTransformations ...func(string) string) StringKey
PrependStr(key string, stringTransformations ...func(string) string) StringKey
}
// KVStore is a wrapper around the cosmos-sdk KVStore to provide more safety regarding key management and better ease-of-use
type KVStore struct {
sdk.KVStore
cdc codec.BinaryCodec
}
// NewNormalizedStore returns a new KVStore
func NewNormalizedStore(store sdk.KVStore, cdc codec.BinaryCodec) KVStore {
return KVStore{
KVStore: store,
cdc: cdc,
}
}
// Set marshals the value and stores it under the given key
func (store KVStore) Set(key Key, value codec.ProtoMarshaler) {
store.KVStore.Set(key.AsKey(), store.cdc.MustMarshalLengthPrefixed(value))
}
// SetRaw stores the value under the given key
func (store KVStore) SetRaw(key Key, value []byte) {
store.KVStore.Set(key.AsKey(), value)
}
// Get unmarshals the raw bytes stored under the given key into the value object. Returns true if the key exists.
func (store KVStore) Get(key Key, value codec.ProtoMarshaler) bool {
bz := store.KVStore.Get(key.AsKey())
if bz == nil {
return false
}
store.cdc.MustUnmarshalLengthPrefixed(bz, value)
return true
}
// GetRaw returns the raw bytes stored under the given key. Returns nil with key does not exist.
func (store KVStore) GetRaw(key Key) []byte {
return store.KVStore.Get(key.AsKey())
}
// Has returns true if the key exists.
func (store KVStore) Has(key Key) bool {
return store.KVStore.Has(key.AsKey())
}
// Delete deletes the value stored under the given key, if it exists
func (store KVStore) Delete(key Key) {
store.KVStore.Delete(key.AsKey())
}
// Iterator returns an Iterator that can handle a structured Key
func (store KVStore) Iterator(prefix Key) Iterator {
iter := sdk.KVStorePrefixIterator(store.KVStore, prefix.AsKey())
return iterator{Iterator: iter, cdc: store.cdc}
}
// Iterator is an easier and safer to use sdk.Iterator extension
type Iterator interface {
sdk.Iterator
UnmarshalValue(marshaler codec.ProtoMarshaler)
GetKey() Key
}
type iterator struct {
sdk.Iterator
cdc codec.BinaryCodec
}
// UnmarshalValue returns the value marshalled into the given type
func (i iterator) UnmarshalValue(value codec.ProtoMarshaler) {
i.cdc.MustUnmarshalLengthPrefixed(i.Value(), value)
}
// GetKey returns the key of the current iterator value
func (i iterator) GetKey() Key {
return KeyFromBz(i.Key())
}
type key struct {
prefix Key
key []byte
}
// KeyFromStr applies the optional string transformations to the given key in sequence and returns a structured key
func KeyFromStr(k string, stringTransformations ...func(string) string) StringKey {
for _, transform := range stringTransformations {
k = transform(k)
}
return key{
prefix: nil,
key: []byte(k),
}
}
// LowerCaseKey returns a key with the input converted to lower case
func LowerCaseKey(k string) StringKey {
return KeyFromStr(k, strings.ToLower)
}
// KeyFromBz returns a structured key
func KeyFromBz(k []byte) StringKey {
return key{
prefix: nil,
key: k,
}
}
// AsKey returns the byte representation of the key. If given, uses a delimiter string to separate prefixes (default is "_")
func (k key) AsKey(delimiter ...string) []byte {
if len(delimiter) == 0 {
return k.asKey(defaultDelimiter)
}
return k.asKey(delimiter[0])
}
func (k key) asKey(delimiter string) []byte {
if k.prefix != nil {
prefix := k.prefix.AsKey(delimiter)
delim := []byte(delimiter)
compKey := make([]byte, 0, len(prefix)+len(delim)+len(k.key))
return append(append(append(compKey, prefix...), delim...), k.key...)
}
return k.key
}
// Prepend prepends the given prefix to the key
func (k key) Prepend(prefix Key) Key {
if k.prefix != nil {
k.prefix = k.prefix.Prepend(prefix)
} else {
k.prefix = prefix
}
return k
}
// PrependStr prepends the given string to this key
func (k key) PrependStr(prefix string, stringTransformations ...func(string) string) StringKey {
return k.Prepend(KeyFromStr(prefix, stringTransformations...)).(StringKey)
}
// Append appends the given key to this key
func (k key) Append(key Key) Key {
return key.Prepend(k)
}
// AppendStr appends the given string to this key
func (k key) AppendStr(key string, stringTransformations ...func(string) string) StringKey {
return KeyFromStr(key, stringTransformations...).Prepend(k).(StringKey)
}
// Equals compares two keys for equality
func (k key) Equals(other Key) bool {
return bytes.Equal(k.AsKey(), other.AsKey())
}
// CloseLogError closes the given iterator and logs if an error is returned
func CloseLogError(iter sdk.Iterator, logger log.Logger) {
err := iter.Close()
if err != nil {
logger.Error(sdkerrors.Wrap(err, "failed to close kv store iterator").Error())
}
}