Skip to content

Commit

Permalink
Merge PR #4658: Generalize Querier REST Pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Jul 2, 2019
1 parent b3a8195 commit aba1f64
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 41 deletions.
2 changes: 2 additions & 0 deletions .pending/improvements/sdk/4601-Implement-gener
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#4601 Implement generic pangination helper function to be used in
REST handlers and queriers.
30 changes: 30 additions & 0 deletions client/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package client

// Paginate returns the correct starting and ending index for a paginated query,
// given that client provides a desired page and limit of objects and the handler
// provides the total number of objects. If the start page is invalid, non-positive
// values are returned signaling the request is invalid.
//
// NOTE: The start page is assumed to be 1-indexed.
func Paginate(numObjs, page, limit, defLimit int) (start, end int) {
if page == 0 {
// invalid start page
return -1, -1
} else if limit == 0 {
limit = defLimit
}

start = (page - 1) * limit
end = limit + start

if end >= numObjs {
end = numObjs
}

if start >= numObjs {
// page is out of bounds
return -1, -1
}

return start, end
}
61 changes: 61 additions & 0 deletions client/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package client_test

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/client"
)

func TestPaginate(t *testing.T) {
testCases := []struct {
name string
numObjs, page, limit, defLimit int
expectedStart, expectedEnd int
}{
{
"all objects in a single page",
100, 1, 100, 100,
0, 100,
},
{
"page one of three",
75, 1, 25, 100,
0, 25,
},
{
"page two of three",
75, 2, 25, 100,
25, 50,
},
{
"page three of three",
75, 3, 25, 100,
50, 75,
},
{
"end is greater than total number of objects",
75, 2, 50, 100,
50, 75,
},
{
"invalid start page",
75, 4, 25, 100,
-1, -1,
},
{
"invalid zero start page",
75, 0, 25, 100,
-1, -1,
},
}

for i, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
start, end := client.Paginate(tc.numObjs, tc.page, tc.limit, tc.defLimit)
require.Equal(t, tc.expectedStart, start, "invalid result; test case #%d", i)
require.Equal(t, tc.expectedEnd, end, "invalid result; test case #%d", i)
})
}
}
17 changes: 3 additions & 14 deletions x/slashing/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand Down Expand Up @@ -65,27 +66,15 @@ func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte
return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
}

if params.Limit == 0 {
// set the default limit to max bonded if no limit was provided
params.Limit = int(k.sk.MaxValidators(ctx))
}

var signingInfos []ValidatorSigningInfo

k.IterateValidatorSigningInfos(ctx, func(consAddr sdk.ConsAddress, info ValidatorSigningInfo) (stop bool) {
signingInfos = append(signingInfos, info)
return false
})

// get pagination bounds
start := (params.Page - 1) * params.Limit
end := params.Limit + start
if end >= len(signingInfos) {
end = len(signingInfos)
}

if start >= len(signingInfos) {
// page is out of bounds
start, end := client.Paginate(len(signingInfos), params.Page, params.Limit, int(k.sk.MaxValidators(ctx)))
if start < 0 || end < 0 {
signingInfos = []ValidatorSigningInfo{}
} else {
signingInfos = signingInfos[start:end]
Expand Down
17 changes: 3 additions & 14 deletions x/staking/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/types"
Expand Down Expand Up @@ -55,11 +56,6 @@ func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte,
return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
}

stakingParams := k.GetParams(ctx)
if params.Limit == 0 {
params.Limit = int(stakingParams.MaxValidators)
}

validators := k.GetAllValidators(ctx)
filteredVals := make([]types.Validator, 0, len(validators))

Expand All @@ -69,15 +65,8 @@ func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte,
}
}

// get pagination bounds
start := (params.Page - 1) * params.Limit
end := params.Limit + start
if end >= len(filteredVals) {
end = len(filteredVals)
}

if start >= len(filteredVals) {
// page is out of bounds
start, end := client.Paginate(len(filteredVals), params.Page, params.Limit, int(k.GetParams(ctx).MaxValidators))
if start < 0 || end < 0 {
filteredVals = []types.Validator{}
} else {
filteredVals = filteredVals[start:end]
Expand Down
16 changes: 3 additions & 13 deletions x/supply/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/supply/types"
)
Expand Down Expand Up @@ -32,20 +33,9 @@ func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte,
}

totalSupply := k.GetSupply(ctx).Total
totalSupplyLen := len(totalSupply)

if params.Limit == 0 {
params.Limit = totalSupplyLen
}

start := (params.Page - 1) * params.Limit
end := params.Limit + start
if end >= totalSupplyLen {
end = totalSupplyLen
}

if start >= totalSupplyLen {
// page is out of bounds
start, end := client.Paginate(len(totalSupply), params.Page, params.Limit, 100)
if start < 0 || end < 0 {
totalSupply = sdk.Coins{}
} else {
totalSupply = totalSupply[start:end]
Expand Down

0 comments on commit aba1f64

Please sign in to comment.