0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-01-06 22:40:28 -05:00
zot/pkg/extensions/search/pagination/image_pagination.go
LaurentiuNiculae 9e38ca51e3
feat(pagination): move pagination and sorting image summary results after conversion (#1637)
fix(config): check for config media type when pushing to repodb

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
2023-07-31 22:16:09 +03:00

164 lines
4.2 KiB
Go

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
}
}