feat(repodb): add PageInfo to GlobalSearch and RepoListWithNewestImage results (#1121)

Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>

add page info to dynamo-> feat(repodb): add PageInfo to GlobalSearch and RepoListWithNewestImage results

(cherry picked from commit 4fed42bb4bbc68199281d9d9a4e09b97fbd4759b)
Signed-off-by: Andrei Aaron <aaaron@luxoft.com>

Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>
Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
Co-authored-by: Alex Stan <alexandrustan96@yahoo.ro>
This commit is contained in:
Andrei Aaron
2023-01-19 00:20:55 +02:00
committed by GitHub
parent d960c2e23f
commit b997176363
17 changed files with 1073 additions and 388 deletions
+373 -123
View File
@@ -116,15 +116,21 @@ type GlobalSearch struct {
Images []common.ImageSummary `json:"images"`
Repos []common.RepoSummary `json:"repos"`
Layers []common.LayerSummary `json:"layers"`
Page repodb.PageInfo `json:"page"`
}
type ExpandedRepoInfo struct {
RepoInfo common.RepoInfo `json:"expandedRepoInfo"`
}
type PaginatedReposResult struct {
Results []common.RepoSummary `json:"results"`
Page repodb.PageInfo `json:"page"`
}
//nolint:tagliatelle // graphQL schema
type RepoListWithNewestImage struct {
Repos []common.RepoSummary `json:"RepoListWithNewestImage"`
PaginatedReposResult `json:"RepoListWithNewestImage"`
}
type ErrorGQL struct {
@@ -332,136 +338,241 @@ func TestRepoListWithNewestImage(t *testing.T) {
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 422)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.Repos), ShouldEqual, 4)
images := responseStruct.RepoListWithNewestImage.Repos
So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
query := `{
RepoListWithNewestImage(requestedPage: {
limit:1
offset:0
sortBy: UPDATE_TIME
}){
Name
NewestImage{
Tag
Convey("Test repoListWithNewestImage with pagination", func() {
query := `{
RepoListWithNewestImage(requestedPage:{
limit: 2
offset: 0
sortBy: UPDATE_TIME
}){
Page{
ItemCount
TotalCount
}
Results{
Name
NewestImage{
Tag
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 2)
So(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Page.ItemCount, ShouldEqual, 2)
So(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Page.TotalCount, ShouldEqual, 4)
})
Convey("Test repoListWithNewestImage with pagination, no limit or offset", func() {
query := `{
RepoListWithNewestImage(requestedPage:{
limit: 0
offset: 0
sortBy: UPDATE_TIME
}){
Page{
ItemCount
TotalCount
}
Results{
Name
NewestImage{
Tag
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 4)
So(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Page.ItemCount, ShouldEqual, 4)
So(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Page.TotalCount, ShouldEqual, 4)
})
Convey("Test repoListWithNewestImage multiple", func() {
query := `{RepoListWithNewestImage{
Results{
Name
NewestImage{
Tag
}
}
}}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 4)
images := responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results
So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
query = `{
RepoListWithNewestImage(requestedPage: {
limit: 1
offset: 0
sortBy: UPDATE_TIME
}){
Results{
Name
NewestImage{
Tag
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 1)
repos := responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results
So(repos[0].NewestImage.Tag, ShouldEqual, "0.0.1")
query = `{
RepoListWithNewestImage{
Results{
Name
NewestImage{
Tag
Vulnerabilities{
MaxSeverity
Count
}
}
}
}
}`
// Verify we don't return any vulnerabilities if CVE scanning is disabled
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 4)
images = responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results
So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
So(images[0].NewestImage.Vulnerabilities.Count, ShouldEqual, 0)
So(images[0].NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "")
query = `{
RepoListWithNewestImage{
Results{
Name
NewestImage{
Tag
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
err = os.Chmod(rootDir, 0o000)
if err != nil {
panic(err)
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.Repos), ShouldEqual, 1)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
repos := responseStruct.RepoListWithNewestImage.Repos
So(repos[0].NewestImage.Tag, ShouldEqual, "0.0.1")
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(responseStruct.Errors, ShouldBeNil) // Even if permissions fail data is coming from the DB
// Verify we don't return any vulnerabilities if CVE scanning is disabled
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag%20Vulnerabilities{MaxSeverity%20Count}}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = os.Chmod(rootDir, 0o755)
if err != nil {
panic(err)
}
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.Repos), ShouldEqual, 4)
var manifestDigest godigest.Digest
var configDigest godigest.Digest
manifestDigest, configDigest, _ = GetOciLayoutDigests("../../../../test/data/zot-test")
images = responseStruct.RepoListWithNewestImage.Repos
So(images[0].NewestImage.Tag, ShouldEqual, "0.0.1")
So(images[0].NewestImage.Vulnerabilities.Count, ShouldEqual, 0)
So(images[0].NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "")
// Delete config blob and try.
err = os.Remove(path.Join(subRootDir, "a/zot-test/blobs/sha256", configDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = os.Chmod(rootDir, 0o000)
if err != nil {
panic(err)
}
err = os.Remove(path.Join(subRootDir, "a/zot-test/blobs/sha256",
manifestDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(responseStruct.Errors, ShouldBeNil) // Even if permissions fail data is coming from the DB
err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", configDigest.Encoded()))
if err != nil {
panic(err)
}
err = os.Chmod(rootDir, 0o755)
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
var manifestDigest godigest.Digest
var configDigest godigest.Digest
manifestDigest, configDigest, _ = GetOciLayoutDigests("../../../../test/data/zot-test")
// Delete manifest blob also and try
err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", manifestDigest.Encoded()))
if err != nil {
panic(err)
}
// Delete config blob and try.
err = os.Remove(path.Join(subRootDir, "a/zot-test/blobs/sha256", configDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = os.Remove(path.Join(subRootDir, "a/zot-test/blobs/sha256",
manifestDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", configDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
// Delete manifest blob also and try
err = os.Remove(path.Join(rootDir, "zot-test/blobs/sha256", manifestDigest.Encoded()))
if err != nil {
panic(err)
}
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query={RepoListWithNewestImage{Name%20NewestImage{Tag}}}")
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix +
"?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
})
})
Convey("Test repoListWithNewestImage with vulnerability scan enabled", t, func() {
@@ -534,8 +645,21 @@ func TestRepoListWithNewestImage(t *testing.T) {
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 422)
query := "?query={RepoListWithNewestImage{Name%20NewestImage{Tag%20Vulnerabilities{MaxSeverity%20Count}}}}"
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + query)
query := `{
RepoListWithNewestImage{
Results{
Name
NewestImage{
Tag
Vulnerabilities{
MaxSeverity
Count
}
}
}
}
}`
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
@@ -543,9 +667,9 @@ func TestRepoListWithNewestImage(t *testing.T) {
var responseStruct RepoWithNewestImageResponse
err = json.Unmarshal(resp.Body(), &responseStruct)
So(err, ShouldBeNil)
So(len(responseStruct.RepoListWithNewestImage.Repos), ShouldEqual, 4)
So(len(responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results), ShouldEqual, 4)
repos := responseStruct.RepoListWithNewestImage.Repos
repos := responseStruct.RepoListWithNewestImage.PaginatedReposResult.Results
So(repos[0].NewestImage.Tag, ShouldEqual, "0.0.1")
for _, repo := range repos {
@@ -3254,7 +3378,7 @@ func TestGlobalSearchPagination(t *testing.T) {
defer stopServer(ctlr)
WaitTillServerReady(baseURL)
for i := 0; i < 1; i++ {
for i := 0; i < 3; i++ {
config, layers, manifest, err := GetImageComponents(10)
So(err, ShouldBeNil)
@@ -3295,7 +3419,133 @@ func TestGlobalSearchPagination(t *testing.T) {
So(responseStruct.GlobalSearchResult.GlobalSearch.Repos, ShouldNotBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 1)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 3)
})
Convey("Limit is lower than the repo count", func() {
query := `
{
GlobalSearch(query:"repo", requestedPage:{limit: 2, offset: 0, sortBy:RELEVANCE}){
Repos {
Name
}
}
}`
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
responseStruct := &GlobalSearchResultResp{}
err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.GlobalSearchResult.GlobalSearch.Images, ShouldBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Repos, ShouldNotBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 2)
})
Convey("PageInfo returned proper response", func() {
query := `
{
GlobalSearch(query:"repo", requestedPage:{limit: 2, offset: 0, sortBy:RELEVANCE}){
Repos {
Name
}
Page{
ItemCount
TotalCount
}
}
}`
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
responseStruct := &GlobalSearchResultResp{}
err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.GlobalSearchResult.GlobalSearch.Images, ShouldBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Repos, ShouldNotBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 2)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.TotalCount, ShouldEqual, 3)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.ItemCount, ShouldEqual, 2)
})
Convey("PageInfo when limit is bigger than the repo count", func() {
query := `
{
GlobalSearch(query:"repo", requestedPage:{limit: 9, offset: 0, sortBy:RELEVANCE}){
Repos {
Name
}
Page{
ItemCount
TotalCount
}
}
}`
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
responseStruct := &GlobalSearchResultResp{}
err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.GlobalSearchResult.GlobalSearch.Images, ShouldBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Repos, ShouldNotBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 3)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.TotalCount, ShouldEqual, 3)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.ItemCount, ShouldEqual, 3)
})
Convey("PageInfo when limit and offset have 0 value", func() {
query := `
{
GlobalSearch(query:"repo", requestedPage:{limit: 0, offset: 0, sortBy:RELEVANCE}){
Repos {
Name
}
Page{
ItemCount
TotalCount
}
}
}`
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
responseStruct := &GlobalSearchResultResp{}
err = json.Unmarshal(resp.Body(), responseStruct)
So(err, ShouldBeNil)
So(responseStruct.GlobalSearchResult.GlobalSearch.Images, ShouldBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Repos, ShouldNotBeEmpty)
So(responseStruct.GlobalSearchResult.GlobalSearch.Layers, ShouldBeEmpty)
So(len(responseStruct.GlobalSearchResult.GlobalSearch.Repos), ShouldEqual, 3)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.TotalCount, ShouldEqual, 3)
So(responseStruct.GlobalSearchResult.GlobalSearch.Page.ItemCount, ShouldEqual, 3)
})
})
}
@@ -52,7 +52,8 @@ func TestConvertErrors(t *testing.T) {
err = repoDB.SetRepoTag("repo1", "0.1.0", digest11, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
repoMetas, manifestMetaMap, err := repoDB.SearchRepos(context.Background(), "", repodb.Filter{}, repodb.PageInput{})
repoMetas, manifestMetaMap, _, err := repoDB.SearchRepos(context.Background(), "", repodb.Filter{},
repodb.PageInput{})
So(err, ShouldBeNil)
ctx := graphql.WithResponseContext(context.Background(),
+389 -89
View File
@@ -128,10 +128,18 @@ type ComplexityRoot struct {
}
PageInfo struct {
NextPage func(childComplexity int) int
ObjectCount func(childComplexity int) int
Pages func(childComplexity int) int
PreviousPage func(childComplexity int) int
ItemCount func(childComplexity int) int
TotalCount func(childComplexity int) int
}
PaginatedImagesResult struct {
Page func(childComplexity int) int
Results func(childComplexity int) int
}
PaginatedReposResult struct {
Page func(childComplexity int) int
Results func(childComplexity int) int
}
Query struct {
@@ -182,7 +190,7 @@ type QueryResolver interface {
ImageListForCve(ctx context.Context, id string) ([]*ImageSummary, error)
ImageListWithCVEFixed(ctx context.Context, id string, image string) ([]*ImageSummary, error)
ImageListForDigest(ctx context.Context, id string, requestedPage *PageInput) ([]*ImageSummary, error)
RepoListWithNewestImage(ctx context.Context, requestedPage *PageInput) ([]*RepoSummary, error)
RepoListWithNewestImage(ctx context.Context, requestedPage *PageInput) (*PaginatedReposResult, error)
ImageList(ctx context.Context, repo string) ([]*ImageSummary, error)
ExpandedRepoInfo(ctx context.Context, repo string) (*RepoInfo, error)
GlobalSearch(ctx context.Context, query string, filter *Filter, requestedPage *PageInput) (*GlobalSearchResult, error)
@@ -564,33 +572,47 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.PackageInfo.Name(childComplexity), true
case "PageInfo.NextPage":
if e.complexity.PageInfo.NextPage == nil {
case "PageInfo.ItemCount":
if e.complexity.PageInfo.ItemCount == nil {
break
}
return e.complexity.PageInfo.NextPage(childComplexity), true
return e.complexity.PageInfo.ItemCount(childComplexity), true
case "PageInfo.ObjectCount":
if e.complexity.PageInfo.ObjectCount == nil {
case "PageInfo.TotalCount":
if e.complexity.PageInfo.TotalCount == nil {
break
}
return e.complexity.PageInfo.ObjectCount(childComplexity), true
return e.complexity.PageInfo.TotalCount(childComplexity), true
case "PageInfo.Pages":
if e.complexity.PageInfo.Pages == nil {
case "PaginatedImagesResult.Page":
if e.complexity.PaginatedImagesResult.Page == nil {
break
}
return e.complexity.PageInfo.Pages(childComplexity), true
return e.complexity.PaginatedImagesResult.Page(childComplexity), true
case "PageInfo.PreviousPage":
if e.complexity.PageInfo.PreviousPage == nil {
case "PaginatedImagesResult.Results":
if e.complexity.PaginatedImagesResult.Results == nil {
break
}
return e.complexity.PageInfo.PreviousPage(childComplexity), true
return e.complexity.PaginatedImagesResult.Results(childComplexity), true
case "PaginatedReposResult.Page":
if e.complexity.PaginatedReposResult.Page == nil {
break
}
return e.complexity.PaginatedReposResult.Page(childComplexity), true
case "PaginatedReposResult.Results":
if e.complexity.PaginatedReposResult.Results == nil {
break
}
return e.complexity.PaginatedReposResult.Results(childComplexity), true
case "Query.BaseImageList":
if e.complexity.Query.BaseImageList == nil {
@@ -1086,10 +1108,8 @@ enum SortCriteria {
}
type PageInfo {
ObjectCount: Int!
PreviousPage: Int
NextPage: Int
Pages: Int
TotalCount: Int!
ItemCount: Int!
}
# Pagination parameters
@@ -1099,6 +1119,20 @@ input PageInput {
sortBy: SortCriteria
}
# Paginated list of RepoSummary objects
# If limit is -1, pagination is disabled
type PaginatedReposResult {
Page: PageInfo
Results: [RepoSummary!]!
}
# Paginated list of ImageSummary objects
# If limit is -1, pagination is disabled
type PaginatedImagesResult {
Page: PageInfo
Results: [ImageSummary!]!
}
input Filter {
Os: [String]
Arch: [String]
@@ -1129,7 +1163,7 @@ type Query {
"""
Returns a list of repos with the newest tag within
"""
RepoListWithNewestImage(requestedPage: PageInput): [RepoSummary!]! # Newest based on created timestamp
RepoListWithNewestImage(requestedPage: PageInput): PaginatedReposResult! # Newest based on created timestamp
"""
Returns all the images from the specified repo
@@ -1887,14 +1921,10 @@ func (ec *executionContext) fieldContext_GlobalSearchResult_Page(ctx context.Con
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "ObjectCount":
return ec.fieldContext_PageInfo_ObjectCount(ctx, field)
case "PreviousPage":
return ec.fieldContext_PageInfo_PreviousPage(ctx, field)
case "NextPage":
return ec.fieldContext_PageInfo_NextPage(ctx, field)
case "Pages":
return ec.fieldContext_PageInfo_Pages(ctx, field)
case "TotalCount":
return ec.fieldContext_PageInfo_TotalCount(ctx, field)
case "ItemCount":
return ec.fieldContext_PageInfo_ItemCount(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name)
},
@@ -3705,8 +3735,8 @@ func (ec *executionContext) fieldContext_PackageInfo_FixedVersion(ctx context.Co
return fc, nil
}
func (ec *executionContext) _PageInfo_ObjectCount(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_ObjectCount(ctx, field)
func (ec *executionContext) _PageInfo_TotalCount(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_TotalCount(ctx, field)
if err != nil {
return graphql.Null
}
@@ -3719,7 +3749,7 @@ func (ec *executionContext) _PageInfo_ObjectCount(ctx context.Context, field gra
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ObjectCount, nil
return obj.TotalCount, nil
})
if err != nil {
ec.Error(ctx, err)
@@ -3736,7 +3766,7 @@ func (ec *executionContext) _PageInfo_ObjectCount(ctx context.Context, field gra
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PageInfo_ObjectCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_PageInfo_TotalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PageInfo",
Field: field,
@@ -3749,8 +3779,8 @@ func (ec *executionContext) fieldContext_PageInfo_ObjectCount(ctx context.Contex
return fc, nil
}
func (ec *executionContext) _PageInfo_PreviousPage(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_PreviousPage(ctx, field)
func (ec *executionContext) _PageInfo_ItemCount(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_ItemCount(ctx, field)
if err != nil {
return graphql.Null
}
@@ -3763,21 +3793,24 @@ func (ec *executionContext) _PageInfo_PreviousPage(ctx context.Context, field gr
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.PreviousPage, nil
return obj.ItemCount, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*int)
res := resTmp.(int)
fc.Result = res
return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PageInfo_PreviousPage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_PageInfo_ItemCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PageInfo",
Field: field,
@@ -3790,8 +3823,8 @@ func (ec *executionContext) fieldContext_PageInfo_PreviousPage(ctx context.Conte
return fc, nil
}
func (ec *executionContext) _PageInfo_NextPage(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_NextPage(ctx, field)
func (ec *executionContext) _PaginatedImagesResult_Page(ctx context.Context, field graphql.CollectedField, obj *PaginatedImagesResult) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PaginatedImagesResult_Page(ctx, field)
if err != nil {
return graphql.Null
}
@@ -3804,7 +3837,7 @@ func (ec *executionContext) _PageInfo_NextPage(ctx context.Context, field graphq
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.NextPage, nil
return obj.Page, nil
})
if err != nil {
ec.Error(ctx, err)
@@ -3813,26 +3846,32 @@ func (ec *executionContext) _PageInfo_NextPage(ctx context.Context, field graphq
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*int)
res := resTmp.(*PageInfo)
fc.Result = res
return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
return ec.marshalOPageInfo2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPageInfo(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PageInfo_NextPage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_PaginatedImagesResult_Page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PageInfo",
Object: "PaginatedImagesResult",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
switch field.Name {
case "TotalCount":
return ec.fieldContext_PageInfo_TotalCount(ctx, field)
case "ItemCount":
return ec.fieldContext_PageInfo_ItemCount(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _PageInfo_Pages(ctx context.Context, field graphql.CollectedField, obj *PageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PageInfo_Pages(ctx, field)
func (ec *executionContext) _PaginatedImagesResult_Results(ctx context.Context, field graphql.CollectedField, obj *PaginatedImagesResult) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PaginatedImagesResult_Results(ctx, field)
if err != nil {
return graphql.Null
}
@@ -3845,7 +3884,95 @@ func (ec *executionContext) _PageInfo_Pages(ctx context.Context, field graphql.C
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Pages, nil
return obj.Results, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*ImageSummary)
fc.Result = res
return ec.marshalNImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PaginatedImagesResult_Results(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PaginatedImagesResult",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "RepoName":
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
case "Tag":
return ec.fieldContext_ImageSummary_Tag(ctx, field)
case "Digest":
return ec.fieldContext_ImageSummary_Digest(ctx, field)
case "ConfigDigest":
return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field)
case "LastUpdated":
return ec.fieldContext_ImageSummary_LastUpdated(ctx, field)
case "IsSigned":
return ec.fieldContext_ImageSummary_IsSigned(ctx, field)
case "Size":
return ec.fieldContext_ImageSummary_Size(ctx, field)
case "Platform":
return ec.fieldContext_ImageSummary_Platform(ctx, field)
case "Vendor":
return ec.fieldContext_ImageSummary_Vendor(ctx, field)
case "Score":
return ec.fieldContext_ImageSummary_Score(ctx, field)
case "DownloadCount":
return ec.fieldContext_ImageSummary_DownloadCount(ctx, field)
case "Layers":
return ec.fieldContext_ImageSummary_Layers(ctx, field)
case "Description":
return ec.fieldContext_ImageSummary_Description(ctx, field)
case "Licenses":
return ec.fieldContext_ImageSummary_Licenses(ctx, field)
case "Labels":
return ec.fieldContext_ImageSummary_Labels(ctx, field)
case "Title":
return ec.fieldContext_ImageSummary_Title(ctx, field)
case "Source":
return ec.fieldContext_ImageSummary_Source(ctx, field)
case "Documentation":
return ec.fieldContext_ImageSummary_Documentation(ctx, field)
case "History":
return ec.fieldContext_ImageSummary_History(ctx, field)
case "Vulnerabilities":
return ec.fieldContext_ImageSummary_Vulnerabilities(ctx, field)
case "Authors":
return ec.fieldContext_ImageSummary_Authors(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _PaginatedReposResult_Page(ctx context.Context, field graphql.CollectedField, obj *PaginatedReposResult) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PaginatedReposResult_Page(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Page, nil
})
if err != nil {
ec.Error(ctx, err)
@@ -3854,19 +3981,93 @@ func (ec *executionContext) _PageInfo_Pages(ctx context.Context, field graphql.C
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*int)
res := resTmp.(*PageInfo)
fc.Result = res
return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
return ec.marshalOPageInfo2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPageInfo(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PageInfo_Pages(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_PaginatedReposResult_Page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PageInfo",
Object: "PaginatedReposResult",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
switch field.Name {
case "TotalCount":
return ec.fieldContext_PageInfo_TotalCount(ctx, field)
case "ItemCount":
return ec.fieldContext_PageInfo_ItemCount(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _PaginatedReposResult_Results(ctx context.Context, field graphql.CollectedField, obj *PaginatedReposResult) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PaginatedReposResult_Results(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Results, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.([]*RepoSummary)
fc.Result = res
return ec.marshalNRepoSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummaryᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_PaginatedReposResult_Results(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "PaginatedReposResult",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "Name":
return ec.fieldContext_RepoSummary_Name(ctx, field)
case "LastUpdated":
return ec.fieldContext_RepoSummary_LastUpdated(ctx, field)
case "Size":
return ec.fieldContext_RepoSummary_Size(ctx, field)
case "Platforms":
return ec.fieldContext_RepoSummary_Platforms(ctx, field)
case "Vendors":
return ec.fieldContext_RepoSummary_Vendors(ctx, field)
case "Score":
return ec.fieldContext_RepoSummary_Score(ctx, field)
case "NewestImage":
return ec.fieldContext_RepoSummary_NewestImage(ctx, field)
case "DownloadCount":
return ec.fieldContext_RepoSummary_DownloadCount(ctx, field)
case "StarCount":
return ec.fieldContext_RepoSummary_StarCount(ctx, field)
case "IsBookmarked":
return ec.fieldContext_RepoSummary_IsBookmarked(ctx, field)
case "IsStarred":
return ec.fieldContext_RepoSummary_IsStarred(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type RepoSummary", field.Name)
},
}
return fc, nil
@@ -4247,9 +4448,9 @@ func (ec *executionContext) _Query_RepoListWithNewestImage(ctx context.Context,
}
return graphql.Null
}
res := resTmp.([]*RepoSummary)
res := resTmp.(*PaginatedReposResult)
fc.Result = res
return ec.marshalNRepoSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐRepoSummaryᚄ(ctx, field.Selections, res)
return ec.marshalNPaginatedReposResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedReposResult(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Query_RepoListWithNewestImage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -4260,30 +4461,12 @@ func (ec *executionContext) fieldContext_Query_RepoListWithNewestImage(ctx conte
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "Name":
return ec.fieldContext_RepoSummary_Name(ctx, field)
case "LastUpdated":
return ec.fieldContext_RepoSummary_LastUpdated(ctx, field)
case "Size":
return ec.fieldContext_RepoSummary_Size(ctx, field)
case "Platforms":
return ec.fieldContext_RepoSummary_Platforms(ctx, field)
case "Vendors":
return ec.fieldContext_RepoSummary_Vendors(ctx, field)
case "Score":
return ec.fieldContext_RepoSummary_Score(ctx, field)
case "NewestImage":
return ec.fieldContext_RepoSummary_NewestImage(ctx, field)
case "DownloadCount":
return ec.fieldContext_RepoSummary_DownloadCount(ctx, field)
case "StarCount":
return ec.fieldContext_RepoSummary_StarCount(ctx, field)
case "IsBookmarked":
return ec.fieldContext_RepoSummary_IsBookmarked(ctx, field)
case "IsStarred":
return ec.fieldContext_RepoSummary_IsStarred(ctx, field)
case "Page":
return ec.fieldContext_PaginatedReposResult_Page(ctx, field)
case "Results":
return ec.fieldContext_PaginatedReposResult_Results(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type RepoSummary", field.Name)
return nil, fmt.Errorf("no field named %q was found under type PaginatedReposResult", field.Name)
},
}
defer func() {
@@ -8185,25 +8368,84 @@ func (ec *executionContext) _PageInfo(ctx context.Context, sel ast.SelectionSet,
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("PageInfo")
case "ObjectCount":
case "TotalCount":
out.Values[i] = ec._PageInfo_ObjectCount(ctx, field, obj)
out.Values[i] = ec._PageInfo_TotalCount(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "PreviousPage":
case "ItemCount":
out.Values[i] = ec._PageInfo_PreviousPage(ctx, field, obj)
out.Values[i] = ec._PageInfo_ItemCount(ctx, field, obj)
case "NextPage":
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalids > 0 {
return graphql.Null
}
return out
}
out.Values[i] = ec._PageInfo_NextPage(ctx, field, obj)
var paginatedImagesResultImplementors = []string{"PaginatedImagesResult"}
case "Pages":
func (ec *executionContext) _PaginatedImagesResult(ctx context.Context, sel ast.SelectionSet, obj *PaginatedImagesResult) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, paginatedImagesResultImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("PaginatedImagesResult")
case "Page":
out.Values[i] = ec._PageInfo_Pages(ctx, field, obj)
out.Values[i] = ec._PaginatedImagesResult_Page(ctx, field, obj)
case "Results":
out.Values[i] = ec._PaginatedImagesResult_Results(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalids > 0 {
return graphql.Null
}
return out
}
var paginatedReposResultImplementors = []string{"PaginatedReposResult"}
func (ec *executionContext) _PaginatedReposResult(ctx context.Context, sel ast.SelectionSet, obj *PaginatedReposResult) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, paginatedReposResultImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("PaginatedReposResult")
case "Page":
out.Values[i] = ec._PaginatedReposResult_Page(ctx, field, obj)
case "Results":
out.Values[i] = ec._PaginatedReposResult_Results(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -9049,6 +9291,50 @@ func (ec *executionContext) marshalNGlobalSearchResult2ᚖzotregistryᚗioᚋzot
return ec._GlobalSearchResult(ctx, sel, v)
}
func (ec *executionContext) marshalNImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx context.Context, sel ast.SelectionSet, v []*ImageSummary) graphql.Marshaler {
ret := make(graphql.Array, len(v))
var wg sync.WaitGroup
isLen1 := len(v) == 1
if !isLen1 {
wg.Add(len(v))
}
for i := range v {
i := i
fc := &graphql.FieldContext{
Index: &i,
Result: &v[i],
}
ctx := graphql.WithFieldContext(ctx, fc)
f := func(i int) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = nil
}
}()
if !isLen1 {
defer wg.Done()
}
ret[i] = ec.marshalNImageSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummary(ctx, sel, v[i])
}
if isLen1 {
f(i)
} else {
go f(i)
}
}
wg.Wait()
for _, e := range ret {
if e == graphql.Null {
return graphql.Null
}
}
return ret
}
func (ec *executionContext) marshalNImageSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummary(ctx context.Context, sel ast.SelectionSet, v *ImageSummary) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
@@ -9074,6 +9360,20 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
return res
}
func (ec *executionContext) marshalNPaginatedReposResult2zotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedReposResult(ctx context.Context, sel ast.SelectionSet, v PaginatedReposResult) graphql.Marshaler {
return ec._PaginatedReposResult(ctx, sel, &v)
}
func (ec *executionContext) marshalNPaginatedReposResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedReposResult(ctx context.Context, sel ast.SelectionSet, v *PaginatedReposResult) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._PaginatedReposResult(ctx, sel, v)
}
func (ec *executionContext) marshalNReferrer2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐReferrer(ctx context.Context, sel ast.SelectionSet, v []*Referrer) graphql.Marshaler {
ret := make(graphql.Array, len(v))
var wg sync.WaitGroup
@@ -111,10 +111,8 @@ type PackageInfo struct {
}
type PageInfo struct {
ObjectCount int `json:"ObjectCount"`
PreviousPage *int `json:"PreviousPage"`
NextPage *int `json:"NextPage"`
Pages *int `json:"Pages"`
TotalCount int `json:"TotalCount"`
ItemCount int `json:"ItemCount"`
}
type PageInput struct {
@@ -123,6 +121,16 @@ type PageInput struct {
SortBy *SortCriteria `json:"sortBy"`
}
type PaginatedImagesResult struct {
Page *PageInfo `json:"Page"`
Results []*ImageSummary `json:"Results"`
}
type PaginatedReposResult struct {
Page *PageInfo `json:"Page"`
Results []*RepoSummary `json:"Results"`
}
type Referrer struct {
MediaType *string `json:"MediaType"`
ArtifactType *string `json:"ArtifactType"`
+31 -11
View File
@@ -197,15 +197,16 @@ func repoListWithNewestImage(
log log.Logger, //nolint:unparam // may be used by devs for debugging
requestedPage *gql_generated.PageInput,
repoDB repodb.RepoDB,
) ([]*gql_generated.RepoSummary, error) {
) (*gql_generated.PaginatedReposResult, error) {
repos := []*gql_generated.RepoSummary{}
paginatedRepos := &gql_generated.PaginatedReposResult{}
if requestedPage == nil {
requestedPage = &gql_generated.PageInput{}
}
skip := convert.SkipQGLField{
Vulnerabilities: canSkipField(convert.GetPreloads(ctx), "NewestImage.Vulnerabilities"),
Vulnerabilities: canSkipField(convert.GetPreloads(ctx), "Results.NewestImage.Vulnerabilities"),
}
pageInput := repodb.PageInput{
@@ -216,9 +217,9 @@ func repoListWithNewestImage(
),
}
reposMeta, manifestMetaMap, err := repoDB.SearchRepos(ctx, "", repodb.Filter{}, pageInput)
reposMeta, manifestMetaMap, pageInfo, err := repoDB.SearchRepos(ctx, "", repodb.Filter{}, pageInput)
if err != nil {
return []*gql_generated.RepoSummary{}, err
return &gql_generated.PaginatedReposResult{}, err
}
for _, repoMeta := range reposMeta {
@@ -226,15 +227,22 @@ func repoListWithNewestImage(
repos = append(repos, repoSummary)
}
return repos, nil
paginatedRepos.Page = &gql_generated.PageInfo{
TotalCount: pageInfo.TotalCount,
ItemCount: pageInfo.ItemCount,
}
paginatedRepos.Results = repos
return paginatedRepos, nil
}
func globalSearch(ctx context.Context, query string, repoDB repodb.RepoDB, filter *gql_generated.Filter,
requestedPage *gql_generated.PageInput, cveInfo cveinfo.CveInfo, log log.Logger, //nolint:unparam
) ([]*gql_generated.RepoSummary, []*gql_generated.ImageSummary, []*gql_generated.LayerSummary, error,
) (*gql_generated.PaginatedReposResult, []*gql_generated.ImageSummary, []*gql_generated.LayerSummary, error,
) {
preloads := convert.GetPreloads(ctx)
repos := []*gql_generated.RepoSummary{}
paginatedRepos := gql_generated.PaginatedReposResult{}
images := []*gql_generated.ImageSummary{}
layers := []*gql_generated.LayerSummary{}
@@ -264,9 +272,9 @@ func globalSearch(ctx context.Context, query string, repoDB repodb.RepoDB, filte
),
}
reposMeta, manifestMetaMap, err := repoDB.SearchRepos(ctx, query, localFilter, pageInput)
reposMeta, manifestMetaMap, pageInfo, err := repoDB.SearchRepos(ctx, query, localFilter, pageInput)
if err != nil {
return []*gql_generated.RepoSummary{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
}
for _, repoMeta := range reposMeta {
@@ -274,6 +282,13 @@ func globalSearch(ctx context.Context, query string, repoDB repodb.RepoDB, filte
repos = append(repos, repoSummary)
}
paginatedRepos.Page = &gql_generated.PageInfo{
TotalCount: pageInfo.TotalCount,
ItemCount: pageInfo.ItemCount,
}
paginatedRepos.Results = repos
} else { // search for images
skip := convert.SkipQGLField{
Vulnerabilities: canSkipField(preloads, "Images.Vulnerabilities"),
@@ -287,9 +302,9 @@ func globalSearch(ctx context.Context, query string, repoDB repodb.RepoDB, filte
),
}
reposMeta, manifestMetaMap, err := repoDB.SearchTags(ctx, query, localFilter, pageInput)
reposMeta, manifestMetaMap, pageInfo, err := repoDB.SearchTags(ctx, query, localFilter, pageInput)
if err != nil {
return []*gql_generated.RepoSummary{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
}
for _, repoMeta := range reposMeta {
@@ -297,9 +312,14 @@ func globalSearch(ctx context.Context, query string, repoDB repodb.RepoDB, filte
images = append(images, imageSummaries...)
}
paginatedRepos.Page = &gql_generated.PageInfo{
TotalCount: pageInfo.TotalCount,
ItemCount: pageInfo.ItemCount,
}
}
return repos, images, layers, nil
return &paginatedRepos, images, layers, nil
}
func canSkipField(preloads map[string]bool, s string) bool {
+38 -38
View File
@@ -31,8 +31,8 @@ func TestGlobalSearch(t *testing.T) {
Convey("RepoDB SearchRepos error", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), ErrTestError
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
},
}
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
@@ -43,13 +43,13 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldNotBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
Convey("RepoDB SearchRepo is successful", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
repos := []repodb.RepoMetadata{
{
Name: "repo1",
@@ -101,7 +101,7 @@ func TestGlobalSearch(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
@@ -123,14 +123,14 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldNotBeEmpty)
So(len(repos[0].Vendors), ShouldEqual, 2)
So(repos.Results, ShouldNotBeEmpty)
So(len(repos.Results[0].Vendors), ShouldEqual, 2)
})
Convey("RepoDB SearchRepo Bad manifest referenced", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
repos := []repodb.RepoMetadata{
{
Name: "repo1",
@@ -154,7 +154,7 @@ func TestGlobalSearch(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
@@ -188,13 +188,13 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
Convey("RepoDB SearchRepo good manifest referenced and bad config blob", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
repos := []repodb.RepoMetadata{
{
Name: "repo1",
@@ -218,7 +218,7 @@ func TestGlobalSearch(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
@@ -241,7 +241,7 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldNotBeEmpty)
So(repos.Results, ShouldNotBeEmpty)
query = "repo1:1.0.1"
responseContext = graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
@@ -251,14 +251,14 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
Convey("RepoDB SearchTags gives error", func() {
mockRepoDB := mocks.RepoDBMock{
SearchTagsFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), ErrTestError
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
},
}
const query = "repo1:1.0.1"
@@ -271,13 +271,13 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldNotBeNil)
So(images, ShouldBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
Convey("RepoDB SearchTags is successful", func() {
mockRepoDB := mocks.RepoDBMock{
SearchTagsFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
repos := []repodb.RepoMetadata{
{
Name: "repo1",
@@ -323,7 +323,7 @@ func TestGlobalSearch(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
@@ -346,7 +346,7 @@ func TestGlobalSearch(t *testing.T) {
So(err, ShouldBeNil)
So(images, ShouldNotBeEmpty)
So(layers, ShouldBeEmpty)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
})
}
@@ -356,8 +356,8 @@ func TestRepoListWithNewestImage(t *testing.T) {
Convey("RepoDB SearchRepos error", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), ErrTestError
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
},
}
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
@@ -374,13 +374,13 @@ func TestRepoListWithNewestImage(t *testing.T) {
}
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), &pageInput, mockRepoDB)
So(err, ShouldNotBeNil)
So(repos, ShouldBeEmpty)
So(repos.Results, ShouldBeEmpty)
})
Convey("RepoDB SearchRepo Bad manifest referenced", func() {
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
repos := []repodb.RepoMetadata{
{
Name: "repo1",
@@ -422,7 +422,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
@@ -440,7 +440,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
}
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), &pageInput, mockRepoDB)
So(err, ShouldBeNil)
So(repos, ShouldNotBeEmpty)
So(repos.Results, ShouldNotBeEmpty)
})
Convey("Working SearchRepo function", func() {
@@ -448,7 +448,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
createTime2 := createTime.Add(time.Second)
mockRepoDB := mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
pageFinder, err := repodb.NewBaseRepoPageFinder(requestedPage.Limit, requestedPage.Offset, requestedPage.SortBy)
So(err, ShouldBeNil)
@@ -483,7 +483,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
createTime = createTime.Add(time.Second)
}
repos = pageFinder.Page()
repos, _ = pageFinder.Page()
configBlob1, err := json.Marshal(ispec.Image{
Config: ispec.ImageConfig{
@@ -515,7 +515,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
},
}
return repos, manifestMetas, nil
return repos, manifestMetas, repodb.PageInfo{}, nil
},
}
Convey("RepoDB missing requestedPage", func() {
@@ -524,7 +524,7 @@ func TestRepoListWithNewestImage(t *testing.T) {
mockCve := mocks.CveInfoMock{}
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), nil, mockRepoDB)
So(err, ShouldBeNil)
So(repos, ShouldNotBeEmpty)
So(repos.Results, ShouldNotBeEmpty)
})
Convey("RepoDB SearchRepo is successful", func() {
@@ -545,9 +545,9 @@ func TestRepoListWithNewestImage(t *testing.T) {
log.NewLogger("debug", ""), &pageInput, mockRepoDB)
So(err, ShouldBeNil)
So(repos, ShouldNotBeEmpty)
So(len(repos), ShouldEqual, 2)
So(*repos[0].Name, ShouldEqual, "repo2")
So(*repos[0].LastUpdated, ShouldEqual, createTime2)
So(len(repos.Results), ShouldEqual, 2)
So(*repos.Results[0].Name, ShouldEqual, "repo2")
So(*repos.Results[0].LastUpdated, ShouldEqual, createTime2)
})
})
})
@@ -960,7 +960,7 @@ func TestImageListForDigest(t *testing.T) {
})
}
repos = pageFinder.Page()
repos, _ = pageFinder.Page()
return repos, manifestMetaDatas, nil
},
@@ -1264,8 +1264,8 @@ func TestQueryResolverErrors(t *testing.T) {
mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter,
requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
return nil, nil, ErrTestError
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
return nil, nil, repodb.PageInfo{}, ErrTestError
},
},
mocks.CveInfoMock{},
@@ -1347,8 +1347,8 @@ func TestQueryResolverErrors(t *testing.T) {
mocks.RepoDBMock{
SearchReposFn: func(ctx context.Context, searchText string,
filter repodb.Filter, requestedPage repodb.PageInput,
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
return nil, nil, ErrTestError
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
return nil, nil, repodb.PageInfo{}, ErrTestError
},
},
mocks.CveInfoMock{},
+17 -5
View File
@@ -167,10 +167,8 @@ enum SortCriteria {
}
type PageInfo {
ObjectCount: Int!
PreviousPage: Int
NextPage: Int
Pages: Int
TotalCount: Int!
ItemCount: Int!
}
# Pagination parameters
@@ -180,6 +178,20 @@ input PageInput {
sortBy: SortCriteria
}
# Paginated list of RepoSummary objects
# If limit is -1, pagination is disabled
type PaginatedReposResult {
Page: PageInfo
Results: [RepoSummary!]!
}
# Paginated list of ImageSummary objects
# If limit is -1, pagination is disabled
type PaginatedImagesResult {
Page: PageInfo
Results: [ImageSummary!]!
}
input Filter {
Os: [String]
Arch: [String]
@@ -210,7 +222,7 @@ type Query {
"""
Returns a list of repos with the newest tag within
"""
RepoListWithNewestImage(requestedPage: PageInput): [RepoSummary!]! # Newest based on created timestamp
RepoListWithNewestImage(requestedPage: PageInput): PaginatedReposResult! # Newest based on created timestamp
"""
Returns all the images from the specified repo
+7 -6
View File
@@ -172,17 +172,17 @@ func (r *queryResolver) ImageListForDigest(ctx context.Context, id string, reque
}
// RepoListWithNewestImage is the resolver for the RepoListWithNewestImage field.
func (r *queryResolver) RepoListWithNewestImage(ctx context.Context, requestedPage *gql_generated.PageInput) ([]*gql_generated.RepoSummary, error) {
func (r *queryResolver) RepoListWithNewestImage(ctx context.Context, requestedPage *gql_generated.PageInput) (*gql_generated.PaginatedReposResult, error) {
r.log.Info().Msg("extension api: finding image list")
reposSummary, err := repoListWithNewestImage(ctx, r.cveInfo, r.log, requestedPage, r.repoDB)
paginatedReposResult, err := repoListWithNewestImage(ctx, r.cveInfo, r.log, requestedPage, r.repoDB)
if err != nil {
r.log.Error().Err(err).Msg("unable to retrieve repo list")
return reposSummary, err
return paginatedReposResult, err
}
return reposSummary, nil
return paginatedReposResult, nil
}
// ImageList is the resolver for the ImageList field.
@@ -238,11 +238,12 @@ func (r *queryResolver) GlobalSearch(ctx context.Context, query string, filter *
query = cleanQuery(query)
filter = cleanFilter(filter)
repos, images, layers, err := globalSearch(ctx, query, r.repoDB, filter, requestedPage, r.cveInfo, r.log)
paginatedReposResult, images, layers, err := globalSearch(ctx, query, r.repoDB, filter, requestedPage, r.cveInfo, r.log)
return &gql_generated.GlobalSearchResult{
Page: paginatedReposResult.Page,
Images: images,
Repos: repos,
Repos: paginatedReposResult.Results,
Layers: layers,
}, err
}