diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go index 1e3fa3030..693e2c50c 100644 --- a/persistence/playlist_repository.go +++ b/persistence/playlist_repository.go @@ -121,20 +121,50 @@ func (r *playlistRepository) fromModel(p *model.Playlist) playlist { return pls } +// TODO: Introduce a relation table for Playlist <-> MediaFiles, and rewrite this method in pure SQL func (r *playlistRepository) loadTracks(p *model.Playlist) model.MediaFiles { + if len(p.Tracks) == 0 { + return nil + } + + // Collect all ids + ids := make([]string, len(p.Tracks)) + for i, t := range p.Tracks { + ids[i] = t.ID + } + + // Break the list in chunks, up to 50 items, to avoid hitting SQLITE_MAX_FUNCTION_ARG limit + const chunkSize = 50 + var chunks [][]string + for i := 0; i < len(ids); i += chunkSize { + end := i + chunkSize + if end > len(ids) { + end = len(ids) + } + + chunks = append(chunks, ids[i:end]) + } + + // Query each chunk of media_file ids and store results in a map mfRepo := NewMediaFileRepository(r.ctx, r.ormer) - var ids []string - for _, t := range p.Tracks { - ids = append(ids, t.ID) + trackMap := map[string]model.MediaFile{} + for i := range chunks { + idsFilter := Eq{"id": chunks[i]} + tracks, err := mfRepo.GetAll(model.QueryOptions{Filters: idsFilter}) + if err != nil { + log.Error(r.ctx, "Could not load playlist's tracks", "playlistName", p.Name, "playlistId", p.ID, err) + } + for _, t := range tracks { + trackMap[t.ID] = t + } } - idsFilter := Eq{"id": ids} - tracks, err := mfRepo.GetAll(model.QueryOptions{Filters: idsFilter}) - if err == nil { - return tracks - } else { - log.Error(r.ctx, "Could not load playlist's tracks", "playlistName", p.Name, "playlistId", p.ID, err) + + // Create a new list of tracks with the same order as the original + newTracks := make(model.MediaFiles, len(p.Tracks)) + for i, t := range p.Tracks { + newTracks[i] = trackMap[t.ID] } - return nil + return newTracks } var _ model.PlaylistRepository = (*playlistRepository)(nil) diff --git a/persistence/playlist_repository_test.go b/persistence/playlist_repository_test.go index 186c4dcef..85eb96a3e 100644 --- a/persistence/playlist_repository_test.go +++ b/persistence/playlist_repository_test.go @@ -63,11 +63,20 @@ var _ = Describe("PlaylistRepository", func() { Describe("Put/Exists/Delete", func() { var newPls model.Playlist BeforeEach(func() { - newPls = model.Playlist{ID: "22", Name: "Great!", Tracks: model.MediaFiles{{ID: "4"}}} + newPls = model.Playlist{ID: "22", Name: "Great!", Tracks: model.MediaFiles{{ID: "4"}, {ID: "3"}}} }) It("saves the playlist to the DB", func() { Expect(repo.Put(&newPls)).To(BeNil()) }) + It("adds repeated songs to a playlist and keeps the order", func() { + newPls.Tracks = append(newPls.Tracks, model.MediaFile{ID: "4"}) + Expect(repo.Put(&newPls)).To(BeNil()) + saved, _ := repo.Get("22") + Expect(saved.Tracks).To(HaveLen(3)) + Expect(saved.Tracks[0].ID).To(Equal("4")) + Expect(saved.Tracks[1].ID).To(Equal("3")) + Expect(saved.Tracks[2].ID).To(Equal("4")) + }) It("returns the newly created playlist", func() { Expect(repo.Exists("22")).To(BeTrue()) })