Skip to content

Commit

Permalink
feat(pagination): move pagination and sorting image summary results a…
Browse files Browse the repository at this point in the history
…fter conversion

Signed-off-by: Laurentiu Niculae <[email protected]>
  • Loading branch information
laurentiuNiculae committed Jul 26, 2023
1 parent abba6aa commit d73b8c8
Show file tree
Hide file tree
Showing 30 changed files with 1,995 additions and 3,092 deletions.
4 changes: 2 additions & 2 deletions pkg/cli/search_cmd_referrers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import (
)

func ref[T any](input T) *T {
obj := input
ref := input

return &obj
return &ref
}

const (
Expand Down
11 changes: 11 additions & 0 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io/fs"
"os"
"strings"
"syscall"
"time"
"unicode/utf8"
Expand Down Expand Up @@ -101,3 +102,13 @@ func MarshalThroughStruct(obj interface{}, throughStruct interface{}) ([]byte, e

return toJSON, nil
}

func ContainsString(strSlice []string, str string) bool {
for _, val := range strSlice {
if strings.EqualFold(val, str) {
return true
}
}

return false
}
164 changes: 164 additions & 0 deletions pkg/common/pagination/image_pagination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package pagination

import (
"fmt"
"sort"
"time"

zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
gql_gen "zotregistry.io/zot/pkg/extensions/search/gql_generated"
)

type ImageSummariesPageFinder struct {
limit int
offset int
sortBy SortCriteria
pageBuffer []*gql_gen.ImageSummary
}

func NewImgSumPageFinder(limit, offset int, sortBy SortCriteria) (*ImageSummariesPageFinder, error) {
if sortBy == "" {
sortBy = AlphabeticAsc
}

if limit < 0 {
return nil, zerr.ErrLimitIsNegative
}

if offset < 0 {
return nil, zerr.ErrOffsetIsNegative
}

if _, found := ImgSumSortFuncs()[sortBy]; !found {
return nil, fmt.Errorf("sorting repos by '%s' is not supported %w",
sortBy, zerr.ErrSortCriteriaNotSupported)
}

return &ImageSummariesPageFinder{
limit: limit,
offset: offset,
sortBy: sortBy,
pageBuffer: []*gql_gen.ImageSummary{},
}, nil
}

func (pf *ImageSummariesPageFinder) Add(imgSum *gql_gen.ImageSummary) {
pf.pageBuffer = append(pf.pageBuffer, imgSum)
}

func (pf *ImageSummariesPageFinder) Page() ([]*gql_gen.ImageSummary, zcommon.PageInfo) {
if len(pf.pageBuffer) == 0 {
return []*gql_gen.ImageSummary{}, zcommon.PageInfo{}
}

pageInfo := zcommon.PageInfo{}

sort.Slice(pf.pageBuffer, ImgSumSortFuncs()[pf.sortBy](pf.pageBuffer))

// the offset and limit are calculated in terms of repos counted
start := pf.offset
end := pf.offset + pf.limit

// we'll return an empty array when the offset is greater than the number of elements
if start >= len(pf.pageBuffer) {
start = len(pf.pageBuffer)
end = start
}

if end >= len(pf.pageBuffer) {
end = len(pf.pageBuffer)
}

page := pf.pageBuffer[start:end]

pageInfo.ItemCount = len(page)

if start == 0 && end == 0 {
page = pf.pageBuffer
pageInfo.ItemCount = len(page)
}

pageInfo.TotalCount = len(pf.pageBuffer)

return page, pageInfo
}

func ImgSumSortFuncs() map[SortCriteria]func(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
return map[SortCriteria]func(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool{
AlphabeticAsc: ImgSortByAlphabeticAsc,
AlphabeticDsc: ImgSortByAlphabeticDsc,
UpdateTime: ImgSortByUpdateTime,
Relevance: ImgSortByRelevance,
Downloads: ImgSortByDownloads,
}
}

func ImgSortByAlphabeticAsc(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
return func(i, j int) bool { //nolint: varnamelen
if *pageBuffer[i].RepoName < *pageBuffer[j].RepoName {
return true
}

if *pageBuffer[i].RepoName == *pageBuffer[j].RepoName {
return *pageBuffer[i].Tag < *pageBuffer[j].Tag
}

return false
}
}

func ImgSortByAlphabeticDsc(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
return func(i, j int) bool { //nolint: varnamelen
if *pageBuffer[i].RepoName > *pageBuffer[j].RepoName {
return true
}

if *pageBuffer[i].RepoName == *pageBuffer[j].RepoName {
return *pageBuffer[i].Tag > *pageBuffer[j].Tag
}

return false
}
}

func ImgSortByRelevance(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
return func(i, j int) bool { //nolint: varnamelen
if *pageBuffer[i].RepoName < *pageBuffer[j].RepoName {
return true
}

if *pageBuffer[i].RepoName == *pageBuffer[j].RepoName {
return *pageBuffer[i].Tag < *pageBuffer[j].Tag
}

return false
}
}

// SortByUpdateTime sorting descending by time.
func ImgSortByUpdateTime(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
repos2LastUpdated := map[string]time.Time{}

for _, img := range pageBuffer {
lastUpdated, ok := repos2LastUpdated[*img.RepoName]

if !ok || lastUpdated.Before(*img.LastUpdated) {
repos2LastUpdated[*img.RepoName] = *img.LastUpdated
}
}

return func(i, j int) bool {
iRepoTime, jRepoTime := repos2LastUpdated[*pageBuffer[i].RepoName], repos2LastUpdated[*pageBuffer[j].RepoName]

return (iRepoTime.After(jRepoTime) || iRepoTime.Equal(jRepoTime)) &&
pageBuffer[i].LastUpdated.After(*pageBuffer[j].LastUpdated)
}
}

// SortByDownloads returns a comparison function for descendant sorting by downloads.
func ImgSortByDownloads(pageBuffer []*gql_gen.ImageSummary) func(i, j int) bool {
return func(i, j int) bool {
return *pageBuffer[i].DownloadCount > *pageBuffer[j].DownloadCount
}
}
18 changes: 18 additions & 0 deletions pkg/common/pagination/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package pagination

type SortCriteria string

type PageInput struct {
Limit int
Offset int
SortBy SortCriteria
}

const (
Relevance = SortCriteria("RELEVANCE")
UpdateTime = SortCriteria("UPDATE_TIME")
AlphabeticAsc = SortCriteria("ALPHABETIC_ASC")
AlphabeticDsc = SortCriteria("ALPHABETIC_DSC")
Stars = SortCriteria("STARS")
Downloads = SortCriteria("DOWNLOADS")
)
Loading

0 comments on commit d73b8c8

Please sign in to comment.