diff --git a/types/query/collections_pagination.go b/types/query/collections_pagination.go index 4ef389038dc6..14a4b7979973 100644 --- a/types/query/collections_pagination.go +++ b/types/query/collections_pagination.go @@ -139,6 +139,8 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( // if no predicate function is specified then we just include the result if predicateFunc == nil { results = append(results, kv) + count++ + // if predicate function is defined we check if the result matches the filtering criteria } else { include, err := predicateFunc(kv.Key, kv.Value) @@ -147,9 +149,9 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( } if include { results = append(results, kv) + count++ } } - count++ // second case, we found all the objects specified within the limit case count == limit: key, err := iterator.Key() @@ -172,12 +174,31 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( // but we need to count how many possible results exist in total. // so we keep increasing the count until the iterator is fully consumed. case count > limit: - count++ + if predicateFunc == nil { + count++ + + // if predicate function is defined we check if the result matches the filtering criteria + } else { + kv, err := iterator.KeyValue() + if err != nil { + return nil, nil, err + } + + include, err := predicateFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + if include { + count++ + } + } } } + resp := &PageResponse{ NextKey: nextKey, } + if countTotal { resp.Total = count + offset } diff --git a/x/gov/keeper/grpc_query.go b/x/gov/keeper/grpc_query.go index a4b4a035140a..b8fe017af28d 100644 --- a/x/gov/keeper/grpc_query.go +++ b/x/gov/keeper/grpc_query.go @@ -56,8 +56,7 @@ func (q queryServer) Proposal(ctx context.Context, req *v1.QueryProposalRequest) // Proposals implements the Query/Proposals gRPC method func (q queryServer) Proposals(ctx context.Context, req *v1.QueryProposalsRequest) (*v1.QueryProposalsResponse, error) { - var filteredProposals []*v1.Proposal - _, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Proposals, req.Pagination, func(key uint64, p v1.Proposal) (bool, error) { + res, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Proposals, req.Pagination, func(key uint64, p v1.Proposal) (include bool, err error) { matchVoter, matchDepositor, matchStatus := true, true, true // match status (if supplied/valid) @@ -90,11 +89,18 @@ func (q queryServer) Proposals(ctx context.Context, req *v1.QueryProposalsReques // if all match, append to results if matchVoter && matchDepositor && matchStatus { - filteredProposals = append(filteredProposals, &p) + return true, nil } // continue to next item, do not include because we're appending results above. return false, nil }) + + filteredProposals := make([]*v1.Proposal, len(res)) + + for i := 0; i < len(res); i++ { + filteredProposals[i] = &res[i].Value + } + if err != nil && !errors.IsOf(err, collections.ErrInvalidIterator) { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 2baadef3467c..befe97919b5b 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -222,7 +222,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { true, }, { - "request 2nd page with limit 4", + "request 2nd page with limit 3", func() { req = &v1.QueryProposalsRequest{ Pagination: &query.PageRequest{Offset: 3, Limit: 3}, @@ -294,6 +294,70 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { }, true, }, + { + "request with filter of status voting period", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusVotingPeriod, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals); i++ { + if testProposals[i].GetStatus() == v1.StatusVotingPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, + { + "request with filter of status deposit period", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusDepositPeriod, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals); i++ { + if testProposals[i].GetStatus() == v1.StatusDepositPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, + { + "request with filter of status deposit period with limit 2", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusDepositPeriod, + Pagination: &query.PageRequest{ + Limit: 2, + CountTotal: true, + }, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals) && len(proposals) < 2; i++ { + if testProposals[i].GetStatus() == v1.StatusDepositPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, } for _, testCase := range testCases {