github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/index.go (about) 1 package orm 2 3 import ( 4 "bytes" 5 6 "github.com/cosmos/gogoproto/proto" 7 8 errorsmod "cosmossdk.io/errors" 9 "cosmossdk.io/store/prefix" 10 "cosmossdk.io/store/types" 11 12 "github.com/cosmos/cosmos-sdk/types/query" 13 "github.com/cosmos/cosmos-sdk/x/group/errors" 14 ) 15 16 // indexer creates and modifies the second MultiKeyIndex based on the operations and changes on the primary object. 17 type indexer interface { 18 OnCreate(store types.KVStore, rowID RowID, value interface{}) error 19 OnDelete(store types.KVStore, rowID RowID, value interface{}) error 20 OnUpdate(store types.KVStore, rowID RowID, newValue, oldValue interface{}) error 21 } 22 23 var _ Index = &MultiKeyIndex{} 24 25 // MultiKeyIndex is an index where multiple entries can point to the same underlying object as opposite to a unique index 26 // where only one entry is allowed. 27 type MultiKeyIndex struct { 28 prefix byte 29 rowGetter RowGetter 30 indexer indexer 31 indexerFunc IndexerFunc 32 indexKey interface{} 33 } 34 35 // NewIndex builds a MultiKeyIndex. 36 // Only single-field indexes are supported and `indexKey` represents such a field value, 37 // which can be []byte, string or uint64. 38 func NewIndex(tb Indexable, prefix byte, indexerF IndexerFunc, indexKey interface{}) (MultiKeyIndex, error) { 39 indexer, err := NewIndexer(indexerF) 40 if err != nil { 41 return MultiKeyIndex{}, err 42 } 43 return newIndex(tb, prefix, indexer, indexer.IndexerFunc(), indexKey) 44 } 45 46 func newIndex(tb Indexable, prefix byte, indexer *Indexer, indexerF IndexerFunc, indexKey interface{}) (MultiKeyIndex, error) { 47 rowGetter := tb.RowGetter() 48 if rowGetter == nil { 49 return MultiKeyIndex{}, errors.ErrORMInvalidArgument.Wrap("rowGetter must not be nil") 50 } 51 if indexKey == nil { 52 return MultiKeyIndex{}, errors.ErrORMInvalidArgument.Wrap("indexKey must not be nil") 53 } 54 55 // Verify indexKey type is bytes, string or uint64 56 switch indexKey.(type) { 57 case []byte, string, uint64: 58 default: 59 return MultiKeyIndex{}, errors.ErrORMInvalidArgument.Wrap("indexKey must be []byte, string or uint64") 60 } 61 62 idx := MultiKeyIndex{ 63 prefix: prefix, 64 rowGetter: rowGetter, 65 indexer: indexer, 66 indexerFunc: indexerF, 67 indexKey: indexKey, 68 } 69 tb.AddAfterSetInterceptor(idx.onSet) 70 tb.AddAfterDeleteInterceptor(idx.onDelete) 71 return idx, nil 72 } 73 74 // Has checks if a key exists. Returns an error on nil key. 75 func (i MultiKeyIndex) Has(store types.KVStore, key interface{}) (bool, error) { 76 pStore := prefix.NewStore(store, []byte{i.prefix}) 77 encodedKey, err := keyPartBytes(key, false) 78 if err != nil { 79 return false, err 80 } 81 it := pStore.Iterator(PrefixRange(encodedKey)) 82 defer it.Close() 83 return it.Valid(), nil 84 } 85 86 // Get returns a result iterator for the searchKey. Parameters must not be nil. 87 func (i MultiKeyIndex) Get(store types.KVStore, searchKey interface{}) (Iterator, error) { 88 pStore := prefix.NewStore(store, []byte{i.prefix}) 89 encodedKey, err := keyPartBytes(searchKey, false) 90 if err != nil { 91 return nil, err 92 } 93 it := pStore.Iterator(PrefixRange(encodedKey)) 94 return indexIterator{store: store, it: it, rowGetter: i.rowGetter, indexKey: i.indexKey}, nil 95 } 96 97 // GetPaginated creates an iterator for the searchKey 98 // starting from pageRequest.Key if provided. 99 // The pageRequest.Key is the rowID while searchKey is a MultiKeyIndex key. 100 func (i MultiKeyIndex) GetPaginated(store types.KVStore, searchKey interface{}, pageRequest *query.PageRequest) (Iterator, error) { 101 pStore := prefix.NewStore(store, []byte{i.prefix}) 102 encodedKey, err := keyPartBytes(searchKey, false) 103 if err != nil { 104 return nil, err 105 } 106 start, end := PrefixRange(encodedKey) 107 108 if pageRequest != nil && len(pageRequest.Key) != 0 { 109 var err error 110 start, err = buildKeyFromParts([]interface{}{searchKey, pageRequest.Key}) 111 if err != nil { 112 return nil, err 113 } 114 } 115 it := pStore.Iterator(start, end) 116 return indexIterator{store: store, it: it, rowGetter: i.rowGetter, indexKey: i.indexKey}, nil 117 } 118 119 // PrefixScan returns an Iterator over a domain of keys in ascending order. End is exclusive. 120 // Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned. 121 // Iterator must be closed by caller. 122 // To iterate over entire domain, use PrefixScan(nil, nil) 123 // 124 // WARNING: The use of a PrefixScan can be very expensive in terms of Gas. Please make sure you do not expose 125 // this as an endpoint to the public without further limits. 126 // Example: 127 // 128 // it, err := idx.PrefixScan(ctx, start, end) 129 // if err !=nil { 130 // return err 131 // } 132 // const defaultLimit = 20 133 // it = LimitIterator(it, defaultLimit) 134 // 135 // CONTRACT: No writes may happen within a domain while an iterator exists over it. 136 func (i MultiKeyIndex) PrefixScan(store types.KVStore, startI, endI interface{}) (Iterator, error) { 137 start, end, err := getStartEndBz(startI, endI) 138 if err != nil { 139 return nil, err 140 } 141 142 pStore := prefix.NewStore(store, []byte{i.prefix}) 143 it := pStore.Iterator(start, end) 144 return indexIterator{store: store, it: it, rowGetter: i.rowGetter, indexKey: i.indexKey}, nil 145 } 146 147 // ReversePrefixScan returns an Iterator over a domain of keys in descending order. End is exclusive. 148 // Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned. 149 // Iterator must be closed by caller. 150 // To iterate over entire domain, use PrefixScan(nil, nil) 151 // 152 // WARNING: The use of a ReversePrefixScan can be very expensive in terms of Gas. Please make sure you do not expose 153 // this as an endpoint to the public without further limits. See `LimitIterator` 154 // 155 // CONTRACT: No writes may happen within a domain while an iterator exists over it. 156 func (i MultiKeyIndex) ReversePrefixScan(store types.KVStore, startI, endI interface{}) (Iterator, error) { 157 start, end, err := getStartEndBz(startI, endI) 158 if err != nil { 159 return nil, err 160 } 161 162 pStore := prefix.NewStore(store, []byte{i.prefix}) 163 it := pStore.ReverseIterator(start, end) 164 return indexIterator{store: store, it: it, rowGetter: i.rowGetter, indexKey: i.indexKey}, nil 165 } 166 167 // getStartEndBz gets the start and end bytes to be passed into the SDK store 168 // iterator. 169 func getStartEndBz(startI, endI interface{}) ([]byte, []byte, error) { 170 start, err := getPrefixScanKeyBytes(startI) 171 if err != nil { 172 return nil, nil, err 173 } 174 end, err := getPrefixScanKeyBytes(endI) 175 if err != nil { 176 return nil, nil, err 177 } 178 179 if start != nil && end != nil && bytes.Compare(start, end) >= 0 { 180 return nil, nil, errorsmod.Wrap(errors.ErrORMInvalidArgument, "start must be less than end") 181 } 182 183 return start, end, nil 184 } 185 186 func getPrefixScanKeyBytes(keyI interface{}) ([]byte, error) { 187 var ( 188 key []byte 189 err error 190 ) 191 // nil value are accepted in the context of PrefixScans 192 if keyI == nil { 193 return nil, nil 194 } 195 key, err = keyPartBytes(keyI, false) 196 if err != nil { 197 return nil, err 198 } 199 return key, nil 200 } 201 202 func (i MultiKeyIndex) onSet(store types.KVStore, rowID RowID, newValue, oldValue proto.Message) error { 203 pStore := prefix.NewStore(store, []byte{i.prefix}) 204 if oldValue == nil { 205 return i.indexer.OnCreate(pStore, rowID, newValue) 206 } 207 return i.indexer.OnUpdate(pStore, rowID, newValue, oldValue) 208 } 209 210 func (i MultiKeyIndex) onDelete(store types.KVStore, rowID RowID, oldValue proto.Message) error { 211 pStore := prefix.NewStore(store, []byte{i.prefix}) 212 return i.indexer.OnDelete(pStore, rowID, oldValue) 213 } 214 215 type UniqueIndex struct { 216 MultiKeyIndex 217 } 218 219 // NewUniqueIndex create a new Index object where duplicate keys are prohibited. 220 func NewUniqueIndex(tb Indexable, prefix byte, uniqueIndexerFunc UniqueIndexerFunc, indexKey interface{}) (UniqueIndex, error) { 221 uniqueIndexer, err := NewUniqueIndexer(uniqueIndexerFunc) 222 if err != nil { 223 return UniqueIndex{}, err 224 } 225 multiKeyIndex, err := newIndex(tb, prefix, uniqueIndexer, uniqueIndexer.IndexerFunc(), indexKey) 226 if err != nil { 227 return UniqueIndex{}, err 228 } 229 return UniqueIndex{ 230 MultiKeyIndex: multiKeyIndex, 231 }, nil 232 } 233 234 // indexIterator uses rowGetter to lazy load new model values on request. 235 type indexIterator struct { 236 store types.KVStore 237 rowGetter RowGetter 238 it types.Iterator 239 indexKey interface{} 240 } 241 242 // LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there 243 // are no more items the errors.ErrORMIteratorDone error is returned 244 // The key is the rowID and not any MultiKeyIndex key. 245 func (i indexIterator) LoadNext(dest proto.Message) (RowID, error) { 246 if !i.it.Valid() { 247 return nil, errors.ErrORMIteratorDone 248 } 249 indexPrefixKey := i.it.Key() 250 rowID, err := stripRowID(indexPrefixKey, i.indexKey) 251 if err != nil { 252 return nil, err 253 } 254 i.it.Next() 255 return rowID, i.rowGetter(i.store, rowID, dest) 256 } 257 258 // Close releases the iterator and should be called at the end of iteration 259 func (i indexIterator) Close() error { 260 return i.it.Close() 261 } 262 263 // PrefixRange turns a prefix into a (start, end) range. The start is the given prefix value and 264 // the end is calculated by adding 1 bit to the start value. Nil is not allowed as prefix. 265 // 266 // Example: []byte{1, 3, 4} becomes []byte{1, 3, 5} 267 // []byte{15, 42, 255, 255} becomes []byte{15, 43, 0, 0} 268 // 269 // In case of an overflow the end is set to nil. 270 // 271 // Example: []byte{255, 255, 255, 255} becomes nil 272 func PrefixRange(prefix []byte) ([]byte, []byte) { 273 if prefix == nil { 274 panic("nil key not allowed") 275 } 276 // special case: no prefix is whole range 277 if len(prefix) == 0 { 278 return nil, nil 279 } 280 281 // copy the prefix and update last byte 282 end := make([]byte, len(prefix)) 283 copy(end, prefix) 284 l := len(end) - 1 285 end[l]++ 286 287 // wait, what if that overflowed?.... 288 for end[l] == 0 && l > 0 { 289 l-- 290 end[l]++ 291 } 292 293 // okay, funny guy, you gave us FFF, no end to this range... 294 if l == 0 && end[0] == 0 { 295 end = nil 296 } 297 return prefix, end 298 }