func tagsDetailPaginatedQuery()

in registry/datastore/repository.go [1143:1236]


func tagsDetailPaginatedQuery(r *models.Repository, filters FilterParams) (string, []any, error) {
	qb := NewQueryBuilder()

	err := qb.Build(
		`SELECT
			t.name,
			encode(m.digest, 'hex') AS digest,
			encode(m.configuration_blob_digest, 'hex') AS config_digest,
			mt.media_type,
			m.total_size,
			t.created_at,
			t.updated_at,
			GREATEST(t.created_at, t.updated_at) as published_at
		FROM
			tags AS t
			JOIN manifests AS m ON m.top_level_namespace_id = t.top_level_namespace_id
				AND m.repository_id = t.repository_id
				AND m.id = t.manifest_id
			JOIN media_types AS mt ON mt.id = m.media_type_id
		WHERE
			t.top_level_namespace_id = ?
			AND t.repository_id = ?
		`,
		r.NamespaceID, r.ID,
	)
	if err != nil {
		return "", nil, err
	}

	if filters.ExactName != "" {
		// NOTE(prozlach): In the case when there is exact match requested,
		// there is going to be only single entry in the response, or none. So
		// there is no point in adding pagination and sorting keywords here.
		err := qb.Build("AND t.name = ?", filters.ExactName)
		if err != nil {
			return "", nil, err
		}
		return qb.SQL(), qb.Params(), nil
	}

	// NOTE(prozlach): We handle both cases in this path - empty and not
	// empty `Name` filter
	err = qb.Build("AND t.name LIKE ?\n", sqlPartialMatch(filters.Name))
	if err != nil {
		return "", nil, err
	}

	// default to ascending order to keep backwards compatibility
	if filters.SortOrder == "" {
		filters.SortOrder = OrderAsc
	}
	if filters.OrderBy == "" {
		filters.OrderBy = orderByName
	}

	switch {
	case filters.LastEntry == "" && filters.BeforeEntry == "" && filters.PublishedAt == "":
		// this should always return the first page up to filters.MaxEntries
		if filters.OrderBy == "published_at" {
			err = qb.Build(
				fmt.Sprintf(`ORDER BY published_at %s, name %s LIMIT ?`, filters.SortOrder, filters.SortOrder),
				filters.MaxEntries,
			)
			if err != nil {
				return "", nil, err
			}
		} else {
			err = qb.Build(
				fmt.Sprintf(`ORDER BY name %s LIMIT ?`, filters.SortOrder),
				filters.MaxEntries,
			)
			if err != nil {
				return "", nil, err
			}
		}
	case filters.LastEntry != "":
		err := getLastEntryQuery(qb, filters)
		if err != nil {
			return "", nil, err
		}
	case filters.BeforeEntry != "":
		err := getBeforeEntryQuery(qb, filters)
		if err != nil {
			return "", nil, err
		}
	case filters.PublishedAt != "":
		err := getPublishedAtQuery(qb, filters)
		if err != nil {
			return "", nil, err
		}
	}

	return qb.SQL(), qb.Params(), nil
}