From 98ec64c6586f14ff7ed4381f8cc9fc246c2c5132 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 6 May 2026 09:40:26 -0400 Subject: [PATCH] feat(db/m7-coverage-gauge): GetAlbumCoverageRollup query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FILTER-aggregate count over albums.cover_art_source and albums.mbid returning total, with_art, pending, settled, pending_no_mbid in a single round-trip. Sub-millisecond on realistic libraries; no index needed for v1. pending_no_mbid is a subset of pending — the UI tooltip uses it to show how many "pending" rows are blocked on missing MBID and won't be moved by another scan. Also bumps the Makefile sqlc pin from 1.27.0 to 1.31.1 to match the version that produced all existing committed dbq/*.go files. The prior pin was stale; running make generate against 1.27.0 silently rolled the codegen back (cosmetic version headers on most files plus a real codegen shape change in DeleteArtistIfEmpty). --- Makefile | 2 +- internal/db/dbq/albums.sql.go | 37 ++++++++++++++++++++++++++++++++++ internal/db/queries/albums.sql | 16 +++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 42b1ad57..ac425514 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: generate test test-short lint build -SQLC_VERSION := 1.27.0 +SQLC_VERSION := 1.31.1 generate: docker run --rm -v "$(CURDIR):/src" -w /src sqlc/sqlc:$(SQLC_VERSION) generate diff --git a/internal/db/dbq/albums.sql.go b/internal/db/dbq/albums.sql.go index 91d8513f..37c4a3a7 100644 --- a/internal/db/dbq/albums.sql.go +++ b/internal/db/dbq/albums.sql.go @@ -121,6 +121,43 @@ func (q *Queries) GetAlbumByID(ctx context.Context, id pgtype.UUID) (Album, erro return i, err } +const getAlbumCoverageRollup = `-- name: GetAlbumCoverageRollup :one +SELECT + COUNT(*) AS total, + COUNT(*) FILTER (WHERE cover_art_source IN ('sidecar','embedded','mbcaa')) AS with_art, + COUNT(*) FILTER (WHERE cover_art_source IS NULL) AS pending, + COUNT(*) FILTER (WHERE cover_art_source = 'none') AS settled, + COUNT(*) FILTER (WHERE cover_art_source IS NULL AND mbid IS NULL) AS pending_no_mbid +FROM albums +` + +type GetAlbumCoverageRollupRow struct { + Total int64 + WithArt int64 + Pending int64 + Settled int64 + PendingNoMbid int64 +} + +// M7 coverage-gauge: library-wide cover-art coverage rollup for the +// admin gauge. Single sequential scan with FILTER aggregates — +// sub-millisecond on realistic libraries. pending_no_mbid is a SUBSET +// of pending; the UI surfaces it separately so operators can see how +// many "pending" albums are blocked on missing MBID and won't be +// helped by another scan. +func (q *Queries) GetAlbumCoverageRollup(ctx context.Context) (GetAlbumCoverageRollupRow, error) { + row := q.db.QueryRow(ctx, getAlbumCoverageRollup) + var i GetAlbumCoverageRollupRow + err := row.Scan( + &i.Total, + &i.WithArt, + &i.Pending, + &i.Settled, + &i.PendingNoMbid, + ) + return i, err +} + const listAlbumsAlphaByArtist = `-- name: ListAlbumsAlphaByArtist :many SELECT albums.id, albums.title, albums.sort_title, albums.artist_id, albums.release_date, albums.mbid, albums.cover_art_path, albums.created_at, albums.updated_at, albums.cover_art_source, artists.sort_name AS artist_sort_name FROM albums diff --git a/internal/db/queries/albums.sql b/internal/db/queries/albums.sql index 527fb4e5..0716205b 100644 --- a/internal/db/queries/albums.sql +++ b/internal/db/queries/albums.sql @@ -124,3 +124,19 @@ SELECT a.id AS album_id, WHERE a.mbid IS NULL ORDER BY a.created_at ASC LIMIT $1; + +-- name: GetAlbumCoverageRollup :one +-- M7 coverage-gauge: library-wide cover-art coverage rollup for the +-- admin gauge. Single sequential scan with FILTER aggregates — +-- sub-millisecond on realistic libraries. pending_no_mbid is a SUBSET +-- of pending; the UI surfaces it separately so operators can see how +-- many "pending" albums are blocked on missing MBID and won't be +-- helped by another scan. +SELECT + COUNT(*) AS total, + COUNT(*) FILTER (WHERE cover_art_source IN ('sidecar','embedded','mbcaa')) AS with_art, + COUNT(*) FILTER (WHERE cover_art_source IS NULL) AS pending, + COUNT(*) FILTER (WHERE cover_art_source = 'none') AS settled, + COUNT(*) FILTER (WHERE cover_art_source IS NULL AND mbid IS NULL) AS pending_no_mbid +FROM albums; +