From 57785255bf29e97c88a9f0f8f6b6bb870a8b4979 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 24 May 2026 20:05:36 -0300 Subject: [PATCH] fix(persistence): preserve CreditedAs through participants JSON round-trip --- persistence/sql_participations.go | 20 +++++++--- persistence/sql_participations_test.go | 51 ++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 persistence/sql_participations_test.go diff --git a/persistence/sql_participations.go b/persistence/sql_participations.go index 38b0203fa..96a9704a6 100644 --- a/persistence/sql_participations.go +++ b/persistence/sql_participations.go @@ -10,9 +10,10 @@ import ( ) type participant struct { - ID string `json:"id"` - Name string `json:"name"` - SubRole string `json:"subRole,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + SubRole string `json:"subRole,omitempty"` + CreditedAs string `json:"creditedAs,omitempty"` } // flatParticipant represents a flattened participant structure for SQL processing @@ -26,7 +27,12 @@ func marshalParticipants(participants model.Participants) string { dbParticipants := make(map[model.Role][]participant) for role, artists := range participants { for _, artist := range artists { - dbParticipants[role] = append(dbParticipants[role], participant{ID: artist.ID, SubRole: artist.SubRole, Name: artist.Name}) + dbParticipants[role] = append(dbParticipants[role], participant{ + ID: artist.ID, + Name: artist.Name, + SubRole: artist.SubRole, + CreditedAs: artist.CreditedAs, + }) } } res, _ := json.Marshal(dbParticipants) @@ -43,7 +49,11 @@ func unmarshalParticipants(data string) (model.Participants, error) { participants := make(model.Participants, len(dbParticipants)) for role, participantList := range dbParticipants { artists := slice.Map(participantList, func(p participant) model.Participant { - return model.Participant{Artist: model.Artist{ID: p.ID, Name: p.Name}, SubRole: p.SubRole} + return model.Participant{ + Artist: model.Artist{ID: p.ID, Name: p.Name}, + SubRole: p.SubRole, + CreditedAs: p.CreditedAs, + } }) participants[role] = artists } diff --git a/persistence/sql_participations_test.go b/persistence/sql_participations_test.go new file mode 100644 index 000000000..685ab4ce6 --- /dev/null +++ b/persistence/sql_participations_test.go @@ -0,0 +1,51 @@ +package persistence + +import ( + "github.com/navidrome/navidrome/model" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("sql_participations", func() { + Describe("marshalParticipants/unmarshalParticipants", func() { + It("preserves CreditedAs through marshal/unmarshal round-trip", func() { + original := model.Participants{ + model.RoleArtist: model.ParticipantList{ + {Artist: model.Artist{ID: "canon-1", Name: "Planetary Assault Systems"}, CreditedAs: "PAS"}, + }, + model.RoleComposer: model.ParticipantList{ + {Artist: model.Artist{ID: "canon-2", Name: "John Lennon"}, CreditedAs: "J. Lennon"}, + }, + } + serialized := marshalParticipants(original) + restored, err := unmarshalParticipants(serialized) + Expect(err).ToNot(HaveOccurred()) + Expect(restored[model.RoleArtist]).To(HaveLen(1)) + Expect(restored[model.RoleArtist][0].CreditedAs).To(Equal("PAS")) + Expect(restored[model.RoleComposer][0].CreditedAs).To(Equal("J. Lennon")) + }) + + It("preserves SubRole through marshal/unmarshal round-trip", func() { + original := model.Participants{ + model.RolePerformer: model.ParticipantList{ + {Artist: model.Artist{ID: "p-1", Name: "Performer"}, SubRole: "Guitar"}, + }, + } + serialized := marshalParticipants(original) + restored, err := unmarshalParticipants(serialized) + Expect(err).ToNot(HaveOccurred()) + Expect(restored[model.RolePerformer]).To(HaveLen(1)) + Expect(restored[model.RolePerformer][0].SubRole).To(Equal("Guitar")) + }) + + It("does not include CreditedAs in serialized JSON when empty (omitempty)", func() { + p := model.Participants{ + model.RoleArtist: model.ParticipantList{ + {Artist: model.Artist{ID: "canon-1", Name: "Foo"}}, + }, + } + serialized := marshalParticipants(p) + Expect(serialized).NotTo(ContainSubstring("creditedAs")) + }) + }) +})