feat(db/m7-cover-sources): SQL queries for provider settings + recheck
- Extends GetAlbumCoverageRollup's with_art FILTER to include 'theaudiodb' so F's coverage gauge surfaces TheAudioDB-found rows as with_art rather than silently undercounting. - Modifies ListAlbumsMissingCover to take the current sources_version as a parameter; eligibility now includes stale-'none' rows. - Adds SetAlbumCoverWithVersion (atomic write of path + source + version stamp) and the parallel SetArtistArtWithVersion + ClearArtistArtNone + ListArtistsMissingArt for the artist-art enricher. - New coverart_settings.sql with ListProviderSettings, UpsertProviderSettings (boot reconciliation, preserves operator values on conflict), UpdateProviderSettings (admin PATCH; tri- state api_key handling), GetCurrentSourcesVersion, BumpSourcesVersion (RETURNING the new value).
This commit is contained in:
@@ -72,7 +72,7 @@ func (q *Queries) DeleteAlbumIfEmpty(ctx context.Context, id pgtype.UUID) (Delet
|
||||
}
|
||||
|
||||
const getAlbumByArtistAndTitle = `-- name: GetAlbumByArtistAndTitle :one
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums WHERE artist_id = $1 AND title = $2 LIMIT 1
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums WHERE artist_id = $1 AND title = $2 LIMIT 1
|
||||
`
|
||||
|
||||
type GetAlbumByArtistAndTitleParams struct {
|
||||
@@ -95,12 +95,13 @@ func (q *Queries) GetAlbumByArtistAndTitle(ctx context.Context, arg GetAlbumByAr
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getAlbumByID = `-- name: GetAlbumByID :one
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums WHERE id = $1
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAlbumByID(ctx context.Context, id pgtype.UUID) (Album, error) {
|
||||
@@ -117,6 +118,7 @@ func (q *Queries) GetAlbumByID(ctx context.Context, id pgtype.UUID) (Album, erro
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -124,7 +126,7 @@ func (q *Queries) GetAlbumByID(ctx context.Context, id pgtype.UUID) (Album, erro
|
||||
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 IN ('sidecar','embedded','mbcaa','theaudiodb')) 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
|
||||
@@ -149,7 +151,7 @@ type GetAlbumCoverageRollupRow struct {
|
||||
// Invariant: with_art + pending + settled = total. (pending_no_mbid is
|
||||
// not part of the sum — it's a subset of pending, surfaced separately.)
|
||||
//
|
||||
// The IN list below ('sidecar','embedded','mbcaa') must stay in sync
|
||||
// The IN list below ('sidecar','embedded','mbcaa','theaudiodb') must stay in sync
|
||||
// with the cover_art_source CHECK constraint in migration
|
||||
// 0016_album_cover_source.up.sql. If a new source value is added there
|
||||
// without updating this query, with_art will silently undercount.
|
||||
@@ -167,7 +169,7 @@ func (q *Queries) GetAlbumCoverageRollup(ctx context.Context) (GetAlbumCoverageR
|
||||
}
|
||||
|
||||
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
|
||||
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, albums.cover_art_sources_version, artists.sort_name AS artist_sort_name
|
||||
FROM albums
|
||||
JOIN artists ON artists.id = albums.artist_id
|
||||
ORDER BY artists.sort_name, albums.sort_title
|
||||
@@ -206,6 +208,7 @@ func (q *Queries) ListAlbumsAlphaByArtist(ctx context.Context, arg ListAlbumsAlp
|
||||
&i.Album.CreatedAt,
|
||||
&i.Album.UpdatedAt,
|
||||
&i.Album.CoverArtSource,
|
||||
&i.Album.CoverArtSourcesVersion,
|
||||
&i.ArtistSortName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -219,7 +222,7 @@ func (q *Queries) ListAlbumsAlphaByArtist(ctx context.Context, arg ListAlbumsAlp
|
||||
}
|
||||
|
||||
const listAlbumsAlphaByName = `-- name: ListAlbumsAlphaByName :many
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums ORDER BY sort_title LIMIT $1 OFFSET $2
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums ORDER BY sort_title LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListAlbumsAlphaByNameParams struct {
|
||||
@@ -247,6 +250,7 @@ func (q *Queries) ListAlbumsAlphaByName(ctx context.Context, arg ListAlbumsAlpha
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -259,7 +263,7 @@ func (q *Queries) ListAlbumsAlphaByName(ctx context.Context, arg ListAlbumsAlpha
|
||||
}
|
||||
|
||||
const listAlbumsAlphaWithArtist = `-- name: ListAlbumsAlphaWithArtist :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.name AS artist_name
|
||||
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, albums.cover_art_sources_version, artists.name AS artist_name
|
||||
FROM albums
|
||||
JOIN artists ON artists.id = albums.artist_id
|
||||
ORDER BY albums.sort_title, albums.id
|
||||
@@ -298,6 +302,7 @@ func (q *Queries) ListAlbumsAlphaWithArtist(ctx context.Context, arg ListAlbumsA
|
||||
&i.Album.CreatedAt,
|
||||
&i.Album.UpdatedAt,
|
||||
&i.Album.CoverArtSource,
|
||||
&i.Album.CoverArtSourcesVersion,
|
||||
&i.ArtistName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -311,7 +316,7 @@ func (q *Queries) ListAlbumsAlphaWithArtist(ctx context.Context, arg ListAlbumsA
|
||||
}
|
||||
|
||||
const listAlbumsByArtist = `-- name: ListAlbumsByArtist :many
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums WHERE artist_id = $1 ORDER BY release_date NULLS LAST, sort_title
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums WHERE artist_id = $1 ORDER BY release_date NULLS LAST, sort_title
|
||||
`
|
||||
|
||||
func (q *Queries) ListAlbumsByArtist(ctx context.Context, artistID pgtype.UUID) ([]Album, error) {
|
||||
@@ -334,6 +339,7 @@ func (q *Queries) ListAlbumsByArtist(ctx context.Context, artistID pgtype.UUID)
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -346,7 +352,7 @@ func (q *Queries) ListAlbumsByArtist(ctx context.Context, artistID pgtype.UUID)
|
||||
}
|
||||
|
||||
const listAlbumsByGenre = `-- name: ListAlbumsByGenre :many
|
||||
SELECT DISTINCT ON (albums.id) 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
|
||||
SELECT DISTINCT ON (albums.id) 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, albums.cover_art_sources_version
|
||||
FROM albums
|
||||
JOIN tracks ON tracks.album_id = albums.id
|
||||
WHERE tracks.genre = $1
|
||||
@@ -381,6 +387,7 @@ func (q *Queries) ListAlbumsByGenre(ctx context.Context, arg ListAlbumsByGenrePa
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -446,7 +453,7 @@ func (q *Queries) ListAlbumsMissingMbidWithTrack(ctx context.Context, limit int3
|
||||
}
|
||||
|
||||
const listAlbumsNewest = `-- name: ListAlbumsNewest :many
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type ListAlbumsNewestParams struct {
|
||||
@@ -474,6 +481,7 @@ func (q *Queries) ListAlbumsNewest(ctx context.Context, arg ListAlbumsNewestPara
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -486,7 +494,7 @@ func (q *Queries) ListAlbumsNewest(ctx context.Context, arg ListAlbumsNewestPara
|
||||
}
|
||||
|
||||
const listAlbumsRandom = `-- name: ListAlbumsRandom :many
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums ORDER BY random() LIMIT $1
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums ORDER BY random() LIMIT $1
|
||||
`
|
||||
|
||||
func (q *Queries) ListAlbumsRandom(ctx context.Context, limit int32) ([]Album, error) {
|
||||
@@ -509,6 +517,7 @@ func (q *Queries) ListAlbumsRandom(ctx context.Context, limit int32) ([]Album, e
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -521,7 +530,7 @@ func (q *Queries) ListAlbumsRandom(ctx context.Context, limit int32) ([]Album, e
|
||||
}
|
||||
|
||||
const listRecentlyAddedAlbumsWithArtist = `-- name: ListRecentlyAddedAlbumsWithArtist :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.name AS artist_name
|
||||
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, albums.cover_art_sources_version, artists.name AS artist_name
|
||||
FROM albums
|
||||
JOIN artists ON artists.id = albums.artist_id
|
||||
ORDER BY albums.created_at DESC, albums.id
|
||||
@@ -557,6 +566,7 @@ func (q *Queries) ListRecentlyAddedAlbumsWithArtist(ctx context.Context, limit i
|
||||
&i.Album.CreatedAt,
|
||||
&i.Album.UpdatedAt,
|
||||
&i.Album.CoverArtSource,
|
||||
&i.Album.CoverArtSourcesVersion,
|
||||
&i.ArtistName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -570,7 +580,7 @@ func (q *Queries) ListRecentlyAddedAlbumsWithArtist(ctx context.Context, limit i
|
||||
}
|
||||
|
||||
const searchAlbums = `-- name: SearchAlbums :many
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source FROM albums
|
||||
SELECT id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version FROM albums
|
||||
WHERE title ILIKE '%' || $1 || '%'
|
||||
ORDER BY sort_title
|
||||
LIMIT $2 OFFSET $3
|
||||
@@ -602,6 +612,7 @@ func (q *Queries) SearchAlbums(ctx context.Context, arg SearchAlbumsParams) ([]A
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -613,6 +624,35 @@ func (q *Queries) SearchAlbums(ctx context.Context, arg SearchAlbumsParams) ([]A
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const setAlbumCoverWithVersion = `-- name: SetAlbumCoverWithVersion :exec
|
||||
UPDATE albums
|
||||
SET cover_art_path = $2,
|
||||
cover_art_source = $3,
|
||||
cover_art_sources_version = $4,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type SetAlbumCoverWithVersionParams struct {
|
||||
ID pgtype.UUID
|
||||
CoverArtPath *string
|
||||
CoverArtSource *string
|
||||
CoverArtSourcesVersion int32
|
||||
}
|
||||
|
||||
// M7 cover-sources: records a successful or settled enrichment with the
|
||||
// current sources_version stamp. cover_art_path is NULL when source is
|
||||
// 'none' (no file written). Atomic; called per album per pass.
|
||||
func (q *Queries) SetAlbumCoverWithVersion(ctx context.Context, arg SetAlbumCoverWithVersionParams) error {
|
||||
_, err := q.db.Exec(ctx, setAlbumCoverWithVersion,
|
||||
arg.ID,
|
||||
arg.CoverArtPath,
|
||||
arg.CoverArtSource,
|
||||
arg.CoverArtSourcesVersion,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const setAlbumMbidIfNull = `-- name: SetAlbumMbidIfNull :exec
|
||||
UPDATE albums
|
||||
SET mbid = $2,
|
||||
@@ -643,7 +683,7 @@ DO UPDATE SET
|
||||
release_date = EXCLUDED.release_date,
|
||||
cover_art_path = EXCLUDED.cover_art_path,
|
||||
updated_at = now()
|
||||
RETURNING id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source
|
||||
RETURNING id, title, sort_title, artist_id, release_date, mbid, cover_art_path, created_at, updated_at, cover_art_source, cover_art_sources_version
|
||||
`
|
||||
|
||||
type UpsertAlbumParams struct {
|
||||
@@ -676,6 +716,7 @@ func (q *Queries) UpsertAlbum(ctx context.Context, arg UpsertAlbumParams) (Album
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CoverArtSource,
|
||||
&i.CoverArtSourcesVersion,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user