From cce3d05c173ffd2ba62c5ad98f5d27cb7048f2b8 Mon Sep 17 00:00:00 2001 From: guacamole Date: Wed, 30 Mar 2022 01:28:32 +0530 Subject: [PATCH] Add: sort images with namespace and last_updated Signed-off-by: guacamole --- registry/v2/extensions/catalog_detail.go | 20 +++++++++++++--- store/postgres/container_image.go | 30 ++++++++++++++---------- store/postgres/postgres.go | 4 +++- store/postgres/queries/registry.go | 15 +++++++----- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/registry/v2/extensions/catalog_detail.go b/registry/v2/extensions/catalog_detail.go index 62f0a0ea..b37e76af 100644 --- a/registry/v2/extensions/catalog_detail.go +++ b/registry/v2/extensions/catalog_detail.go @@ -1,6 +1,7 @@ package extensions import ( + "fmt" "net/http" "strconv" "time" @@ -35,6 +36,7 @@ func (ext *extension) CatalogDetail(ctx echo.Context) error { queryParamPageSize := ctx.QueryParam("n") queryParamOffset := ctx.QueryParam("last") namespace := ctx.QueryParam("ns") + sortBy := ctx.QueryParam("sort_by") var pageSize int64 var offset int64 if queryParamPageSize != "" { @@ -62,12 +64,25 @@ func (ext *extension) CatalogDetail(ctx echo.Context) error { total, err := ext.store.GetCatalogCount(ctx.Request().Context()) if err != nil { ext.logger.Log(ctx, err) - return ctx.JSON(http.StatusInternalServerError, echo.Map{ + return ctx.JSON(http.StatusInternalServerError, echo.Map{"error": err.Error()}) + } + + switch sortBy { + case "last_updated": + sortBy = "updated_at desc" + case "namespace": + sortBy = "namespace asc" + case "": + sortBy = "namespace asc" + default: + err = fmt.Errorf("invalid choice of sort_by element") + ext.logger.Log(ctx, err) + return ctx.JSON(http.StatusBadRequest, echo.Map{ "error": err.Error(), }) } - catalogWithDetail, err := ext.store.GetCatalogDetail(ctx.Request().Context(), namespace, pageSize, offset) + catalogWithDetail, err := ext.store.GetCatalogDetail(ctx.Request().Context(), namespace, pageSize, offset, sortBy) if err != nil { ext.logger.Log(ctx, err) return ctx.JSON(http.StatusInternalServerError, echo.Map{ @@ -75,7 +90,6 @@ func (ext *extension) CatalogDetail(ctx echo.Context) error { }) } - ext.logger.Log(ctx, nil) return ctx.JSON(http.StatusOK, echo.Map{ "repositories": catalogWithDetail, "total": total, diff --git a/store/postgres/container_image.go b/store/postgres/container_image.go index 5822a7f3..fcd989d6 100644 --- a/store/postgres/container_image.go +++ b/store/postgres/container_image.go @@ -296,27 +296,31 @@ func (p *pg) GetCatalog(ctx context.Context, ns string, pageSize, offset int64) } // GetCatalogDetail - ns -> Namespace; ps -> PageSize -func (p *pg) GetCatalogDetail(ctx context.Context, ns string, ps, offset int64) ([]*types.ImageManifestV2, error) { +func (p *pg) GetCatalogDetail( + ctx context.Context, ns string, ps, offset int64, sortBy string, +) ([]*types.ImageManifestV2, error) { childCtx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() var rows pgx.Rows var err error + pageSize := int64(10) + if ps > 0 { + pageSize = ps + } - if ps != 0 { - rows, err = p.conn.Query(childCtx, queries.GetCatalogDetailWithPagination, ps, offset) - if err != nil { - err = fmt.Errorf("ERR_CATALOG_WITH_PAGINATION: %w", err) - } - } else { - rows, err = p.conn.Query(childCtx, queries.GetCatalogDetailWithPagination, 10, 0) - if err != nil { - err = fmt.Errorf("ERR_CATALOG: %w", err) - } + q := fmt.Sprintf(queries.GetCatalogDetailWithPagination, sortBy) + if ns != "" { + q = fmt.Sprintf(queries.GetUserCatalogDetailWithPagination, sortBy) + } + + rows, err = p.conn.Query(childCtx, q, pageSize, offset) + if err != nil { + err = fmt.Errorf("ERR_CATALOG_WITH_PAGINATION: %w", err) } if ns != "" { - rows, err = p.conn.Query(childCtx, queries.GetUserCatalogDetailWithPagination, ns+"/%", ps, offset) + rows, err = p.conn.Query(childCtx, q, ns+"/%", sortBy, ps, offset) if err != nil { err = fmt.Errorf("ERR_USER_CATALOG: %w", err) } @@ -327,8 +331,8 @@ func (p *pg) GetCatalogDetail(ctx context.Context, ns string, ps, offset int64) } defer rows.Close() - var catalog []*types.ImageManifestV2 + var catalog []*types.ImageManifestV2 for i := 0; rows.Next(); i++ { var mf types.ImageManifestV2 diff --git a/store/postgres/postgres.go b/store/postgres/postgres.go index da141403..475ee12a 100644 --- a/store/postgres/postgres.go +++ b/store/postgres/postgres.go @@ -70,7 +70,9 @@ type RegistryStore interface { GetConfig(ctx context.Context, namespace string) ([]*types.ConfigV2, error) GetImageTags(ctx context.Context, namespace string) ([]string, error) GetCatalog(ctx context.Context, namespace string, pageSize int64, offset int64) ([]string, error) - GetCatalogDetail(ctx context.Context, namespace string, pageSize int64, offset int64) ([]*types.ImageManifestV2, error) + GetCatalogDetail( + ctx context.Context, namespace string, pageSize int64, offset int64, sortBy string, + ) ([]*types.ImageManifestV2, error) GetRepoDetail(ctx context.Context, namespace string, pageSize int64, offset int64) (*types.Repository, error) GetCatalogCount(ctx context.Context) (int64, error) GetImageNamespace(ctx context.Context, search string) ([]*types.ImageManifestV2, error) diff --git a/store/postgres/queries/registry.go b/store/postgres/queries/registry.go index 822996f4..bdcae746 100644 --- a/store/postgres/queries/registry.go +++ b/store/postgres/queries/registry.go @@ -32,13 +32,16 @@ var ( GetCatalog = `select namespace from image_manifest;` GetCatalogWithPagination = `select namespace from image_manifest limit $1 offset $2;` GetUserCatalogWithPagination = `select namespace from image_manifest where namespace like $1 limit $2 offset $3;` - GetImageNamespace = `select uuid,namespace,created_at::timestamptz,updated_at::timestamptz from image_manifest where substr(namespace, 1, 50) like $1;` + GetImageNamespace = `select uuid,namespace,created_at::timestamptz,updated_at::timestamptz from + image_manifest where substr(namespace, 1, 50) like $1;` - GetCatalogDetailWithPagination = `select namespace,created_at::timestamptz,updated_at::timestamptz from image_manifest limit $1 offset $2;` - GetUserCatalogDetailWithPagination = `select namespace,created_at::timestamptz,updated_at::timestamptz from image_manifest where namespace like $1 limit $2 offset $3;` - - // select floor(sum(size::float4/1000000)) from layer where digest = ANY(ARRAY(select layers from config where namespace='johndoe/traefik')); - GetRepoDetailWithPagination = `select reference, digest, sky_link, (select sum(size) from layer where digest = ANY(layers)) as size, created_at::timestamptz, updated_at::timestamptz from config where namespace=$1 limit $2 offset $3;` + // be very careful using this one + GetCatalogDetailWithPagination = `select namespace,created_at::timestamptz,updated_at::timestamptz from image_manifest order by %s limit $1 offset $2;` + GetUserCatalogDetailWithPagination = `select namespace,created_at::timestamptz,updated_at::timestamptz from + image_manifest where namespace like $1 order by %s limit $3 offset $4;` + GetRepoDetailWithPagination = `select reference, digest, sky_link, (select sum(size) from layer where digest = + ANY(layers)) as size, created_at::timestamptz, updated_at::timestamptz from config where namespace=$1 + limit $2 offset $3;` ) // delete queries