Refactor included handling

This commit is contained in:
Deluan 2023-05-23 21:15:54 -04:00 committed by Deluan
parent 40f7170930
commit 7cf98af9da
3 changed files with 109 additions and 70 deletions

View file

@ -1,7 +1,6 @@
package model package model
import ( import (
"strings"
"time" "time"
"github.com/navidrome/navidrome/utils/slice" "github.com/navidrome/navidrome/utils/slice"
@ -61,6 +60,10 @@ func (a Album) CoverArtID() ArtworkID {
return artworkIDFromAlbum(a) return artworkIDFromAlbum(a)
} }
func (a Album) ArtistIDs() []string {
return []string{a.ArtistID, a.AlbumArtistID}
}
type DiscID struct { type DiscID struct {
AlbumID string `json:"albumId"` AlbumID string `json:"albumId"`
ReleaseDate string `json:"releaseDate"` ReleaseDate string `json:"releaseDate"`
@ -95,7 +98,7 @@ func (als Albums) ToAlbumArtist() Artist {
func (als Albums) ArtistIDs() []string { func (als Albums) ArtistIDs() []string {
var ids []string var ids []string
for _, al := range als { for _, al := range als {
ids = append(ids, strings.Split(al.AllArtistIDs, " ")...) ids = append(ids, al.ArtistIDs()...)
} }
return ids return ids
} }

View file

@ -73,21 +73,18 @@ func (a *Router) GetTracks(ctx context.Context, request GetTracksRequestObject)
} }
baseUrl := baseResourceUrl(ctx, "tracks") baseUrl := baseResourceUrl(ctx, "tracks")
links, meta := buildPaginationLinksAndMeta(int32(cnt), request.Params, baseUrl) links, meta := buildPaginationLinksAndMeta(int32(cnt), request.Params, baseUrl)
resources := includedResources{ctx: ctx, ds: a.ds, includes: request.Params.Include}
err = resources.AddArtists(mfs.ArtistIDs()...) resources := newIncludedResources(ctx, a.ds, request.Params.Include)
if err != nil { resources.Artists(mfs.ArtistIDs()...)
return nil, err resources.Albums(mfs.AlbumIDs()...)
}
err = resources.AddAlbums(mfs.AlbumIDs()...) response := GetTracks200JSONResponse{
if err != nil {
return nil, err
}
return GetTracks200JSONResponse{
Data: toAPITracks(mfs), Data: toAPITracks(mfs),
Links: links, Links: links,
Meta: &meta, Meta: &meta,
Included: resources.Build(), }
}, nil response.Included, err = resources.Build()
return response, err
} }
func (a *Router) GetTrack(ctx context.Context, request GetTrackRequestObject) (GetTrackResponseObject, error) { func (a *Router) GetTrack(ctx context.Context, request GetTrackRequestObject) (GetTrackResponseObject, error) {
@ -95,19 +92,16 @@ func (a *Router) GetTrack(ctx context.Context, request GetTrackRequestObject) (G
if err != nil { if err != nil {
return nil, err return nil, err
} }
resources := includedResources{ctx: ctx, ds: a.ds, includes: request.Params.Include}
err = resources.AddArtists(mf.ArtistID, mf.AlbumArtistID) resources := newIncludedResources(ctx, a.ds, request.Params.Include)
if err != nil { resources.Artists(mf.ArtistID, mf.AlbumArtistID)
return nil, err resources.Albums(mf.AlbumID)
}
err = resources.AddAlbums(mf.AlbumID) response := GetTrack200JSONResponse{
if err != nil {
return nil, err
}
return GetTrack200JSONResponse{
Data: toAPITrack(*mf), Data: toAPITrack(*mf),
Included: resources.Build(), }
}, nil response.Included, err = resources.Build()
return response, err
} }
func (a *Router) GetAlbums(ctx context.Context, request GetAlbumsRequestObject) (GetAlbumsResponseObject, error) { func (a *Router) GetAlbums(ctx context.Context, request GetAlbumsRequestObject) (GetAlbumsResponseObject, error) {
@ -122,17 +116,17 @@ func (a *Router) GetAlbums(ctx context.Context, request GetAlbumsRequestObject)
} }
baseUrl := baseResourceUrl(ctx, "albums") baseUrl := baseResourceUrl(ctx, "albums")
links, meta := buildPaginationLinksAndMeta(int32(cnt), request.Params, baseUrl) links, meta := buildPaginationLinksAndMeta(int32(cnt), request.Params, baseUrl)
resources := includedResources{ctx: ctx, ds: a.ds, includes: request.Params.Include}
err = resources.AddArtists(albums.ArtistIDs()...) resources := newIncludedResources(ctx, a.ds, request.Params.Include)
if err != nil { resources.Artists(albums.ArtistIDs()...)
return nil, err
} response := GetAlbums200JSONResponse{
return GetAlbums200JSONResponse{
Data: toAPIAlbums(albums), Data: toAPIAlbums(albums),
Links: links, Links: links,
Meta: &meta, Meta: &meta,
Included: resources.Build(), }
}, nil response.Included, err = resources.Build()
return response, err
} }
func (a *Router) GetAlbum(ctx context.Context, request GetAlbumRequestObject) (GetAlbumResponseObject, error) { func (a *Router) GetAlbum(ctx context.Context, request GetAlbumRequestObject) (GetAlbumResponseObject, error) {
@ -140,19 +134,16 @@ func (a *Router) GetAlbum(ctx context.Context, request GetAlbumRequestObject) (G
if err != nil { if err != nil {
return nil, err return nil, err
} }
resources := includedResources{ctx: ctx, ds: a.ds, includes: request.Params.Include}
err = resources.AddArtists(album.ArtistID, album.AlbumArtistID) resources := newIncludedResources(ctx, a.ds, request.Params.Include)
if err != nil { resources.Artists(album.ArtistID, album.AlbumArtistID)
return nil, err resources.Tracks(album.ID)
}
err = resources.AddTracks(album.ID) response := GetAlbum200JSONResponse{
if err != nil {
return nil, err
}
return GetAlbum200JSONResponse{
Data: toAPIAlbum(*album), Data: toAPIAlbum(*album),
Included: resources.Build(), }
}, nil response.Included, err = resources.Build()
return response, err
} }
func (a *Router) GetArtists(ctx context.Context, request GetArtistsRequestObject) (GetArtistsResponseObject, error) { func (a *Router) GetArtists(ctx context.Context, request GetArtistsRequestObject) (GetArtistsResponseObject, error) {

View file

@ -14,14 +14,46 @@ type includedResources struct {
ds model.DataStore ds model.DataStore
includes *includeSlice includes *includeSlice
resources []IncludedResource resources []IncludedResource
ids map[ResourceType][]string
} }
func (i *includedResources) AddTracks(albumIds ...string) error { func newIncludedResources(ctx context.Context, ds model.DataStore, includes *includeSlice) *includedResources {
if i.includes == nil || !slices.Contains(*i.includes, string(ResourceTypeTrack)) { i := &includedResources{
return nil ctx: ctx,
ds: ds,
includes: includes,
} }
sort.Strings(albumIds) if includes != nil {
slices.Compact(albumIds) i.ids = make(map[ResourceType][]string)
for _, inc := range *includes {
i.ids[ResourceType(inc)] = []string{}
}
}
return i
}
func (i *includedResources) Tracks(trackIds ...string) {
if i.ids == nil || i.ids[ResourceTypeTrack] == nil {
return
}
i.ids[ResourceTypeTrack] = append(i.ids[ResourceTypeTrack], trackIds...)
}
func (i *includedResources) Albums(albumIds ...string) {
if i.ids == nil || i.ids[ResourceTypeAlbum] == nil {
return
}
i.ids[ResourceTypeAlbum] = append(i.ids[ResourceTypeAlbum], albumIds...)
}
func (i *includedResources) Artists(artistIds ...string) {
if i.ids == nil || i.ids[ResourceTypeArtist] == nil {
return
}
i.ids[ResourceTypeArtist] = append(i.ids[ResourceTypeArtist], artistIds...)
}
func (i *includedResources) addTracks(albumIds []string) error {
tracks, err := i.ds.MediaFile(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"album_id": albumIds}}) tracks, err := i.ds.MediaFile(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"album_id": albumIds}})
if err != nil { if err != nil {
return err return err
@ -34,12 +66,7 @@ func (i *includedResources) AddTracks(albumIds ...string) error {
return nil return nil
} }
func (i *includedResources) AddAlbums(albumIds ...string) error { func (i *includedResources) addAlbums(albumIds []string) error {
if i.includes == nil || !slices.Contains(*i.includes, string(ResourceTypeAlbum)) {
return nil
}
sort.Strings(albumIds)
slices.Compact(albumIds)
albums, err := i.ds.Album(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"id": albumIds}}) albums, err := i.ds.Album(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"id": albumIds}})
if err != nil { if err != nil {
return err return err
@ -52,12 +79,7 @@ func (i *includedResources) AddAlbums(albumIds ...string) error {
return nil return nil
} }
func (i *includedResources) AddArtists(artistIds ...string) error { func (i *includedResources) addArtists(artistIds []string) error {
if i.includes == nil || !slices.Contains(*i.includes, string(ResourceTypeArtist)) {
return nil
}
sort.Strings(artistIds)
slices.Compact(artistIds)
artists, err := i.ds.Artist(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"artist.id": artistIds}}) artists, err := i.ds.Artist(i.ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"artist.id": artistIds}})
if err != nil { if err != nil {
return err return err
@ -70,9 +92,32 @@ func (i *includedResources) AddArtists(artistIds ...string) error {
return nil return nil
} }
func (i *includedResources) Build() *[]IncludedResource { func (i *includedResources) Build() (*[]IncludedResource, error) {
if i.includes == nil { if i.includes == nil {
return nil return nil, nil
} }
return &i.resources for _, typ := range *i.includes {
ids := i.ids[ResourceType(typ)]
sort.Strings(ids)
slices.Compact(ids)
if len(ids) == 0 {
continue
}
switch ResourceType(typ) {
case ResourceTypeAlbum:
if err := i.addAlbums(ids); err != nil {
return nil, err
}
case ResourceTypeArtist:
if err := i.addArtists(ids); err != nil {
return nil, err
}
case ResourceTypeTrack:
if err := i.addTracks(ids); err != nil {
return nil, err
}
}
}
return &i.resources, nil
} }