From 5c386dc73ed08d61853b9abfab5207b065d36a91 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 6 May 2026 13:22:36 -0400 Subject: [PATCH] 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. --- internal/db/dbq/artists.sql.go | 29 +++++-------------- internal/db/queries/artists.sql | 12 ++------ internal/tracks/service_test.go | 18 ++++++------ .../admin/integrations/integrations.test.ts | 2 +- 4 files changed, 20 insertions(+), 41 deletions(-) diff --git a/internal/db/dbq/artists.sql.go b/internal/db/dbq/artists.sql.go index 8272c1d1..a96aec5e 100644 --- a/internal/db/dbq/artists.sql.go +++ b/internal/db/dbq/artists.sql.go @@ -67,36 +67,21 @@ func (q *Queries) DeleteArtistIfEmpty(ctx context.Context, id pgtype.UUID) (pgty } const getArtistByID = `-- name: GetArtistByID :one -SELECT a.id, a.name, a.sort_name, a.mbid, - a.artist_thumb_path, a.artist_fanart_path, - a.artist_art_source, a.artist_art_sources_version - FROM artists a - WHERE a.id = $1 +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 ` -type GetArtistByIDRow struct { - ID pgtype.UUID - Name string - SortName string - Mbid *string - ArtistThumbPath *string - ArtistFanartPath *string - ArtistArtSource *string - ArtistArtSourcesVersion int32 -} - -// M7 cover-sources: enricher reads the artist's mbid + current art -// columns to drive eligibility check. (Modified from SELECT * to -// explicitly include the new artist_art_* columns added in migration -// 0018.) -func (q *Queries) GetArtistByID(ctx context.Context, id pgtype.UUID) (GetArtistByIDRow, error) { +// 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 GetArtistByIDRow + var i Artist err := row.Scan( &i.ID, &i.Name, &i.SortName, &i.Mbid, + &i.CreatedAt, + &i.UpdatedAt, &i.ArtistThumbPath, &i.ArtistFanartPath, &i.ArtistArtSource, diff --git a/internal/db/queries/artists.sql b/internal/db/queries/artists.sql index 0de71efd..62535726 100644 --- a/internal/db/queries/artists.sql +++ b/internal/db/queries/artists.sql @@ -11,15 +11,9 @@ DO UPDATE SET RETURNING *; -- name: GetArtistByID :one --- M7 cover-sources: enricher reads the artist's mbid + current art --- columns to drive eligibility check. (Modified from SELECT * to --- explicitly include the new artist_art_* columns added in migration --- 0018.) -SELECT a.id, a.name, a.sort_name, a.mbid, - a.artist_thumb_path, a.artist_fanart_path, - a.artist_art_source, a.artist_art_sources_version - FROM artists a - WHERE a.id = $1; +-- Lookup an artist row by its UUID. Returns the full row; consumers +-- pick the columns they need. +SELECT * FROM artists WHERE id = $1; -- name: GetArtistByName :one SELECT * FROM artists WHERE name = $1 LIMIT 1; diff --git a/internal/tracks/service_test.go b/internal/tracks/service_test.go index d7ce67a6..02c9aa57 100644 --- a/internal/tracks/service_test.go +++ b/internal/tracks/service_test.go @@ -122,7 +122,7 @@ func TestRemoveTrack_NotFound(t *testing.T) { bogus.Bytes = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} bogus.Valid = true - svc := NewService(pool, nil, nil) + svc := NewService(pool, nil, nil, "") _, _, _, err := svc.RemoveTrack(context.Background(), bogus, admin.ID, false) if !errors.Is(err, ErrNotFound) { t.Errorf("err = %v, want ErrNotFound", err) @@ -142,7 +142,7 @@ func TestRemoveTrack_LocalFile_HappyPath(t *testing.T) { _, _, track := seedArtistAlbumTrack(t, pool, "Solo", "", path) fake := &fakeLidarrUnmonitorer{} - svc := NewService(pool, nil, fake) + svc := NewService(pool, nil, fake, "") _, _, lidarrFailed, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, false) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -170,7 +170,7 @@ func TestRemoveTrack_FileAlreadyMissing(t *testing.T) { missing := filepath.Join(t.TempDir(), "does-not-exist.mp3") _, _, track := seedArtistAlbumTrack(t, pool, "Ghost", "", missing) - svc := NewService(pool, nil, nil) + svc := NewService(pool, nil, nil, "") _, _, _, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, false) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -226,7 +226,7 @@ func TestRemoveTrack_Cascade_AlbumEmpty(t *testing.T) { t.Fatalf("trackB: %v", err) } - svc := NewService(pool, nil, nil) + svc := NewService(pool, nil, nil, "") delAlbum, delArtist, _, err := svc.RemoveTrack(context.Background(), trackA.ID, admin.ID, false) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -259,7 +259,7 @@ func TestRemoveTrack_Cascade_ArtistEmpty(t *testing.T) { } artist, album, track := seedArtistAlbumTrack(t, pool, "Lone", "", path) - svc := NewService(pool, nil, nil) + svc := NewService(pool, nil, nil, "") delAlbum, delArtist, _, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, false) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -325,7 +325,7 @@ func TestRemoveTrack_Unmonitor_HappyPath(t *testing.T) { } fake := &fakeLidarrUnmonitorer{} - svc := NewService(pool, nil, fake) + svc := NewService(pool, nil, fake, "") _, _, lidarrFailed, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, true) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -381,7 +381,7 @@ func TestRemoveTrack_Unmonitor_LidarrErrorIsNonFatal(t *testing.T) { } fake := &fakeLidarrUnmonitorer{err: errors.New("simulated lidarr 5xx")} - svc := NewService(pool, nil, fake) + svc := NewService(pool, nil, fake, "") _, _, lidarrFailed, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, true) if err != nil { t.Fatalf("RemoveTrack: %v (want nil — Lidarr failure is non-fatal)", err) @@ -411,7 +411,7 @@ func TestRemoveTrack_Unmonitor_NoMbidSkipsLidarr(t *testing.T) { _, _, track := seedArtistAlbumTrack(t, pool, "Local", "", path) fake := &fakeLidarrUnmonitorer{} - svc := NewService(pool, nil, fake) + svc := NewService(pool, nil, fake, "") _, _, lidarrFailed, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, true) if err != nil { t.Fatalf("RemoveTrack: %v", err) @@ -437,7 +437,7 @@ func TestRemoveTrack_NoUnmonitor_SkipsLidarr(t *testing.T) { _, _, track := seedArtistAlbumTrack(t, pool, "NoMon", "track-mbid", path) fake := &fakeLidarrUnmonitorer{} - svc := NewService(pool, nil, fake) + svc := NewService(pool, nil, fake, "") _, _, lidarrFailed, err := svc.RemoveTrack(context.Background(), track.ID, admin.ID, false) if err != nil { t.Fatalf("RemoveTrack: %v", err) diff --git a/web/src/routes/admin/integrations/integrations.test.ts b/web/src/routes/admin/integrations/integrations.test.ts index 0ec33dfe..ed68e43c 100644 --- a/web/src/routes/admin/integrations/integrations.test.ts +++ b/web/src/routes/admin/integrations/integrations.test.ts @@ -353,7 +353,7 @@ describe('/admin/integrations — cover art providers', () => { }); // coverage invalidation should NOT have been called const coverageCalls = invalidateQueries.mock.calls.filter( - (call: [{ queryKey: unknown[] }]) => JSON.stringify(call[0]?.queryKey) === JSON.stringify(['coverage']) + (call: any[]) => JSON.stringify(call[0]?.queryKey) === JSON.stringify(['coverage']) ); expect(coverageCalls.length).toBe(0); });