Skip to content

Commit

Permalink
feat(x/ecocredit): query all projects with pagination (#1178)
Browse files Browse the repository at this point in the history
* feat(x/ecocredit): query all projects with pagination

* feat(x/ecocredit): query all projects with pagination

* feat(x/ecocredit): query all projects with pagination

* fix comments

* clean up test format and add alternative binding
  • Loading branch information
ryanchristo authored Jun 13, 2022
1 parent b90aa21 commit c874e24
Show file tree
Hide file tree
Showing 14 changed files with 2,930 additions and 660 deletions.
2,009 changes: 1,579 additions & 430 deletions api/regen/ecocredit/v1/query.pulsar.go

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions api/regen/ecocredit/v1/query_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions proto/regen/ecocredit/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,18 @@ service Query {
};
}

// Projects queries for all projects with pagination.
rpc Projects(QueryProjectsRequest) returns (QueryProjectsResponse) {
option (google.api.http).get = "/regen/ecocredit/v1/projects";
}

// ProjectsByClass queries for all projects within a class with pagination.
rpc ProjectsByClass(QueryProjectsByClassRequest)
returns (QueryProjectsByClassResponse) {
option (google.api.http) = {
get : "/regen/ecocredit/v1/projects-by-class/{class_id}"
additional_bindings : [
{get : "/regen/ecocredit/v1/projects/class/{class_id}"},
{get : "/regen/ecocredit/v1/classes/{class_id}/projects"}
]
};
Expand Down Expand Up @@ -253,6 +259,23 @@ message QueryClassIssuersResponse {
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryProjectsRequest is the Query/Projects request type.
message QueryProjectsRequest {

// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryProjectsResponse is the Query/Projects response type.
message QueryProjectsResponse {

// projects are the fetched projects.
repeated ProjectInfo projects = 1;

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryProjectsByClassRequest is the Query/ProjectsByClass request type.
message QueryProjectsByClassRequest {

Expand Down
45 changes: 41 additions & 4 deletions x/ecocredit/client/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func QueryCmd(name string) *cobra.Command {
QueryBalanceCmd(),
QuerySupplyCmd(),
QueryCreditTypesCmd(),
QueryProjectsCmd(),
QueryProjectsByClassCmd(),
QueryProjectsByReferenceIdCmd(),
QueryProjectsByAdminCmd(),
Expand Down Expand Up @@ -154,14 +155,50 @@ regen q ecocredit class-issuers C01 --limit 10
return qflags(cmd)
}

// QueryProjectsByClassCmd returns a query command that retrieves projects.
// QueryProjectsCmd returns a query command that retrieves all projects.
func QueryProjectsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "projects",
Short: "Query all projects",
Long: "Query all projects with optional pagination flags.",
Example: `
regen q ecocredit projects
regen q ecocredit projects --limit 10 --count-total
`,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
c, ctx, err := mkQueryClient(cmd)
if err != nil {
return err
}

pagination, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}

res, err := c.Projects(cmd.Context(), &core.QueryProjectsRequest{
Pagination: pagination,
})

return printQueryResponse(ctx, res, err)
},
}

flags.AddPaginationFlagsToCmd(cmd, "projects")

return qflags(cmd)
}

// QueryProjectsByClassCmd returns a query command that retrieves projects by credit class.
func QueryProjectsByClassCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "projects-by-class [class_id]",
Short: "List all projects in the given class with pagination flags",
Short: "Query projects by credit class",
Long: "Query projects by credit class with optional pagination flags.",
Example: `
regen q ecocredit projects C01
regen q ecocredit projects C01 --limit 10
regen q ecocredit projects-by-class C01
regen q ecocredit projects-by-class C01 --limit 10 --count-total
`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down
189 changes: 187 additions & 2 deletions x/ecocredit/client/testsuite/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package testsuite

import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"

types2 "github.com/regen-network/regen-ledger/types"
"github.com/regen-network/regen-ledger/x/ecocredit/core"
"github.com/regen-network/regen-ledger/x/ecocredit/marketplace"
Expand Down Expand Up @@ -80,7 +80,192 @@ func (s *IntegrationTestSuite) TestQueryClass() {
err = s.val.ClientCtx.Codec.UnmarshalJSON(resp, &res)
require.NoError(err)
require.NotNil(res.Class)
require.Contains(res.Class.Id, s.classId)
require.Equal(res.Class.Id, s.classId)
})
}
}

