-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
134 lines (115 loc) · 5.46 KB
/
types.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
/*
Package orm is a convenient object to data store mapper.
*/
package orm
import (
"io"
"reflect"
"github.com/blockgenx/blockgen-sdk/codec"
"github.com/blockgenx/blockgen-sdk/store/prefix"
sdk "github.com/blockgenx/blockgen-sdk/types"
sdkerrors "github.com/blockgenx/blockgen-sdk/types/errors"
"github.com/blockgenx/blockgen-sdk/types/query"
"github.com/blockgenx/blockgen-sdk/x/group/errors"
)
// Unique identifier of a persistent table.
type RowID []byte
// Bytes returns raw bytes.
func (r RowID) Bytes() []byte {
return r
}
// Validateable is an interface that ProtoMarshaler types can implement and is called on any orm save or update operation.
type Validateable interface {
// ValidateBasic is a sanity check on the data. Any error returned prevents create or updates.
ValidateBasic() error
}
// Index allows efficient prefix scans is stored as key = concat(indexKeyBytes, rowIDUint64) with value empty
// so that the row PrimaryKey is allows a fixed with 8 byte integer. This allows the MultiKeyIndex key bytes to be
// variable length and scanned iteratively.
type Index interface {
// Has checks if a key exists. Panics on nil key.
Has(store sdk.KVStore, key interface{}) (bool, error)
// Get returns a result iterator for the searchKey.
// searchKey must not be nil.
Get(store sdk.KVStore, searchKey interface{}) (Iterator, error)
// GetPaginated returns a result iterator for the searchKey and optional pageRequest.
// searchKey must not be nil.
GetPaginated(store sdk.KVStore, searchKey interface{}, pageRequest *query.PageRequest) (Iterator, error)
// PrefixScan returns an Iterator over a domain of keys in ascending order. End is exclusive.
// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned.
// Iterator must be closed by caller.
// To iterate over entire domain, use PrefixScan(nil, nil)
//
// WARNING: The use of a PrefixScan can be very expensive in terms of Gas. Please make sure you do not expose
// this as an endpoint to the public without further limits.
// Example:
// it, err := idx.PrefixScan(ctx, start, end)
// if err !=nil {
// return err
// }
// const defaultLimit = 20
// it = LimitIterator(it, defaultLimit)
//
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
PrefixScan(store sdk.KVStore, startI interface{}, endI interface{}) (Iterator, error)
// ReversePrefixScan returns an Iterator over a domain of keys in descending order. End is exclusive.
// Start is an MultiKeyIndex key or prefix. It must be less than end, or the Iterator is invalid and error is returned.
// Iterator must be closed by caller.
// To iterate over entire domain, use PrefixScan(nil, nil)
//
// WARNING: The use of a ReversePrefixScan can be very expensive in terms of Gas. Please make sure you do not expose
// this as an endpoint to the public without further limits. See `LimitIterator`
//
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
ReversePrefixScan(store sdk.KVStore, startI interface{}, endI interface{}) (Iterator, error)
}
// Iterator allows iteration through a sequence of key value pairs
type Iterator interface {
// LoadNext loads the next value in the sequence into the pointer passed as dest and returns the key. If there
// are no more items the ErrORMIteratorDone error is returned
// The key is the rowID.
LoadNext(dest codec.ProtoMarshaler) (RowID, error)
// Close releases the iterator and should be called at the end of iteration
io.Closer
}
// Indexable types are used to setup new tables.
// This interface provides a set of functions that can be called by indexes to register and interact with the tables.
type Indexable interface {
RowGetter() RowGetter
AddAfterSetInterceptor(interceptor AfterSetInterceptor)
AddAfterDeleteInterceptor(interceptor AfterDeleteInterceptor)
}
// AfterSetInterceptor defines a callback function to be called on Create + Update.
type AfterSetInterceptor func(store sdk.KVStore, rowID RowID, newValue, oldValue codec.ProtoMarshaler) error
// AfterDeleteInterceptor defines a callback function to be called on Delete operations.
type AfterDeleteInterceptor func(store sdk.KVStore, rowID RowID, value codec.ProtoMarshaler) error
// RowGetter loads a persistent object by row ID into the destination object. The dest parameter must therefore be a pointer.
// Any implementation must return `sdkerrors.ErrNotFound` when no object for the rowID exists
type RowGetter func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error
// NewTypeSafeRowGetter returns a `RowGetter` with type check on the dest parameter.
func NewTypeSafeRowGetter(prefixKey [2]byte, model reflect.Type, cdc codec.Codec) RowGetter {
return func(store sdk.KVStore, rowID RowID, dest codec.ProtoMarshaler) error {
if len(rowID) == 0 {
return sdkerrors.Wrap(errors.ErrORMEmptyKey, "key must not be nil")
}
if err := assertCorrectType(model, dest); err != nil {
return err
}
pStore := prefix.NewStore(store, prefixKey[:])
bz := pStore.Get(rowID)
if len(bz) == 0 {
return sdkerrors.ErrNotFound
}
return cdc.Unmarshal(bz, dest)
}
}
func assertCorrectType(model reflect.Type, obj codec.ProtoMarshaler) error {
tp := reflect.TypeOf(obj)
if tp.Kind() != reflect.Ptr {
return sdkerrors.Wrap(sdkerrors.ErrInvalidType, "model destination must be a pointer")
}
if model != tp.Elem() {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "can not use %T with this bucket", obj)
}
return nil
}