Skip to content

Commit

Permalink
feat: add pagination to ListResources API (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
FemiNoviaLina authored Apr 1, 2024
1 parent 713e2e8 commit 81b8706
Show file tree
Hide file tree
Showing 25 changed files with 812 additions and 637 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ GOVERSION := $(shell go version | cut -d ' ' -f 3 | cut -d '.' -f 2)

.PHONY: build check fmt lint test test-race vet test-cover-html help install proto
.DEFAULT_GOAL := build
PROTON_COMMIT := "cf2c230788bd298aa64c6e18dc79f0c0d1a9d076"
PROTON_COMMIT := "253aa80d6a65c575cdf4a6a1433867fd4d8092ca"

install:
@echo "Clean up imports..."
Expand Down
7 changes: 7 additions & 0 deletions core/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type Filter struct {
GroupID string
OrganizationID string
NamespaceID string
Limit int32
Page int32
}

type YAML struct {
Expand All @@ -59,3 +61,8 @@ type YAML struct {
ResourceType string `json:"resource_type" yaml:"resource_type"`
Actions map[string][]string `json:"actions" yaml:"actions"`
}

type PagedResources struct {
Count int32
Resources []Resource
}
11 changes: 9 additions & 2 deletions core/resource/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,15 @@ func (s Service) Create(ctx context.Context, res Resource) (Resource, error) {
return newResource, nil
}

func (s Service) List(ctx context.Context, flt Filter) ([]Resource, error) {
return s.repository.List(ctx, flt)
func (s Service) List(ctx context.Context, flt Filter) (PagedResources, error) {
resources, err := s.repository.List(ctx, flt)
if err != nil {
return PagedResources{}, err
}
return PagedResources{
Count: int32(len(resources)),
Resources: resources,
}, nil
}

func (s Service) Update(ctx context.Context, id string, resource Resource) (Resource, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/action_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/group_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/namespace_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/organization_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/policy_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/project_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/relation_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/relation_transformer.go

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

18 changes: 8 additions & 10 deletions internal/api/v1beta1/mocks/resource_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/role_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/rule_service.go

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

2 changes: 1 addition & 1 deletion internal/api/v1beta1/mocks/user_service.go

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

9 changes: 6 additions & 3 deletions internal/api/v1beta1/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

type ResourceService interface {
Get(ctx context.Context, id string) (resource.Resource, error)
List(ctx context.Context, flt resource.Filter) ([]resource.Resource, error)
List(ctx context.Context, flt resource.Filter) (resource.PagedResources, error)
Create(ctx context.Context, resource resource.Resource) (resource.Resource, error)
Update(ctx context.Context, id string, resource resource.Resource) (resource.Resource, error)
CheckAuthz(ctx context.Context, resource resource.Resource, action action.Action) (bool, error)
Expand All @@ -36,15 +36,17 @@ func (h Handler) ListResources(ctx context.Context, request *shieldv1beta1.ListR
OrganizationID: request.GetOrganizationId(),
ProjectID: request.GetProjectId(),
GroupID: request.GetGroupId(),
Limit: request.GetPageSize(),
Page: request.GetPageNum(),
}

resourcesList, err := h.resourceService.List(ctx, filters)
resourcesResp, err := h.resourceService.List(ctx, filters)
if err != nil {
logger.Error(err.Error())
return nil, grpcInternalServerError
}

for _, r := range resourcesList {
for _, r := range resourcesResp.Resources {
resourcePB, err := transformResourceToPB(r)
if err != nil {
logger.Error(err.Error())
Expand All @@ -54,6 +56,7 @@ func (h Handler) ListResources(ctx context.Context, request *shieldv1beta1.ListR
}

return &shieldv1beta1.ListResourcesResponse{
Count: resourcesResp.Count,
Resources: resources,
}, nil
}
Expand Down
16 changes: 12 additions & 4 deletions internal/api/v1beta1/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestHandler_ListResources(t *testing.T) {
{
name: "should return internal error if resource service return some error",
setup: func(rs *mocks.ResourceService) {
rs.EXPECT().List(mock.AnythingOfType("*context.emptyCtx"), resource.Filter{}).Return([]resource.Resource{}, errors.New("some error"))
rs.EXPECT().List(mock.AnythingOfType("*context.emptyCtx"), resource.Filter{}).Return(resource.PagedResources{}, errors.New("some error"))
},
request: &shieldv1beta1.ListResourcesRequest{},
want: nil,
Expand All @@ -71,12 +71,20 @@ func TestHandler_ListResources(t *testing.T) {
{
name: "should return resources if resource service return nil error",
setup: func(rs *mocks.ResourceService) {
rs.EXPECT().List(mock.AnythingOfType("*context.emptyCtx"), resource.Filter{}).Return([]resource.Resource{
testResource,
}, nil)
testResourceList := []resource.Resource{testResource}
rs.EXPECT().List(mock.AnythingOfType("*context.emptyCtx"), resource.Filter{}).Return(
resource.PagedResources{
Count: int32(len(testResourceList)),
Resources: testResourceList,
}, nil)
},
request: &shieldv1beta1.ListResourcesRequest{},
want: &shieldv1beta1.ListResourcesResponse{
Count: int32(
len([]*shieldv1beta1.Resource{
testResourcePB,
},
)),
Resources: []*shieldv1beta1.Resource{
testResourcePB,
},
Expand Down
2 changes: 1 addition & 1 deletion internal/proxy/hook/authz/mocks/relation_service.go

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

2 changes: 1 addition & 1 deletion internal/proxy/hook/authz/mocks/relation_transformer.go

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

2 changes: 1 addition & 1 deletion internal/proxy/hook/authz/mocks/resource_service.go

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

12 changes: 12 additions & 0 deletions internal/store/postgres/resource_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ func (r ResourceRepository) Create(ctx context.Context, res resource.Resource) (
func (r ResourceRepository) List(ctx context.Context, flt resource.Filter) ([]resource.Resource, error) {
var fetchedResources []Resource

var defaultLimit int32 = 50
var defaultPage int32 = 1
if flt.Limit < 1 {
flt.Limit = defaultLimit
}
if flt.Page < 1 {
flt.Page = defaultPage
}

offset := (flt.Page - 1) * flt.Limit

sqlStatement := dialect.From(TABLE_RESOURCES)
if flt.ProjectID != "" {
sqlStatement = sqlStatement.Where(goqu.Ex{"project_id": flt.ProjectID})
Expand All @@ -97,6 +108,7 @@ func (r ResourceRepository) List(ctx context.Context, flt resource.Filter) ([]re
if flt.NamespaceID != "" {
sqlStatement = sqlStatement.Where(goqu.Ex{"namespace_id": flt.NamespaceID})
}
sqlStatement = sqlStatement.Limit(uint(flt.Limit)).Offset(uint(offset))
query, params, err := sqlStatement.ToSQL()
if err != nil {
return nil, err
Expand Down
93 changes: 93 additions & 0 deletions internal/store/postgres/resource_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,99 @@ func (s *ResourceRepositoryTestSuite) TestList() {
},
},
},
{
Description: "should return the page given if filter page given is 1 or greater",
Filter: resource.Filter{
Page: 1,
Limit: 2,
},
ExpectedResources: []resource.Resource{
{
Idxa: s.resources[0].Idxa,
URN: s.resources[0].URN,
Name: s.resources[0].Name,
ProjectID: s.resources[0].ProjectID,
OrganizationID: s.resources[0].OrganizationID,
NamespaceID: s.resources[0].NamespaceID,
UserID: s.resources[0].UserID,
},
{
Idxa: s.resources[1].Idxa,
URN: s.resources[1].URN,
Name: s.resources[1].Name,
ProjectID: s.resources[1].ProjectID,
OrganizationID: s.resources[1].OrganizationID,
NamespaceID: s.resources[1].NamespaceID,
UserID: s.resources[1].UserID,
},
},
},
{
Description: "should return 1st page if filter page given is 0 or less",
Filter: resource.Filter{
Page: 0,
Limit: 2,
},
ExpectedResources: []resource.Resource{
{
Idxa: s.resources[0].Idxa,
URN: s.resources[0].URN,
Name: s.resources[0].Name,
ProjectID: s.resources[0].ProjectID,
OrganizationID: s.resources[0].OrganizationID,
NamespaceID: s.resources[0].NamespaceID,
UserID: s.resources[0].UserID,
},
{
Idxa: s.resources[1].Idxa,
URN: s.resources[1].URN,
Name: s.resources[1].Name,
ProjectID: s.resources[1].ProjectID,
OrganizationID: s.resources[1].OrganizationID,
NamespaceID: s.resources[1].NamespaceID,
UserID: s.resources[1].UserID,
},
},
},
{
Description: "should return list of users with maximum 50 data if limit given is 0 or less",
Filter: resource.Filter{
Limit: 0,
Page: 1,
},
ExpectedResources: s.resources,
},
{
Description: "should return first page of filtered resources based on search filters",
Filter: resource.Filter{
Page: 1,
Limit: 2,
ProjectID: s.projects[1].ID,
OrganizationID: s.orgs[1].ID,
NamespaceID: s.namespaces[1].ID,
},
ExpectedResources: []resource.Resource{
{
Idxa: s.resources[1].Idxa,
URN: s.resources[1].URN,
Name: s.resources[1].Name,
ProjectID: s.resources[1].ProjectID,
OrganizationID: s.resources[1].OrganizationID,
NamespaceID: s.resources[1].NamespaceID,
UserID: s.resources[1].UserID,
},
},
},
{
Description: "should return second page of filtered resources based on search filters",
Filter: resource.Filter{
Page: 2,
Limit: 2,
ProjectID: s.projects[1].ID,
OrganizationID: s.orgs[1].ID,
NamespaceID: s.namespaces[1].ID,
},
},
}

for _, tc := range testCases {
Expand Down
Loading

0 comments on commit 81b8706

Please sign in to comment.