Files
bvandeusen 5c386dc73e fix(server,web/m7-cover-sources): forward-fix CI
Three failures from the prior push:

1. internal/api/library.go and 3 other callers of q.GetArtistByID
   broke because T2 modified the query to use an explicit column
   list, making sqlc generate GetArtistByIDRow instead of returning
   dbq.Artist. dbq.Artist already has every column added by
   migration 0018 (artist_thumb_path / artist_fanart_path /
   artist_art_source / artist_art_sources_version), so the explicit
   column list was unnecessary work. Revert the SELECT to SELECT *,
   regenerate sqlc, GetArtistByIDRow disappears, all callers compile
   again.

2. internal/tracks/service_test.go missed the dataDir parameter
   added to NewService in T9. Add "" as the 4th arg to every test
   call site (tests don't exercise the artist-art cleanup path; the
   empty dataDir is fine).

3. integrations.test.ts:356's mock.calls.filter callback had a
   too-narrow type annotation that svelte-check rejected. Relax to
   any[] to match what mock.calls actually is.
2026-05-06 13:22:36 -04:00

507 lines
14 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: artists.sql
package dbq
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const clearArtistArtNone = `-- name: ClearArtistArtNone :exec
UPDATE artists
SET artist_art_source = NULL,
updated_at = now()
WHERE id = $1
AND artist_art_source = 'none'
`
// M7 cover-sources: parallel of ClearAlbumCoverNone. Used by the
// eligibility loop to flip stale 'none' rows back to NULL.
func (q *Queries) ClearArtistArtNone(ctx context.Context, id pgtype.UUID) error {
_, err := q.db.Exec(ctx, clearArtistArtNone, id)
return err
}
const countArtists = `-- name: CountArtists :one
SELECT COUNT(*) FROM artists
`
func (q *Queries) CountArtists(ctx context.Context) (int64, error) {
row := q.db.QueryRow(ctx, countArtists)
var count int64
err := row.Scan(&count)
return count, err
}
const countArtistsMatching = `-- name: CountArtistsMatching :one
SELECT COUNT(*) FROM artists WHERE name ILIKE '%' || $1::text || '%'
`
func (q *Queries) CountArtistsMatching(ctx context.Context, dollar_1 string) (int64, error) {
row := q.db.QueryRow(ctx, countArtistsMatching, dollar_1)
var count int64
err := row.Scan(&count)
return count, err
}
const deleteArtistIfEmpty = `-- name: DeleteArtistIfEmpty :one
DELETE FROM artists a
WHERE a.id = $1
AND NOT EXISTS (SELECT 1 FROM albums al WHERE al.artist_id = a.id)
AND NOT EXISTS (SELECT 1 FROM tracks t WHERE t.artist_id = a.id)
RETURNING a.id
`
// M7 #372: deletes the artist row only when it has no remaining albums
// AND no remaining tracks (defensive — tracks can in principle exist
// without an album, though the scanner doesn't write that shape today).
func (q *Queries) DeleteArtistIfEmpty(ctx context.Context, id pgtype.UUID) (pgtype.UUID, error) {
row := q.db.QueryRow(ctx, deleteArtistIfEmpty, id)
var id_2 pgtype.UUID
err := row.Scan(&id_2)
return id_2, err
}
const getArtistByID = `-- name: GetArtistByID :one
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists WHERE id = $1
`
// Lookup an artist row by its UUID. Returns the full row; consumers
// pick the columns they need.
func (q *Queries) GetArtistByID(ctx context.Context, id pgtype.UUID) (Artist, error) {
row := q.db.QueryRow(ctx, getArtistByID, id)
var i Artist
err := row.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
)
return i, err
}
const getArtistByName = `-- name: GetArtistByName :one
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists WHERE name = $1 LIMIT 1
`
func (q *Queries) GetArtistByName(ctx context.Context, name string) (Artist, error) {
row := q.db.QueryRow(ctx, getArtistByName, name)
var i Artist
err := row.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
)
return i, err
}
const getArtistsByIDs = `-- name: GetArtistsByIDs :many
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists WHERE id = ANY($1::uuid[])
`
// Batched lookup used by M5c suggestion attribution to resolve top-3
// contributing seed UUIDs back to artist names in one round-trip.
func (q *Queries) GetArtistsByIDs(ctx context.Context, dollar_1 []pgtype.UUID) ([]Artist, error) {
rows, err := q.db.Query(ctx, getArtistsByIDs, dollar_1)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Artist
for rows.Next() {
var i Artist
if err := rows.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listArtists = `-- name: ListArtists :many
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists ORDER BY sort_name
`
func (q *Queries) ListArtists(ctx context.Context) ([]Artist, error) {
rows, err := q.db.Query(ctx, listArtists)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Artist
for rows.Next() {
var i Artist
if err := rows.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listArtistsAlpha = `-- name: ListArtistsAlpha :many
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists ORDER BY sort_name, name, id LIMIT $1 OFFSET $2
`
type ListArtistsAlphaParams struct {
Limit int32
Offset int32
}
func (q *Queries) ListArtistsAlpha(ctx context.Context, arg ListArtistsAlphaParams) ([]Artist, error) {
rows, err := q.db.Query(ctx, listArtistsAlpha, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Artist
for rows.Next() {
var i Artist
if err := rows.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listArtistsAlphaWithCovers = `-- name: ListArtistsAlphaWithCovers :many
SELECT artists.id, artists.name, artists.sort_name, artists.mbid, artists.created_at, artists.updated_at, artists.artist_thumb_path, artists.artist_fanart_path, artists.artist_art_source, artists.artist_art_sources_version,
cov.id AS cover_album_id,
cnt.album_count::bigint AS album_count
FROM artists
LEFT JOIN LATERAL (
SELECT id FROM albums
WHERE artist_id = artists.id AND cover_art_path IS NOT NULL
ORDER BY created_at DESC LIMIT 1
) cov ON true
LEFT JOIN LATERAL (
SELECT count(*) AS album_count
FROM albums WHERE artist_id = artists.id
) cnt ON true
ORDER BY artists.sort_name, artists.name, artists.id
LIMIT $1 OFFSET $2
`
type ListArtistsAlphaWithCoversParams struct {
Limit int32
Offset int32
}
type ListArtistsAlphaWithCoversRow struct {
Artist Artist
CoverAlbumID pgtype.UUID
AlbumCount int64
}
// M6a: alpha-sorted artist list with derived cover_album_id (most-recent
// album whose cover_art_path is set). Replaces ListArtistsAlpha for the
// /api/artists?sort=alpha branch — the new column is appended, so the
// alpha branch is purely additive on the wire. album_count is computed
// in the same query to drop the old N+1 in handleListArtists.
func (q *Queries) ListArtistsAlphaWithCovers(ctx context.Context, arg ListArtistsAlphaWithCoversParams) ([]ListArtistsAlphaWithCoversRow, error) {
rows, err := q.db.Query(ctx, listArtistsAlphaWithCovers, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListArtistsAlphaWithCoversRow
for rows.Next() {
var i ListArtistsAlphaWithCoversRow
if err := rows.Scan(
&i.Artist.ID,
&i.Artist.Name,
&i.Artist.SortName,
&i.Artist.Mbid,
&i.Artist.CreatedAt,
&i.Artist.UpdatedAt,
&i.Artist.ArtistThumbPath,
&i.Artist.ArtistFanartPath,
&i.Artist.ArtistArtSource,
&i.Artist.ArtistArtSourcesVersion,
&i.CoverAlbumID,
&i.AlbumCount,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listArtistsMissingArt = `-- name: ListArtistsMissingArt :many
SELECT a.id
FROM artists a
WHERE a.artist_art_source IS NULL
OR (a.artist_art_source = 'none' AND a.artist_art_sources_version != $1)
ORDER BY a.created_at
LIMIT $2
`
type ListArtistsMissingArtParams struct {
ArtistArtSourcesVersion int32
Limit int32
}
// M7 cover-sources: returns artist rows the artist-art enricher should
// attempt. Eligible: artist_art_source IS NULL OR (= 'none' AND stale
// artist_art_sources_version). MBID-less artists are returned but the
// enricher skips them at the row.mbid == nil guard inside the chain.
func (q *Queries) ListArtistsMissingArt(ctx context.Context, arg ListArtistsMissingArtParams) ([]pgtype.UUID, error) {
rows, err := q.db.Query(ctx, listArtistsMissingArt, arg.ArtistArtSourcesVersion, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []pgtype.UUID
for rows.Next() {
var id pgtype.UUID
if err := rows.Scan(&id); err != nil {
return nil, err
}
items = append(items, id)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listArtistsNewest = `-- name: ListArtistsNewest :many
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists ORDER BY created_at DESC, id DESC LIMIT $1 OFFSET $2
`
type ListArtistsNewestParams struct {
Limit int32
Offset int32
}
// Secondary id tiebreaker keeps pagination stable when created_at ties.
func (q *Queries) ListArtistsNewest(ctx context.Context, arg ListArtistsNewestParams) ([]Artist, error) {
rows, err := q.db.Query(ctx, listArtistsNewest, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Artist
for rows.Next() {
var i Artist
if err := rows.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const searchArtists = `-- name: SearchArtists :many
SELECT id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version FROM artists
WHERE name ILIKE '%' || $1 || '%'
ORDER BY sort_name
LIMIT $2 OFFSET $3
`
type SearchArtistsParams struct {
Column1 *string
Limit int32
Offset int32
}
func (q *Queries) SearchArtists(ctx context.Context, arg SearchArtistsParams) ([]Artist, error) {
rows, err := q.db.Query(ctx, searchArtists, arg.Column1, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Artist
for rows.Next() {
var i Artist
if err := rows.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const setArtistArtWithVersion = `-- name: SetArtistArtWithVersion :exec
UPDATE artists
SET artist_thumb_path = $2,
artist_fanart_path = $3,
artist_art_source = $4,
artist_art_sources_version = $5,
updated_at = now()
WHERE id = $1
`
type SetArtistArtWithVersionParams struct {
ID pgtype.UUID
ArtistThumbPath *string
ArtistFanartPath *string
ArtistArtSource *string
ArtistArtSourcesVersion int32
}
// M7 cover-sources: records a successful or settled artist-art
// enrichment with the current sources_version stamp. thumb_path /
// fanart_path are NULL on a 'none' result, or independently NULL if
// the provider returned only one of the two image types (e.g.
// TheAudioDB had a thumb but no fanart for this artist).
func (q *Queries) SetArtistArtWithVersion(ctx context.Context, arg SetArtistArtWithVersionParams) error {
_, err := q.db.Exec(ctx, setArtistArtWithVersion,
arg.ID,
arg.ArtistThumbPath,
arg.ArtistFanartPath,
arg.ArtistArtSource,
arg.ArtistArtSourcesVersion,
)
return err
}
const setArtistMbidIfNull = `-- name: SetArtistMbidIfNull :exec
UPDATE artists
SET mbid = $2,
updated_at = now()
WHERE id = $1 AND mbid IS NULL
`
type SetArtistMbidIfNullParams struct {
ID pgtype.UUID
Mbid *string
}
// M7 #379: heal MBID on existing artist rows during rescan. Idempotent —
// only updates when the existing mbid is NULL, so concurrent scans don't
// overwrite an existing value with a stale one.
func (q *Queries) SetArtistMbidIfNull(ctx context.Context, arg SetArtistMbidIfNullParams) error {
_, err := q.db.Exec(ctx, setArtistMbidIfNull, arg.ID, arg.Mbid)
return err
}
const upsertArtist = `-- name: UpsertArtist :one
INSERT INTO artists (name, sort_name, mbid)
VALUES ($1, $2, $3)
ON CONFLICT (mbid) WHERE mbid IS NOT NULL
DO UPDATE SET
name = EXCLUDED.name,
sort_name = EXCLUDED.sort_name,
updated_at = now()
RETURNING id, name, sort_name, mbid, created_at, updated_at, artist_thumb_path, artist_fanart_path, artist_art_source, artist_art_sources_version
`
type UpsertArtistParams struct {
Name string
SortName string
Mbid *string
}
// Insert or update by mbid when present; otherwise by (name, sort_name).
// Callers pass the canonical sort_name; scanner is responsible for derivation.
func (q *Queries) UpsertArtist(ctx context.Context, arg UpsertArtistParams) (Artist, error) {
row := q.db.QueryRow(ctx, upsertArtist, arg.Name, arg.SortName, arg.Mbid)
var i Artist
err := row.Scan(
&i.ID,
&i.Name,
&i.SortName,
&i.Mbid,
&i.CreatedAt,
&i.UpdatedAt,
&i.ArtistThumbPath,
&i.ArtistFanartPath,
&i.ArtistArtSource,
&i.ArtistArtSourcesVersion,
)
return i, err
}