diff --git a/internal/api/convert.go b/internal/api/convert.go index 6b9de429..60635789 100644 --- a/internal/api/convert.go +++ b/internal/api/convert.go @@ -2,6 +2,8 @@ package api import ( "github.com/jackc/pgx/v5/pgtype" + + "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // uuidToString renders a pgtype.UUID as a canonical hyphenated string. @@ -65,3 +67,51 @@ func coverURL(albumID pgtype.UUID) string { func streamURL(trackID pgtype.UUID) string { return "/api/tracks/" + uuidToString(trackID) + "/stream" } + +// artistRefFrom projects a dbq.Artist into an ArtistRef. albumCount must be +// pre-computed by the caller (one query per artist in lists). +func artistRefFrom(a dbq.Artist, albumCount int) ArtistRef { + return ArtistRef{ + ID: uuidToString(a.ID), + Name: a.Name, + AlbumCount: albumCount, + } +} + +// albumRefFrom projects a dbq.Album into an AlbumRef. artistName must be +// pre-resolved because Album only carries artist_id. trackCount and +// durationSec may be 0 when the caller does not compute them. +func albumRefFrom(a dbq.Album, artistName string, trackCount, durationSec int) AlbumRef { + return AlbumRef{ + ID: uuidToString(a.ID), + Title: a.Title, + ArtistID: uuidToString(a.ArtistID), + ArtistName: artistName, + Year: yearFromDate(a.ReleaseDate), + TrackCount: trackCount, + DurationSec: durationSec, + CoverURL: coverURL(a.ID), + } +} + +// trackRefFrom projects a dbq.Track into a TrackRef. Parent names must be +// pre-resolved because Track only carries album_id and artist_id. +func trackRefFrom(t dbq.Track, albumTitle, artistName string) TrackRef { + ref := TrackRef{ + ID: uuidToString(t.ID), + Title: t.Title, + AlbumID: uuidToString(t.AlbumID), + AlbumTitle: albumTitle, + ArtistID: uuidToString(t.ArtistID), + ArtistName: artistName, + DurationSec: durationMsToSec(t.DurationMs), + StreamURL: streamURL(t.ID), + } + if t.TrackNumber != nil { + ref.TrackNumber = int(*t.TrackNumber) + } + if t.DiscNumber != nil { + ref.DiscNumber = int(*t.DiscNumber) + } + return ref +} diff --git a/internal/api/convert_test.go b/internal/api/convert_test.go index ad147415..4b319bf5 100644 --- a/internal/api/convert_test.go +++ b/internal/api/convert_test.go @@ -4,6 +4,8 @@ import ( "testing" "github.com/jackc/pgx/v5/pgtype" + + "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) func TestUUIDToString(t *testing.T) { @@ -73,3 +75,77 @@ func TestCoverURLAndStreamURL(t *testing.T) { t.Errorf("streamURL = %q", got) } } + +func TestArtistRefFrom(t *testing.T) { + var id pgtype.UUID + _ = id.Scan("00112233-4455-6677-8899-aabbccddeeff") + a := dbq.Artist{ID: id, Name: "Beatles", SortName: "Beatles"} + got := artistRefFrom(a, 7) + if got.ID != "00112233-4455-6677-8899-aabbccddeeff" { + t.Errorf("ID = %q", got.ID) + } + if got.Name != "Beatles" || got.AlbumCount != 7 { + t.Errorf("ref = %+v", got) + } +} + +func TestAlbumRefFrom(t *testing.T) { + var aid, artID pgtype.UUID + _ = aid.Scan("00000000-0000-0000-0000-000000000001") + _ = artID.Scan("00000000-0000-0000-0000-000000000002") + var rel pgtype.Date + _ = rel.Scan("1969-09-26") + a := dbq.Album{ID: aid, Title: "Abbey Road", ArtistID: artID, ReleaseDate: rel} + got := albumRefFrom(a, "Beatles", 17, 2820) + if got.Title != "Abbey Road" || got.ArtistName != "Beatles" { + t.Errorf("ref = %+v", got) + } + if got.TrackCount != 17 || got.DurationSec != 2820 { + t.Errorf("counts = %+v", got) + } + if got.Year != 1969 { + t.Errorf("year = %d", got.Year) + } + if got.CoverURL != "/api/albums/00000000-0000-0000-0000-000000000001/cover" { + t.Errorf("cover_url = %q", got.CoverURL) + } +} + +func TestTrackRefFrom(t *testing.T) { + var tid, aid, artID pgtype.UUID + _ = tid.Scan("00000000-0000-0000-0000-000000000010") + _ = aid.Scan("00000000-0000-0000-0000-000000000001") + _ = artID.Scan("00000000-0000-0000-0000-000000000002") + trackNum := int32(3) + discNum := int32(1) + t2 := dbq.Track{ + ID: tid, Title: "Something", AlbumID: aid, ArtistID: artID, + TrackNumber: &trackNum, DiscNumber: &discNum, + DurationMs: 183_000, + } + got := trackRefFrom(t2, "Abbey Road", "Beatles") + if got.Title != "Something" || got.AlbumTitle != "Abbey Road" || got.ArtistName != "Beatles" { + t.Errorf("ref = %+v", got) + } + if got.TrackNumber != 3 || got.DiscNumber != 1 { + t.Errorf("positions = %+v", got) + } + if got.DurationSec != 183 { + t.Errorf("duration = %d, want 183", got.DurationSec) + } + if got.StreamURL != "/api/tracks/00000000-0000-0000-0000-000000000010/stream" { + t.Errorf("stream_url = %q", got.StreamURL) + } +} + +func TestTrackRefFromNilPositions(t *testing.T) { + var tid, aid, artID pgtype.UUID + _ = tid.Scan("00000000-0000-0000-0000-000000000010") + _ = aid.Scan("00000000-0000-0000-0000-000000000001") + _ = artID.Scan("00000000-0000-0000-0000-000000000002") + t2 := dbq.Track{ID: tid, AlbumID: aid, ArtistID: artID, DurationMs: 1000} + got := trackRefFrom(t2, "A", "B") + if got.TrackNumber != 0 || got.DiscNumber != 0 { + t.Errorf("nil positions should be 0, got %+v", got) + } +}