satellite/console: Add pagination fields for ListProjectsByOwnerID
Add ProjectsCursor type for pagination Add PageCount, CurrentPage, and TotalCount ProjectsPage This allows us to mimic the logic of GetBucketTotals and the implementation of BucketUsages in graphql for the new ProjectsByOwnerID functionality. Change-Id: I4e1613859085db65971b44fcacd9813d9ddad8eb
This commit is contained in:
parent
e6c0383477
commit
0a48071854
@ -34,7 +34,7 @@ type Projects interface {
|
||||
// List returns paginated projects, created before provided timestamp.
|
||||
List(ctx context.Context, offset int64, limit int, before time.Time) (ProjectsPage, error)
|
||||
// ListByOwnerID is a method for querying all projects from the database by ownerID. It also includes the number of members for each project.
|
||||
ListByOwnerID(ctx context.Context, userID uuid.UUID, limit int, offset int64) (ProjectsPage, error)
|
||||
ListByOwnerID(ctx context.Context, userID uuid.UUID, cursor ProjectsCursor) (ProjectsPage, error)
|
||||
|
||||
// UpdateRateLimit is a method for updating projects rate limit.
|
||||
UpdateRateLimit(ctx context.Context, id uuid.UUID, newLimit int) error
|
||||
@ -67,6 +67,13 @@ type ProjectInfo struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// ProjectsCursor holds info for project
|
||||
// cursor pagination.
|
||||
type ProjectsCursor struct {
|
||||
Limit int
|
||||
Page int
|
||||
}
|
||||
|
||||
// ProjectsPage returns paginated projects,
|
||||
// providing next offset if there are more projects
|
||||
// to retrieve.
|
||||
@ -74,6 +81,13 @@ type ProjectsPage struct {
|
||||
Projects []Project
|
||||
Next bool
|
||||
NextOffset int64
|
||||
|
||||
Limit int
|
||||
Offset int64
|
||||
|
||||
PageCount int
|
||||
CurrentPage int
|
||||
TotalCount int64
|
||||
}
|
||||
|
||||
// ValidateNameAndDescription validates project name and description strings.
|
||||
|
@ -228,7 +228,7 @@ func TestProjectsList(t *testing.T) {
|
||||
}
|
||||
|
||||
require.False(t, projsPage.Next)
|
||||
require.Equal(t, int64(0), projsPage.NextOffset)
|
||||
require.EqualValues(t, 0, projsPage.NextOffset)
|
||||
require.Equal(t, length, len(projectsList))
|
||||
require.Empty(t, cmp.Diff(projects[0], projectsList[0],
|
||||
cmp.Transformer("Sort", func(xs []console.Project) []console.Project {
|
||||
@ -243,8 +243,9 @@ func TestProjectsList(t *testing.T) {
|
||||
|
||||
func TestProjectsListByOwner(t *testing.T) {
|
||||
const (
|
||||
limit = 5
|
||||
length = limit*4 - 1 // make length offset from page size so we can test incomplete page at end
|
||||
limit = 5
|
||||
length = limit*4 - 1 // make length offset from page size so we can test incomplete page at end
|
||||
totalPages = 4
|
||||
)
|
||||
|
||||
rateLimit := 100
|
||||
@ -333,23 +334,34 @@ func TestProjectsListByOwner(t *testing.T) {
|
||||
{id: owner2.ID, originalProjects: owner2Projects},
|
||||
}
|
||||
for _, tt := range testCases {
|
||||
projsPage, err := projectsDB.ListByOwnerID(ctx, tt.id, limit, 0)
|
||||
cursor := &console.ProjectsCursor{
|
||||
Limit: limit,
|
||||
Page: 1,
|
||||
}
|
||||
projsPage, err := projectsDB.ListByOwnerID(ctx, tt.id, *cursor)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, projsPage.Projects, limit)
|
||||
require.EqualValues(t, 1, projsPage.CurrentPage)
|
||||
require.EqualValues(t, totalPages, projsPage.PageCount)
|
||||
require.EqualValues(t, length, projsPage.TotalCount)
|
||||
|
||||
ownerProjectsDB := projsPage.Projects
|
||||
|
||||
for projsPage.Next {
|
||||
projsPage, err = projectsDB.ListByOwnerID(ctx, tt.id, limit, projsPage.NextOffset)
|
||||
cursor.Page++
|
||||
projsPage, err = projectsDB.ListByOwnerID(ctx, tt.id, *cursor)
|
||||
require.NoError(t, err)
|
||||
// number of projects should not exceed page limit
|
||||
require.True(t, len(projsPage.Projects) > 0 && len(projsPage.Projects) <= limit)
|
||||
require.EqualValues(t, cursor.Page, projsPage.CurrentPage)
|
||||
require.EqualValues(t, totalPages, projsPage.PageCount)
|
||||
require.EqualValues(t, length, projsPage.TotalCount)
|
||||
|
||||
ownerProjectsDB = append(ownerProjectsDB, projsPage.Projects...)
|
||||
}
|
||||
|
||||
require.False(t, projsPage.Next)
|
||||
require.Equal(t, int64(0), projsPage.NextOffset)
|
||||
require.EqualValues(t, 0, projsPage.NextOffset)
|
||||
require.Equal(t, length, len(ownerProjectsDB))
|
||||
// sort originalProjects by Name in alphabetical order
|
||||
originalProjects := tt.originalProjects
|
||||
|
@ -203,10 +203,34 @@ func (projects *projects) List(ctx context.Context, offset int64, limit int, bef
|
||||
}
|
||||
|
||||
// ListByOwnerID is a method for querying all projects from the database by ownerID. It also includes the number of members for each project.
|
||||
func (projects *projects) ListByOwnerID(ctx context.Context, ownerID uuid.UUID, limit int, offset int64) (_ console.ProjectsPage, err error) {
|
||||
// cursor.Limit is set to 50 if it exceeds 50.
|
||||
func (projects *projects) ListByOwnerID(ctx context.Context, ownerID uuid.UUID, cursor console.ProjectsCursor) (_ console.ProjectsPage, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
var page console.ProjectsPage
|
||||
if cursor.Limit > 50 {
|
||||
cursor.Limit = 50
|
||||
}
|
||||
if cursor.Page == 0 {
|
||||
return console.ProjectsPage{}, errs.New("page can not be 0")
|
||||
}
|
||||
|
||||
page := console.ProjectsPage{
|
||||
CurrentPage: cursor.Page,
|
||||
Limit: cursor.Limit,
|
||||
Offset: int64((cursor.Page - 1) * cursor.Limit),
|
||||
}
|
||||
|
||||
countRow := projects.sdb.QueryRowContext(ctx, projects.sdb.Rebind(`
|
||||
SELECT COUNT(*) FROM projects WHERE owner_id = ?
|
||||
`), ownerID)
|
||||
err = countRow.Scan(&page.TotalCount)
|
||||
if err != nil {
|
||||
return console.ProjectsPage{}, err
|
||||
}
|
||||
page.PageCount = int(page.TotalCount / int64(cursor.Limit))
|
||||
if page.TotalCount%int64(cursor.Limit) != 0 {
|
||||
page.PageCount++
|
||||
}
|
||||
|
||||
rows, err := projects.sdb.Query(ctx, projects.sdb.Rebind(`
|
||||
SELECT id, name, description, owner_id, rate_limit, max_buckets, created_at,
|
||||
@ -216,20 +240,20 @@ func (projects *projects) ListByOwnerID(ctx context.Context, ownerID uuid.UUID,
|
||||
ORDER BY name ASC
|
||||
OFFSET ? ROWS
|
||||
LIMIT ?
|
||||
`), ownerID, offset, limit+1) // add 1 to limit to see if there is another page
|
||||
`), ownerID, page.Offset, page.Limit+1) // add 1 to limit to see if there is another page
|
||||
if err != nil {
|
||||
return console.ProjectsPage{}, err
|
||||
}
|
||||
defer func() { err = errs.Combine(err, rows.Close()) }()
|
||||
|
||||
count := 0
|
||||
projectsToSend := make([]console.Project, 0, limit)
|
||||
projectsToSend := make([]console.Project, 0, page.Limit)
|
||||
for rows.Next() {
|
||||
count++
|
||||
if count == limit+1 {
|
||||
if count == page.Limit+1 {
|
||||
// we are done with this page; do not include this project
|
||||
page.Next = true
|
||||
page.NextOffset = offset + int64(limit)
|
||||
page.NextOffset = page.Offset + int64(page.Limit)
|
||||
break
|
||||
}
|
||||
var rateLimit, maxBuckets sql.NullInt32
|
||||
|
Loading…
Reference in New Issue
Block a user