116 lines
2.5 KiB
Go
116 lines
2.5 KiB
Go
package query
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/types"
|
|
)
|
|
|
|
// FilteredPaginate does pagination of all the results in the PrefixStore based on the
|
|
// provided PageRequest. onResult should be used to do actual unmarshaling and filter the results.
|
|
// If key is provided, the pagination uses the optimized querying.
|
|
// If offset is used, the pagination uses lazy filtering i.e., searches through all the records.
|
|
// The accumulate parameter represents if the response is valid based on the offset given.
|
|
// It will be false for the results (filtered) < offset and true for `offset > accumulate <= end`.
|
|
// When accumulate is set to true the current result should be appended to the result set returned
|
|
// to the client.
|
|
func FilteredPaginate(
|
|
prefixStore types.KVStore,
|
|
pageRequest *PageRequest,
|
|
onResult func(key []byte, value []byte, accumulate bool) (bool, error),
|
|
) (*PageResponse, error) {
|
|
|
|
// if the PageRequest is nil, use default PageRequest
|
|
if pageRequest == nil {
|
|
pageRequest = &PageRequest{}
|
|
}
|
|
|
|
offset := pageRequest.Offset
|
|
key := pageRequest.Key
|
|
limit := pageRequest.Limit
|
|
countTotal := pageRequest.CountTotal
|
|
reverse := pageRequest.Reverse
|
|
|
|
if offset > 0 && key != nil {
|
|
return nil, fmt.Errorf("invalid request, either offset or key is expected, got both")
|
|
}
|
|
|
|
if limit == 0 {
|
|
limit = DefaultLimit
|
|
|
|
// count total results when the limit is zero/not supplied
|
|
countTotal = true
|
|
}
|
|
|
|
if len(key) != 0 {
|
|
iterator := getIterator(prefixStore, key, reverse)
|
|
defer iterator.Close()
|
|
|
|
var numHits uint64
|
|
var nextKey []byte
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
if numHits == limit {
|
|
nextKey = iterator.Key()
|
|
break
|
|
}
|
|
|
|
if iterator.Error() != nil {
|
|
return nil, iterator.Error()
|
|
}
|
|
|
|
hit, err := onResult(iterator.Key(), iterator.Value(), true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if hit {
|
|
numHits++
|
|
}
|
|
}
|
|
|
|
return &PageResponse{
|
|
NextKey: nextKey,
|
|
}, nil
|
|
}
|
|
|
|
iterator := getIterator(prefixStore, nil, reverse)
|
|
defer iterator.Close()
|
|
|
|
end := offset + limit
|
|
|
|
var numHits uint64
|
|
var nextKey []byte
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
if iterator.Error() != nil {
|
|
return nil, iterator.Error()
|
|
}
|
|
|
|
accumulate := numHits >= offset && numHits < end
|
|
hit, err := onResult(iterator.Key(), iterator.Value(), accumulate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if hit {
|
|
numHits++
|
|
}
|
|
|
|
if numHits == end+1 {
|
|
nextKey = iterator.Key()
|
|
|
|
if !countTotal {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
res := &PageResponse{NextKey: nextKey}
|
|
if countTotal {
|
|
res.Total = numHits
|
|
}
|
|
|
|
return res, nil
|
|
}
|