Files
at-container-registry/pkg/appview/db/models.go
T
Evan JarrettandClaude Opus 5 f186760847 db: drop the vestigial tags.id
Nothing joined on it. It was selected into a struct field no caller read, and
used only by DeleteTagsNotInList, which fetched surrogate ids, filtered them in
Go with a nested loop over the keep list, and issued one DELETE per row. The
natural key was already enforced by UNIQUE(did, repository, tag), so that
becomes the primary key and the column goes.

An AUTOINCREMENT rowid is allocated by whichever node performs the insert. That
is fine while every write funnels through one writer and stops being a stable
identity the moment they do not, so removing an identifier nobody used is the
cheapest way to shrink that surface before local-write replicas.

DeleteTagsNotInList now diffs against a set and deletes in batches. It still
reads the current tags first rather than issuing one NOT IN over the keep list:
that would need two placeholders per kept tag and would break past the driver's
parameter ceiling for a user with enough tags, and it cannot be chunked, because
each chunk would delete the tags every other chunk meant to keep. An explicit
delete list chunks safely.

idx_tags_did_repo is dropped rather than recreated: the new primary key indexes
(did, repository) as a prefix. It existed only because the primary key used to be
the surrogate id.

The rebuild names its columns explicitly. Column order is not guaranteed to
match between a fresh install and a migrated one, so INSERT ... SELECT * here
could write values into the wrong columns. TestMigration0032PreservesTagRows runs
the migration body against a table in the old shape and checks the contents
survive, which the schema drift test cannot: it compares shape, not data.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 21:44:05 -05:00

202 lines
6.2 KiB
Go

package db
import "time"
// User represents a user in the system
type User struct {
DID string
Handle string
PDSEndpoint string
Avatar string
DefaultHoldDID string
OciClient string
RegistryDomain string
LastSeen time.Time
}
// Manifest represents an OCI manifest stored in the cache
type Manifest struct {
ID int64
DID string
Repository string
Digest string
HoldEndpoint string
SchemaVersion int
MediaType string
ConfigDigest string
ConfigSize int64
ArtifactType string // container-image, helm-chart, unknown
SubjectDigest string // digest of the parent manifest (for attestations/referrers)
CreatedAt time.Time
// Annotations removed - now stored in repository_annotations table
}
// Layer represents a layer in a manifest
type Layer struct {
ManifestID int64
Digest string
Size int64
MediaType string
LayerIndex int
Annotations map[string]string // JSON-encoded layer annotations (e.g. in-toto predicate type)
}
// ManifestReference represents a reference to a manifest in a manifest list/index
type ManifestReference struct {
ManifestID int64
Digest string
Size int64
MediaType string
PlatformArchitecture string
PlatformOS string
PlatformVariant string
PlatformOSVersion string
IsAttestation bool // true if vnd.docker.reference.type = "attestation-manifest"
ReferenceIndex int
}
// Tag represents a tag pointing to a manifest
type Tag struct {
DID string
Repository string
Tag string
Digest string
CreatedAt time.Time
}
// Repository represents an aggregated view of a user's repository
type Repository struct {
Name string
TagCount int
ManifestCount int
LastPush time.Time
Tags []Tag
Manifests []Manifest
Title string
Description string
SourceURL string
DocumentationURL string
Licenses string
IconURL string
ReadmeURL string
Version string
}
// RepositoryStats represents statistics for a repository
type RepositoryStats struct {
DID string `json:"did"`
Repository string `json:"repository"`
StarCount int `json:"star_count"` // Calculated from stars table, not stored
PullCount int `json:"pull_count"`
LastPull *time.Time `json:"last_pull,omitempty"`
PushCount int `json:"push_count"`
LastPush *time.Time `json:"last_push,omitempty"`
}
// DailyStats represents daily pull/push statistics for a repository
type DailyStats struct {
DID string `json:"did"`
Repository string `json:"repository"`
Date string `json:"date"`
PullCount int `json:"pull_count"`
PushCount int `json:"push_count"`
}
// RepositoryWithStats combines repository data with statistics
type RepositoryWithStats struct {
Repository
Stats RepositoryStats
}
// RepoCardData contains all data needed to render a repository card
type RepoCardData struct {
OwnerHandle string
OwnerAvatarURL string // Owner's profile avatar URL (fallback when no repo icon)
Repository string
Title string
Description string
IconURL string
StarCount int
PullCount int
IsStarred bool // Whether the current user has starred this repository
ArtifactType string // container-image, helm-chart, unknown
Tag string // Latest tag name (e.g., "latest", "v1.0.0")
Digest string // Latest manifest digest (sha256:...)
LastUpdated time.Time // When the repository was last pushed to
RegistryURL string // Registry URL for docker commands (e.g., "atcr.io" or "127.0.0.1:5000")
OciClient string // Preferred OCI client for pull commands (e.g., "docker", "podman")
}
// SetRegistryURL sets the RegistryURL field on all cards in the slice
func SetRegistryURL(cards []RepoCardData, registryURL string) {
for i := range cards {
cards[i].RegistryURL = registryURL
}
}
// SetOciClient sets the OciClient field on all cards in the slice
func SetOciClient(cards []RepoCardData, ociClient string) {
for i := range cards {
cards[i].OciClient = ociClient
}
}
// PlatformInfo represents platform information (OS/Architecture)
type PlatformInfo struct {
OS string
Architecture string
Variant string
OSVersion string
Digest string // child platform manifest digest (for manifest lists)
HoldEndpoint string // hold endpoint for this platform manifest
CompressedSize int64 // sum of layer sizes (compressed)
}
// TagWithPlatforms extends Tag with platform information
type TagWithPlatforms struct {
Tag
HoldEndpoint string // hold endpoint from the tag's own manifest
Platforms []PlatformInfo
IsMultiArch bool
HasAttestations bool // true if manifest list contains attestation references
ArtifactType string // container-image, helm-chart, unknown
CompressedSize int64 // sum of layer sizes for single-arch tags
}
// ManifestWithMetadata extends Manifest with tags and platform information
type ManifestWithMetadata struct {
Manifest
Tags []string
Platforms []PlatformInfo
PlatformCount int
IsManifestList bool
HasAttestations bool // true if manifest list contains attestation references
Reachable bool // Whether the hold endpoint is reachable
Pending bool // Whether health check is still in progress
// Note: ArtifactType is available via embedded Manifest struct
}
// ManifestEntry is a unified view model for the tags tab.
// Every entry is a manifest — labeled by tag name or digest.
type ManifestEntry struct {
Label string // tag name, or digest if untagged
Digest string // manifest digest
IsTagged bool
CreatedAt time.Time
HoldEndpoint string
Platforms []PlatformInfo
IsMultiArch bool
HasAttestations bool
ArtifactType string
CompressedSize int64 // for single-arch
}
// AttestationDetail represents an attestation manifest and its layers
type AttestationDetail struct {
Digest string
MediaType string // attestation manifest media type
Size int64
HoldEndpoint string // hold DID/URL where blobs are stored
Layers []Layer
}