Skip to content

Commit

Permalink
add pagination for project list api (#839)
Browse files Browse the repository at this point in the history
* add pagination for project list api

* update default page size to 1000

* remove hardcoded pagination from service

* update ListOrganizations to accept page size and num from request
  • Loading branch information
AmanGIT07 authored Jan 3, 2025
1 parent ceed362 commit e065480
Show file tree
Hide file tree
Showing 9 changed files with 5,237 additions and 5,049 deletions.
3 changes: 3 additions & 0 deletions core/project/filter.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package project

import "github.com/raystack/frontier/pkg/pagination"

type Filter struct {
OrgID string
WithMemberCount bool
ProjectIDs []string
State State
// NonInherited filters out projects that are inherited from access given through an organization
NonInherited bool
Pagination *pagination.Pagination
}
2 changes: 1 addition & 1 deletion internal/api/v1beta1/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type OrganizationService interface {

func (h Handler) ListOrganizations(ctx context.Context, request *frontierv1beta1.ListOrganizationsRequest) (*frontierv1beta1.ListOrganizationsResponse, error) {
var orgs []*frontierv1beta1.Organization
paginate := pagination.NewPagination(1, 50)
paginate := pagination.NewPagination(request.GetPageNum(), request.GetPageSize())

orgList, err := h.orgService.List(ctx, organization.Filter{
State: organization.State(request.GetState()),
Expand Down
12 changes: 7 additions & 5 deletions internal/api/v1beta1/org_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ var (
}
)

const DefaultPageSize = 1000

func TestHandler_ListOrganization(t *testing.T) {
table := []struct {
title string
Expand All @@ -54,7 +56,7 @@ func TestHandler_ListOrganization(t *testing.T) {
title: "should return internal error if org service return some error",
setup: func(os *mocks.OrganizationService) {
os.EXPECT().List(mock.AnythingOfType("context.backgroundCtx"), organization.Filter{
Pagination: pagination.NewPagination(1, 50)},
Pagination: pagination.NewPagination(1, DefaultPageSize)},
).Return([]organization.Organization{}, errors.New("test error"))
},
want: nil,
Expand All @@ -68,7 +70,7 @@ func TestHandler_ListOrganization(t *testing.T) {
testOrgList = append(testOrgList, o)
}
os.EXPECT().List(mock.AnythingOfType("context.backgroundCtx"), organization.Filter{
Pagination: pagination.NewPagination(1, 50),
Pagination: pagination.NewPagination(1, DefaultPageSize),
}).Return(testOrgList, nil)
},
want: &frontierv1beta1.ListOrganizationsResponse{Organizations: []*frontierv1beta1.Organization{
Expand Down Expand Up @@ -855,7 +857,7 @@ func TestHandler_ListAllOrganizations(t *testing.T) {
setup: func(os *mocks.OrganizationService) {
os.EXPECT().List(mock.AnythingOfType("context.backgroundCtx"),
organization.Filter{
Pagination: pagination.NewPagination(1, 50),
Pagination: pagination.NewPagination(1, DefaultPageSize),
}).Return([]organization.Organization{}, errors.New("test error"))
},
req: &frontierv1beta1.ListAllOrganizationsRequest{},
Expand All @@ -866,7 +868,7 @@ func TestHandler_ListAllOrganizations(t *testing.T) {
name: "should return empty list of orgs if org service return nil error",
setup: func(os *mocks.OrganizationService) {
os.EXPECT().List(mock.AnythingOfType("context.backgroundCtx"), organization.Filter{
Pagination: pagination.NewPagination(1, 50),
Pagination: pagination.NewPagination(1, DefaultPageSize),
}).Return([]organization.Organization{}, nil)
},
req: &frontierv1beta1.ListAllOrganizationsRequest{},
Expand All @@ -881,7 +883,7 @@ func TestHandler_ListAllOrganizations(t *testing.T) {
testOrgList = append(testOrgList, o)
}
os.EXPECT().List(mock.AnythingOfType("context.backgroundCtx"), organization.Filter{
Pagination: pagination.NewPagination(1, 50),
Pagination: pagination.NewPagination(1, DefaultPageSize),
}).Return(testOrgList, nil)
},
req: &frontierv1beta1.ListAllOrganizationsRequest{},
Expand Down
4 changes: 4 additions & 0 deletions internal/api/v1beta1/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/raystack/frontier/core/organization"
"github.com/raystack/frontier/pkg/pagination"

"github.com/raystack/frontier/core/project"
"github.com/raystack/frontier/core/relation"
Expand Down Expand Up @@ -562,10 +563,12 @@ func (h Handler) ListProjectsByCurrentUser(ctx context.Context, request *frontie
if err != nil {
return nil, err
}
paginate := pagination.NewPagination(request.GetPageNum(), request.GetPageSize())
projList, err := h.projectService.ListByUser(ctx, principal.ID, principal.Type, project.Filter{
OrgID: request.GetOrgId(),
NonInherited: request.GetNonInherited(),
WithMemberCount: request.GetWithMemberCount(),
Pagination: paginate,
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -608,6 +611,7 @@ func (h Handler) ListProjectsByCurrentUser(ctx context.Context, request *frontie
return &frontierv1beta1.ListProjectsByCurrentUserResponse{
Projects: projects,
AccessPairs: accessPairsPb,
Count: paginate.Count,
}, nil
}

Expand Down
24 changes: 24 additions & 0 deletions internal/store/postgres/project_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,30 @@ func (r ProjectRepository) List(ctx context.Context, flt project.Filter) ([]proj
"state": flt.State.String(),
})
}

if flt.Pagination != nil {
offset := flt.Pagination.Offset()
limit := flt.Pagination.PageSize

// always make this call after all the filters have been applied
totalCountStmt := stmt.Select(goqu.COUNT("*"))
totalCountQuery, _, err := totalCountStmt.ToSQL()

if err != nil {
return []project.Project{}, fmt.Errorf("%w: %w", queryErr, err)
}

var totalCount int32
if err = r.dbc.WithTimeout(ctx, TABLE_PROJECTS, "Count", func(ctx context.Context) error {
return r.dbc.GetContext(ctx, &totalCount, totalCountQuery)
}); err != nil {
return nil, fmt.Errorf("%w: %w", dbErr, err)
}

flt.Pagination.SetCount(totalCount)
stmt = stmt.Limit(uint(limit)).Offset(uint(offset)).Order(goqu.C("created_at").Desc())
}

query, params, err := stmt.ToSQL()
if err != nil {
return []project.Project{}, fmt.Errorf("%w: %w", queryErr, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/pagination/pagination.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package pagination

const (
DefaultPageSize = 50
DefaultPageSize = 1000
DefaultPageNum = 1
)

Expand Down
27 changes: 27 additions & 0 deletions proto/apidocs.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2587,6 +2587,18 @@ paths:
in: query
required: false
type: string
- name: page_size
description: The maximum number of users to return per page. The default is 50.
in: query
required: false
type: integer
format: int32
- name: page_num
description: The page number to return. The default is 1.
in: query
required: false
type: integer
format: int32
tags:
- Organization
post:
Expand Down Expand Up @@ -9989,6 +10001,18 @@ paths:
in: query
required: false
type: boolean
- name: page_size
description: The maximum number of users to return per page. The default is 50.
in: query
required: false
type: integer
format: int32
- name: page_num
description: The page number to return. The default is 1.
in: query
required: false
type: integer
format: int32
tags:
- User
definitions:
Expand Down Expand Up @@ -11730,6 +11754,9 @@ definitions:
items:
type: object
$ref: '#/definitions/v1beta1ListProjectsByCurrentUserResponseAccessPair'
count:
type: integer
format: int32
v1beta1ListProjectsByCurrentUserResponseAccessPair:
type: object
properties:
Expand Down
Loading

0 comments on commit e065480

Please sign in to comment.