github.com/cosmos/cosmos-sdk@v0.50.10/x/group/internal/orm/table.go (about)

     1  package orm
     2  
     3  import (
     4  	"bytes"
     5  	"reflect"
     6  
     7  	"github.com/cosmos/gogoproto/proto"
     8  
     9  	errorsmod "cosmossdk.io/errors"
    10  	"cosmossdk.io/store/prefix"
    11  	"cosmossdk.io/store/types"
    12  
    13  	"github.com/cosmos/cosmos-sdk/codec"
    14  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    15  	"github.com/cosmos/cosmos-sdk/x/group/errors"
    16  )
    17  
    18  var (
    19  	_ Indexable       = &table{}
    20  	_ TableExportable = &table{}
    21  )
    22  
    23  // table is the high level object to storage mapper functionality. Persistent
    24  // entities are stored by an unique identifier called `RowID`. The table struct
    25  // does not:
    26  // - enforce uniqueness of the `RowID`
    27  // - enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix
    28  // of another
    29  // - optimize Gas usage conditions
    30  // The caller must ensure that these things are handled. The table struct is
    31  // private, so that we only have custom tables built on top of table, that do satisfy
    32  // these requirements.
    33  type table struct {
    34  	model       reflect.Type
    35  	prefix      [2]byte
    36  	afterSet    []AfterSetInterceptor
    37  	afterDelete []AfterDeleteInterceptor
    38  	cdc         codec.Codec
    39  }
    40  
    41  // newTable creates a new table
    42  func newTable(prefix [2]byte, model proto.Message, cdc codec.Codec) (*table, error) {
    43  	if model == nil {
    44  		return nil, errors.ErrORMInvalidArgument.Wrap("Model must not be nil")
    45  	}
    46  	tp := reflect.TypeOf(model)
    47  	if tp.Kind() == reflect.Ptr {
    48  		tp = tp.Elem()
    49  	}
    50  	return &table{
    51  		prefix: prefix,
    52  		model:  tp,
    53  		cdc:    cdc,
    54  	}, nil
    55  }
    56  
    57  // RowGetter returns a type safe RowGetter.
    58  func (a table) RowGetter() RowGetter {
    59  	return NewTypeSafeRowGetter(a.prefix, a.model, a.cdc)
    60  }
    61  
    62  // AddAfterSetInterceptor can be used to register a callback function that is executed after an object is created and/or updated.
    63  func (a *table) AddAfterSetInterceptor(interceptor AfterSetInterceptor) {
    64  	a.afterSet = append(a.afterSet, interceptor)
    65  }
    66  
    67  // AddAfterDeleteInterceptor can be used to register a callback function that is executed after an object is deleted.
    68  func (a *table) AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor) {
    69  	a.afterDelete = append(a.afterDelete, interceptor)
    70  }
    71  
    72  // Create persists the given object under the rowID key, returning an
    73  // errors.ErrORMUniqueConstraint if a value already exists at that key.
    74  //
    75  // Create iterates through the registered callbacks that may add secondary index
    76  // keys.
    77  func (a table) Create(store types.KVStore, rowID RowID, obj proto.Message) error {
    78  	if a.Has(store, rowID) {
    79  		return errors.ErrORMUniqueConstraint
    80  	}
    81  
    82  	return a.Set(store, rowID, obj)
    83  }
    84  
    85  // Update updates the given object under the rowID key. It expects the key to
    86  // exists already and fails with an `sdkerrors.ErrNotFound` otherwise. Any caller must
    87  // therefore make sure that this contract is fulfilled. Parameters must not be
    88  // nil.
    89  //
    90  // Update triggers all "after set" hooks that may add or remove secondary index keys.
    91  func (a table) Update(store types.KVStore, rowID RowID, newValue proto.Message) error {
    92  	if !a.Has(store, rowID) {
    93  		return sdkerrors.ErrNotFound
    94  	}
    95  
    96  	return a.Set(store, rowID, newValue)
    97  }
    98  
    99  // Set persists the given object under the rowID key. It does not check if the
   100  // key already exists and overwrites the value if it does.
   101  //
   102  // Set iterates through the registered callbacks that may add secondary index
   103  // keys.
   104  func (a table) Set(store types.KVStore, rowID RowID, newValue proto.Message) error {
   105  	if len(rowID) == 0 {
   106  		return errors.ErrORMEmptyKey
   107  	}
   108  	if err := assertCorrectType(a.model, newValue); err != nil {
   109  		return err
   110  	}
   111  	if err := assertValid(newValue); err != nil {
   112  		return err
   113  	}
   114  
   115  	pStore := prefix.NewStore(store, a.prefix[:])
   116  
   117  	var oldValue proto.Message
   118  	if a.Has(store, rowID) {
   119  		oldValue = reflect.New(a.model).Interface().(proto.Message)
   120  		a.GetOne(store, rowID, oldValue)
   121  	}
   122  
   123  	newValueEncoded, err := a.cdc.Marshal(newValue)
   124  	if err != nil {
   125  		return errorsmod.Wrapf(err, "failed to serialize %T", newValue)
   126  	}
   127  
   128  	pStore.Set(rowID, newValueEncoded)
   129  	for i, itc := range a.afterSet {
   130  		if err := itc(store, rowID, newValue, oldValue); err != nil {
   131  			return errorsmod.Wrapf(err, "interceptor %d failed", i)
   132  		}
   133  	}
   134  	return nil
   135  }
   136  
   137  func assertValid(obj proto.Message) error {
   138  	if v, ok := obj.(Validateable); ok {
   139  		if err := v.ValidateBasic(); err != nil {
   140  			return err
   141  		}
   142  	}
   143  	return nil
   144  }
   145  
   146  // Delete removes the object under the rowID key. It expects the key to exists
   147  // already and fails with a `sdkerrors.ErrNotFound` otherwise. Any caller must therefore
   148  // make sure that this contract is fulfilled.
   149  //
   150  // Delete iterates through the registered callbacks that remove secondary index
   151  // keys.
   152  func (a table) Delete(store types.KVStore, rowID RowID) error {
   153  	pStore := prefix.NewStore(store, a.prefix[:])
   154  
   155  	oldValue := reflect.New(a.model).Interface().(proto.Message)
   156  	if err := a.GetOne(store, rowID, oldValue); err != nil {
   157  		return errorsmod.Wrap(err, "load old value")
   158  	}
   159  	pStore.Delete(rowID)
   160  
   161  	for i, itc := range a.afterDelete {
   162  		if err := itc(store, rowID, oldValue); err != nil {
   163  			return errorsmod.Wrapf(err, "delete interceptor %d failed", i)
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  // Has checks if a key exists. Returns false when the key is empty or nil
   170  // because we don't allow creation of values without a key.
   171  func (a table) Has(store types.KVStore, key RowID) bool {
   172  	if len(key) == 0 {
   173  		return false
   174  	}
   175  	pStore := prefix.NewStore(store, a.prefix[:])
   176  	return pStore.Has(key)
   177  }
   178  
   179  // GetOne load the object persisted for the given RowID into the dest parameter.
   180  // If none exists or `rowID==nil` then `sdkerrors.ErrNotFound` is returned instead.
   181  // Parameters must not be nil - we don't allow creation of values with empty keys.
   182  func (a table) GetOne(store types.KVStore, rowID RowID, dest proto.Message) error {
   183  	if len(rowID) == 0 {
   184  		return sdkerrors.ErrNotFound
   185  	}
   186  	x := NewTypeSafeRowGetter(a.prefix, a.model, a.cdc)
   187  	return x(store, rowID, dest)
   188  }
   189  
   190  // PrefixScan returns an Iterator over a domain of keys in ascending order. End is exclusive.
   191  // Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid.
   192  // Iterator must be closed by caller.
   193  // To iterate over entire domain, use PrefixScan(nil, nil)
   194  //
   195  // WARNING: The use of a PrefixScan can be very expensive in terms of Gas. Please make sure you do not expose
   196  // this as an endpoint to the public without further limits.
   197  // Example:
   198  //
   199  //	it, err := idx.PrefixScan(ctx, start, end)
   200  //	if err !=nil {
   201  //		return err
   202  //	}
   203  //	const defaultLimit = 20
   204  //	it = LimitIterator(it, defaultLimit)
   205  //
   206  // CONTRACT: No writes may happen within a domain while an iterator exists over it.
   207  func (a table) PrefixScan(store types.KVStore, start, end RowID) (Iterator, error) {
   208  	if start != nil && end != nil && bytes.Compare(start, end) >= 0 {
   209  		return NewInvalidIterator(), errorsmod.Wrap(errors.ErrORMInvalidArgument, "start must be before end")
   210  	}
   211  	pStore := prefix.NewStore(store, a.prefix[:])
   212  	return &typeSafeIterator{
   213  		store:     store,
   214  		rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc),
   215  		it:        pStore.Iterator(start, end),
   216  	}, nil
   217  }
   218  
   219  // ReversePrefixScan returns an Iterator over a domain of keys in descending order. End is exclusive.
   220  // Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid  and error is returned.
   221  // Iterator must be closed by caller.
   222  // To iterate over entire domain, use PrefixScan(nil, nil)
   223  //
   224  // WARNING: The use of a ReversePrefixScan can be very expensive in terms of Gas. Please make sure you do not expose
   225  // this as an endpoint to the public without further limits. See `LimitIterator`
   226  //
   227  // CONTRACT: No writes may happen within a domain while an iterator exists over it.
   228  func (a table) ReversePrefixScan(store types.KVStore, start, end RowID) (Iterator, error) {
   229  	if start != nil && end != nil && bytes.Compare(start, end) >= 0 {
   230  		return NewInvalidIterator(), errorsmod.Wrap(errors.ErrORMInvalidArgument, "start must be before end")
   231  	}
   232  	pStore := prefix.NewStore(store, a.prefix[:])
   233  	return &typeSafeIterator{
   234  		store:     store,
   235  		rowGetter: NewTypeSafeRowGetter(a.prefix, a.model, a.cdc),
   236  		it:        pStore.ReverseIterator(start, end),
   237  	}, nil
   238  }
   239  
   240  // Export stores all the values in the table in the passed ModelSlicePtr.
   241  func (a table) Export(store types.KVStore, dest ModelSlicePtr) (uint64, error) {
   242  	it, err := a.PrefixScan(store, nil, nil)
   243  	if err != nil {
   244  		return 0, errorsmod.Wrap(err, "table Export failure when exporting table data")
   245  	}
   246  	_, err = ReadAll(it, dest)
   247  	if err != nil {
   248  		return 0, err
   249  	}
   250  	return 0, nil
   251  }
   252  
   253  // Import clears the table and initializes it from the given data interface{}.
   254  // data should be a slice of structs that implement PrimaryKeyed.
   255  func (a table) Import(store types.KVStore, data interface{}, _ uint64) error {
   256  	// Clear all data
   257  	keys := a.keys(store)
   258  	for _, key := range keys {
   259  		if err := a.Delete(store, key); err != nil {
   260  			return err
   261  		}
   262  	}
   263  
   264  	// Provided data must be a slice
   265  	modelSlice := reflect.ValueOf(data)
   266  	if modelSlice.Kind() != reflect.Slice {
   267  		return errorsmod.Wrap(errors.ErrORMInvalidArgument, "data must be a slice")
   268  	}
   269  
   270  	// Import values from slice
   271  	for i := 0; i < modelSlice.Len(); i++ {
   272  		obj, ok := modelSlice.Index(i).Interface().(PrimaryKeyed)
   273  		if !ok {
   274  			return errorsmod.Wrapf(errors.ErrORMInvalidArgument, "unsupported type :%s", reflect.TypeOf(data).Elem().Elem())
   275  		}
   276  		err := a.Create(store, PrimaryKey(obj), obj)
   277  		if err != nil {
   278  			return err
   279  		}
   280  	}
   281  
   282  	return nil
   283  }
   284  
   285  func (a table) keys(store types.KVStore) [][]byte {
   286  	pStore := prefix.NewStore(store, a.prefix[:])
   287  	it := pStore.Iterator(nil, nil)
   288  	defer it.Close()
   289  
   290  	var keys [][]byte
   291  	for ; it.Valid(); it.Next() {
   292  		keys = append(keys, it.Key())
   293  	}
   294  	return keys
   295  }
   296  
   297  // typeSafeIterator is initialized with a type safe RowGetter only.
   298  type typeSafeIterator struct {
   299  	store     types.KVStore
   300  	rowGetter RowGetter
   301  	it        types.Iterator
   302  }
   303  
   304  func (i typeSafeIterator) LoadNext(dest proto.Message) (RowID, error) {
   305  	if !i.it.Valid() {
   306  		return nil, errors.ErrORMIteratorDone
   307  	}
   308  	rowID := i.it.Key()
   309  	i.it.Next()
   310  	return rowID, i.rowGetter(i.store, rowID, dest)
   311  }
   312  
   313  func (i typeSafeIterator) Close() error {
   314  	return i.it.Close()
   315  }