zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/search/pagination/repo_pagination.go (about)

     1  package pagination
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	zerr "zotregistry.dev/zot/errors"
     8  	zcommon "zotregistry.dev/zot/pkg/common"
     9  	gql_gen "zotregistry.dev/zot/pkg/extensions/search/gql_generated"
    10  )
    11  
    12  type RepoSummariesPageFinder struct {
    13  	limit      int
    14  	offset     int
    15  	sortBy     SortCriteria
    16  	pageBuffer []*gql_gen.RepoSummary
    17  }
    18  
    19  func NewRepoSumPageFinder(limit, offset int, sortBy SortCriteria) (*RepoSummariesPageFinder, error) {
    20  	if sortBy == "" {
    21  		sortBy = AlphabeticAsc
    22  	}
    23  
    24  	if limit < 0 {
    25  		return nil, zerr.ErrLimitIsNegative
    26  	}
    27  
    28  	if offset < 0 {
    29  		return nil, zerr.ErrOffsetIsNegative
    30  	}
    31  
    32  	if _, found := RepoSumSortFuncs()[sortBy]; !found {
    33  		return nil, fmt.Errorf("sorting repos by '%s' is not supported %w",
    34  			sortBy, zerr.ErrSortCriteriaNotSupported)
    35  	}
    36  
    37  	return &RepoSummariesPageFinder{
    38  		limit:      limit,
    39  		offset:     offset,
    40  		sortBy:     sortBy,
    41  		pageBuffer: []*gql_gen.RepoSummary{},
    42  	}, nil
    43  }
    44  
    45  func (pf *RepoSummariesPageFinder) Add(imgSum *gql_gen.RepoSummary) {
    46  	pf.pageBuffer = append(pf.pageBuffer, imgSum)
    47  }
    48  
    49  func (pf *RepoSummariesPageFinder) Page() ([]*gql_gen.RepoSummary, zcommon.PageInfo) {
    50  	if len(pf.pageBuffer) == 0 {
    51  		return []*gql_gen.RepoSummary{}, zcommon.PageInfo{}
    52  	}
    53  
    54  	pageInfo := zcommon.PageInfo{}
    55  
    56  	sort.Slice(pf.pageBuffer, RepoSumSortFuncs()[pf.sortBy](pf.pageBuffer))
    57  
    58  	// the offset and limit are calculated in terms of repos counted
    59  	start := pf.offset
    60  	end := pf.offset + pf.limit
    61  
    62  	// we'll return an empty array when the offset is greater than the number of elements
    63  	if start >= len(pf.pageBuffer) {
    64  		start = len(pf.pageBuffer)
    65  		end = start
    66  	}
    67  
    68  	if end >= len(pf.pageBuffer) {
    69  		end = len(pf.pageBuffer)
    70  	}
    71  
    72  	page := pf.pageBuffer[start:end]
    73  
    74  	pageInfo.ItemCount = len(page)
    75  
    76  	if start == 0 && end == 0 {
    77  		page = pf.pageBuffer
    78  		pageInfo.ItemCount = len(page)
    79  	}
    80  
    81  	pageInfo.TotalCount = len(pf.pageBuffer)
    82  
    83  	return page, pageInfo
    84  }
    85  
    86  func RepoSumSortFuncs() map[SortCriteria]func(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
    87  	return map[SortCriteria]func(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool{
    88  		AlphabeticAsc: RepoSortByAlphabeticAsc,
    89  		AlphabeticDsc: RepoSortByAlphabeticDsc,
    90  		Relevance:     RepoSortByRelevance,
    91  		UpdateTime:    RepoSortByUpdateTime,
    92  		Downloads:     RepoSortByDownloads,
    93  	}
    94  }
    95  
    96  func RepoSortByAlphabeticAsc(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
    97  	return func(i, j int) bool {
    98  		return *pageBuffer[i].Name < *pageBuffer[j].Name
    99  	}
   100  }
   101  
   102  func RepoSortByAlphabeticDsc(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
   103  	return func(i, j int) bool {
   104  		return *pageBuffer[i].Name > *pageBuffer[j].Name
   105  	}
   106  }
   107  
   108  func RepoSortByRelevance(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
   109  	return func(i, j int) bool {
   110  		return *pageBuffer[i].Rank < *pageBuffer[j].Rank
   111  	}
   112  }
   113  
   114  // SortByUpdateTime sorting descending by time.
   115  func RepoSortByUpdateTime(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
   116  	return func(i, j int) bool {
   117  		return pageBuffer[i].LastUpdated.After(*pageBuffer[j].LastUpdated)
   118  	}
   119  }
   120  
   121  // SortByDownloads returns a comparison function for descendant sorting by downloads.
   122  func RepoSortByDownloads(pageBuffer []*gql_gen.RepoSummary) func(i, j int) bool {
   123  	return func(i, j int) bool {
   124  		return *pageBuffer[i].DownloadCount > *pageBuffer[j].DownloadCount
   125  	}
   126  }