github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/indexer.go (about) 1 package orm 2 3 import ( 4 errorsmod "cosmossdk.io/errors" 5 storetypes "cosmossdk.io/store/types" 6 7 "github.com/cosmos/cosmos-sdk/x/group/errors" 8 ) 9 10 // IndexerFunc creates one or multiple index keys for the source object. 11 type IndexerFunc func(value interface{}) ([]interface{}, error) 12 13 // IndexerFunc creates exactly one index key for the source object. 14 type UniqueIndexerFunc func(value interface{}) (interface{}, error) 15 16 // Indexer manages the persistence of an Index based on searchable keys and operations. 17 type Indexer struct { 18 indexerFunc IndexerFunc 19 addFunc func(store storetypes.KVStore, secondaryIndexKey interface{}, rowID RowID) error 20 } 21 22 // NewIndexer returns an indexer that supports multiple reference keys for an entity. 23 func NewIndexer(indexerFunc IndexerFunc) (*Indexer, error) { 24 if indexerFunc == nil { 25 return nil, errors.ErrORMInvalidArgument.Wrap("Indexer func must not be nil") 26 } 27 return &Indexer{ 28 indexerFunc: pruneEmptyKeys(indexerFunc), 29 addFunc: multiKeyAddFunc, 30 }, nil 31 } 32 33 // NewUniqueIndexer returns an indexer that requires exactly one reference keys for an entity. 34 func NewUniqueIndexer(f UniqueIndexerFunc) (*Indexer, error) { 35 if f == nil { 36 return nil, errors.ErrORMInvalidArgument.Wrap("Indexer func must not be nil") 37 } 38 adaptor := func(indexerFunc UniqueIndexerFunc) IndexerFunc { 39 return func(v interface{}) ([]interface{}, error) { 40 k, err := indexerFunc(v) 41 return []interface{}{k}, err 42 } 43 } 44 idx, err := NewIndexer(adaptor(f)) 45 if err != nil { 46 return nil, err 47 } 48 idx.addFunc = uniqueKeysAddFunc 49 return idx, nil 50 } 51 52 // IndexerFunc returns the indexer IndexerFunc, 53 // ensuring it has been prune from empty keys. 54 func (i Indexer) IndexerFunc() IndexerFunc { 55 return i.indexerFunc 56 } 57 58 // OnCreate persists the secondary index entries for the new object. 59 func (i Indexer) OnCreate(store storetypes.KVStore, rowID RowID, value interface{}) error { 60 secondaryIndexKeys, err := i.indexerFunc(value) 61 if err != nil { 62 return err 63 } 64 65 for _, secondaryIndexKey := range secondaryIndexKeys { 66 if err := i.addFunc(store, secondaryIndexKey, []byte(rowID)); err != nil { 67 return err 68 } 69 } 70 return nil 71 } 72 73 // OnDelete removes the secondary index entries for the deleted object. 74 func (i Indexer) OnDelete(store storetypes.KVStore, rowID RowID, value interface{}) error { 75 secondaryIndexKeys, err := i.indexerFunc(value) 76 if err != nil { 77 return err 78 } 79 80 for _, secondaryIndexKey := range secondaryIndexKeys { 81 indexKey, err := buildKeyFromParts([]interface{}{secondaryIndexKey, []byte(rowID)}) 82 if err != nil { 83 return err 84 } 85 store.Delete(indexKey) 86 } 87 return nil 88 } 89 90 // OnUpdate rebuilds the secondary index entries for the updated object. 91 func (i Indexer) OnUpdate(store storetypes.KVStore, rowID RowID, newValue, oldValue interface{}) error { 92 oldSecIdxKeys, err := i.indexerFunc(oldValue) 93 if err != nil { 94 return err 95 } 96 newSecIdxKeys, err := i.indexerFunc(newValue) 97 if err != nil { 98 return err 99 } 100 oldKeys, err := difference(oldSecIdxKeys, newSecIdxKeys) 101 if err != nil { 102 return err 103 } 104 for _, oldIdxKey := range oldKeys { 105 indexKey, err := buildKeyFromParts([]interface{}{oldIdxKey, []byte(rowID)}) 106 if err != nil { 107 return err 108 } 109 store.Delete(indexKey) 110 } 111 newKeys, err := difference(newSecIdxKeys, oldSecIdxKeys) 112 if err != nil { 113 return err 114 } 115 for _, newIdxKey := range newKeys { 116 if err := i.addFunc(store, newIdxKey, rowID); err != nil { 117 return err 118 } 119 } 120 return nil 121 } 122 123 // uniqueKeysAddFunc enforces keys to be unique 124 func uniqueKeysAddFunc(store storetypes.KVStore, secondaryIndexKey interface{}, rowID RowID) error { 125 secondaryIndexKeyBytes, err := keyPartBytes(secondaryIndexKey, false) 126 if err != nil { 127 return err 128 } 129 if len(secondaryIndexKeyBytes) == 0 { 130 return errorsmod.Wrap(errors.ErrORMInvalidArgument, "empty index key") 131 } 132 133 if err := checkUniqueIndexKey(store, secondaryIndexKeyBytes); err != nil { 134 return err 135 } 136 137 indexKey, err := buildKeyFromParts([]interface{}{secondaryIndexKey, []byte(rowID)}) 138 if err != nil { 139 return err 140 } 141 142 store.Set(indexKey, []byte{}) 143 return nil 144 } 145 146 // checkUniqueIndexKey checks that the given secondary index key is unique 147 func checkUniqueIndexKey(store storetypes.KVStore, secondaryIndexKeyBytes []byte) error { 148 it := store.Iterator(PrefixRange(secondaryIndexKeyBytes)) 149 defer it.Close() 150 if it.Valid() { 151 return errors.ErrORMUniqueConstraint 152 } 153 return nil 154 } 155 156 // multiKeyAddFunc allows multiple entries for a key 157 func multiKeyAddFunc(store storetypes.KVStore, secondaryIndexKey interface{}, rowID RowID) error { 158 secondaryIndexKeyBytes, err := keyPartBytes(secondaryIndexKey, false) 159 if err != nil { 160 return err 161 } 162 if len(secondaryIndexKeyBytes) == 0 { 163 return errorsmod.Wrap(errors.ErrORMInvalidArgument, "empty index key") 164 } 165 166 encodedKey, err := buildKeyFromParts([]interface{}{secondaryIndexKey, []byte(rowID)}) 167 if err != nil { 168 return err 169 } 170 if len(encodedKey) == 0 { 171 return errorsmod.Wrap(errors.ErrORMInvalidArgument, "empty index key") 172 } 173 174 store.Set(encodedKey, []byte{}) 175 return nil 176 } 177 178 // difference returns the list of elements that are in a but not in b. 179 func difference(a, b []interface{}) ([]interface{}, error) { 180 set := make(map[interface{}]struct{}, len(b)) 181 for _, v := range b { 182 bt, err := keyPartBytes(v, true) 183 if err != nil { 184 return nil, err 185 } 186 set[string(bt)] = struct{}{} 187 } 188 var result []interface{} 189 for _, v := range a { 190 bt, err := keyPartBytes(v, true) 191 if err != nil { 192 return nil, err 193 } 194 if _, ok := set[string(bt)]; !ok { 195 result = append(result, v) 196 } 197 } 198 return result, nil 199 } 200 201 // pruneEmptyKeys drops any empty key from IndexerFunc f returned 202 func pruneEmptyKeys(f IndexerFunc) IndexerFunc { 203 return func(v interface{}) ([]interface{}, error) { 204 keys, err := f(v) 205 if err != nil || keys == nil { 206 return keys, err 207 } 208 r := make([]interface{}, 0, len(keys)) 209 for i := range keys { 210 key, err := keyPartBytes(keys[i], true) 211 if err != nil { 212 return nil, err 213 } 214 if len(key) != 0 { 215 r = append(r, keys[i]) 216 } 217 } 218 return r, nil 219 } 220 }