cosmos-sdk/types/query/pagination.go

108 lines
2.1 KiB
Go

package query
import (
"fmt"
"github.com/cosmos/cosmos-sdk/store/types"
)
// defaultLimit is the default `limit` for queries
// if the `limit` is not supplied, paginate will use `defaultLimit`
const defaultLimit = 100
// Paginate does pagination of all the results in the PrefixStore based on the
// provided PageRequest. onResult should be used to do actual unmarshaling.
func Paginate(
prefixStore types.KVStore,
pageRequest *PageRequest,
onResult func(key []byte, value []byte) 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
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 := prefixStore.Iterator(key, nil)
defer iterator.Close()
var count uint64
var nextKey []byte
for ; iterator.Valid(); iterator.Next() {
if count == limit {
nextKey = iterator.Key()
break
}
if iterator.Error() != nil {
return nil, iterator.Error()
}
err := onResult(iterator.Key(), iterator.Value())
if err != nil {
return nil, err
}
count++
}
return &PageResponse{
NextKey: nextKey,
}, nil
}
iterator := prefixStore.Iterator(nil, nil)
defer iterator.Close()
end := offset + limit
var count uint64
var nextKey []byte
for ; iterator.Valid(); iterator.Next() {
count++
if count <= offset {
continue
}
if count <= end {
err := onResult(iterator.Key(), iterator.Value())
if err != nil {
return nil, err
}
} else if count == end+1 {
nextKey = iterator.Key()
if !countTotal {
break
}
}
if iterator.Error() != nil {
return nil, iterator.Error()
}
}
res := &PageResponse{NextKey: nextKey}
if countTotal {
res.Total = count
}
return res, nil
}