func (s *IntegrationTestSuite) TestQueryProject() {
require := s.Require()

testCases := []struct {
name string
url string
}{
{
"valid",
fmt.Sprintf("%s/%s/project/%s", s.val.APIAddress, coreRoute, s.projectId),
},
{
"valid alternative",
fmt.Sprintf("%s/%s/projects/%s", s.val.APIAddress, coreRoute, s.projectId),
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
bz, err := rest.GetRequest(tc.url)
require.NoError(err)
require.NotContains(string(bz), "code")

var res core.QueryProjectResponse
require.NoError(s.val.ClientCtx.Codec.UnmarshalJSON(bz, &res))
require.NotEmpty(res.Project)
})
}
}

func (s *IntegrationTestSuite) TestQueryProjects() {
require := s.Require()

testCases := []struct {
name string
url string
}{
{
"valid",
fmt.Sprintf("%s/%s/projects", s.val.APIAddress, coreRoute),
},
{
"valid with pagination",
fmt.Sprintf(
"%s/%s/projects?pagination.limit=1&pagination.countTotal=true",
s.val.APIAddress,
coreRoute,
),
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
bz, err := rest.GetRequest(tc.url)
require.NoError(err)
require.NotContains(string(bz), "code")

var res core.QueryProjectsResponse
require.NoError(s.val.ClientCtx.Codec.UnmarshalJSON(bz, &res))
require.NotEmpty(res.Projects)

if strings.Contains(tc.name, "pagination") {
require.Len(res.Projects, 1)
require.NotEmpty(res.Pagination)
require.NotEmpty(res.Pagination.Total)
} else {
require.Empty(res.Pagination)
}
})
}
}

func (s *IntegrationTestSuite) TestQueryProjectsByClass() {
require := s.Require()

testCases := []struct {
name string
url string
}{
{
"valid",
fmt.Sprintf("%s/%s/projects-by-class/%s", s.val.APIAddress, coreRoute, s.classId),
},
{
"valid with pagination",
fmt.Sprintf(
"%s/%s/projects-by-class/%s?pagination.countTotal=true",
// TODO: #1113
// "%s/%s/projects-by-class/%s?pagination.limit=1&pagination.countTotal=true",
s.val.APIAddress,
coreRoute,
s.classId,
),
},
{
"valid alternative",
fmt.Sprintf("%s/%s/projects/class/%s", s.val.APIAddress, coreRoute, s.classId),
},
{
"valid alternative",
fmt.Sprintf("%s/%s/classes/%s/projects", s.val.APIAddress, coreRoute, s.classId),
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
bz, err := rest.GetRequest(tc.url)
require.NoError(err)
require.NotContains(string(bz), "code")

var res core.QueryProjectsByClassResponse
require.NoError(s.val.ClientCtx.Codec.UnmarshalJSON(bz, &res))
require.NotEmpty(res.Projects)

if strings.Contains(tc.name, "pagination") {
require.Len(res.Projects, 1)
require.NotEmpty(res.Pagination)
require.NotEmpty(res.Pagination.Total)
} else {
require.Empty(res.Pagination)
}
})
}
}

func (s *IntegrationTestSuite) TestQueryProjectsByReferenceId() {
require := s.Require()

testCases := []struct {
name string
url string
}{
{
"valid",
fmt.Sprintf(
"%s/%s/projects-by-reference-id/%s",
s.val.APIAddress,
coreRoute,
s.projectReferenceId,
),
},
{
"valid with pagination",
fmt.Sprintf(
"%s/%s/projects-by-reference-id/%s?pagination.limit=1&pagination.countTotal=true",
s.val.APIAddress,
coreRoute,
s.projectReferenceId,
),
},
{
"valid alternative",
fmt.Sprintf("%s/%s/projects/reference-id/%s",
s.val.APIAddress,
coreRoute,
s.projectReferenceId,
),
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
bz, err := rest.GetRequest(tc.url)
require.NoError(err)
require.NotContains(string(bz), "code")

var res core.QueryProjectsByReferenceIdResponse
require.NoError(s.val.ClientCtx.Codec.UnmarshalJSON(bz, &res))
require.NotEmpty(res.Projects)

if strings.Contains(tc.name, "pagination") {
require.Len(res.Projects, 1)
require.NotEmpty(res.Pagination)
require.NotEmpty(res.Pagination.Total)
} else {
require.Empty(res.Pagination)
}
})
}
}
Expand Down
Loading

0 comments on commit c874e24

Please sign in to comment.