fix(persistence): preserve CreditedAs through participants JSON round-trip

This commit is contained in:
Deluan 2026-05-24 20:05:36 -03:00
parent 03b8b15f6e
commit 57785255bf
2 changed files with 66 additions and 5 deletions

View File

@ -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
}

View File

@ -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"))
})
})
})