github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/types/query/pagination.go (about)

     1  package query
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  
     8  	"google.golang.org/grpc/codes"
     9  	"google.golang.org/grpc/status"
    10  )
    11  
    12  // DefaultLimit is the default `limit` for queries
    13  // if the `limit` is not supplied, paginate will use `DefaultLimit`
    14  const DefaultLimit = 100
    15  
    16  // ParsePagination validate PageRequest and returns page number & limit.
    17  func ParsePagination(pageReq *PageRequest) (page, limit int, err error) {
    18  	offset := 0
    19  	limit = DefaultLimit
    20  
    21  	if pageReq != nil {
    22  		offset = int(pageReq.Offset)
    23  		limit = int(pageReq.Limit)
    24  	}
    25  	if offset < 0 {
    26  		return 1, 0, status.Error(codes.InvalidArgument, "offset must greater than 0")
    27  	}
    28  
    29  	if limit < 0 {
    30  		return 1, 0, status.Error(codes.InvalidArgument, "limit must greater than 0")
    31  	} else if limit == 0 {
    32  		limit = DefaultLimit
    33  	}
    34  
    35  	page = offset/limit + 1
    36  
    37  	return page, limit, nil
    38  }
    39  
    40  // Paginate does pagination of all the results in the PrefixStore based on the
    41  // provided PageRequest. onResult should be used to do actual unmarshaling.
    42  func Paginate(
    43  	prefixStore types.KVStore,
    44  	pageRequest *PageRequest,
    45  	onResult func(key []byte, value []byte) error,
    46  ) (*PageResponse, error) {
    47  
    48  	// if the PageRequest is nil, use default PageRequest
    49  	if pageRequest == nil {
    50  		pageRequest = &PageRequest{}
    51  	}
    52  
    53  	offset := pageRequest.Offset
    54  	key := pageRequest.Key
    55  	limit := pageRequest.Limit
    56  	countTotal := pageRequest.CountTotal
    57  
    58  	if offset > 0 && key != nil {
    59  		return nil, fmt.Errorf("invalid request, either offset or key is expected, got both")
    60  	}
    61  
    62  	if limit == 0 {
    63  		limit = DefaultLimit
    64  
    65  		// count total results when the limit is zero/not supplied
    66  		countTotal = true
    67  	}
    68  
    69  	if len(key) != 0 {
    70  		iterator := prefixStore.Iterator(key, nil)
    71  		defer iterator.Close()
    72  
    73  		var count uint64
    74  		var nextKey []byte
    75  
    76  		for ; iterator.Valid(); iterator.Next() {
    77  			if count == limit {
    78  				nextKey = iterator.Key()
    79  				break
    80  			}
    81  			if iterator.Error() != nil {
    82  				return nil, iterator.Error()
    83  			}
    84  			err := onResult(iterator.Key(), iterator.Value())
    85  			if err != nil {
    86  				return nil, err
    87  			}
    88  
    89  			count++
    90  		}
    91  
    92  		return &PageResponse{
    93  			NextKey: nextKey,
    94  		}, nil
    95  	}
    96  
    97  	iterator := prefixStore.Iterator(nil, nil)
    98  	defer iterator.Close()
    99  
   100  	end := offset + limit
   101  
   102  	var count uint64
   103  	var nextKey []byte
   104  
   105  	for ; iterator.Valid(); iterator.Next() {
   106  		count++
   107  
   108  		if count <= offset {
   109  			continue
   110  		}
   111  		if count <= end {
   112  			err := onResult(iterator.Key(), iterator.Value())
   113  			if err != nil {
   114  				return nil, err
   115  			}
   116  		} else if count == end+1 {
   117  			nextKey = iterator.Key()
   118  
   119  			if !countTotal {
   120  				break
   121  			}
   122  		}
   123  		if iterator.Error() != nil {
   124  			return nil, iterator.Error()
   125  		}
   126  	}
   127  
   128  	res := &PageResponse{NextKey: nextKey}
   129  	if countTotal {
   130  		res.Total = count
   131  	}
   132  
   133  	return res, nil
   134  }
   135  
   136  func NewPaginateFromPageLimit(page, limit int) *PageRequest {
   137  	var offset uint64
   138  	if page > 1 {
   139  		offset = uint64((page - 1) * limit)
   140  	}
   141  
   142  	if limit <= 0 {
   143  		limit = DefaultLimit
   144  	}
   145  
   146  	return &PageRequest{
   147  		Key:        nil,
   148  		Offset:     offset,
   149  		Limit:      uint64(limit),
   150  		CountTotal: true,
   151  	}
   152  }