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  }