Optimize AlbumRepository.GetAll and add a GetAllWithoutGenres method specifically for Subsonic API, where multiple-genres are not required

This commit is contained in:
Deluan 2021-11-02 21:18:53 -04:00
parent bc8132ef1f
commit 9422373be0
6 changed files with 33 additions and 9 deletions

View File

@ -52,6 +52,7 @@ type AlbumRepository interface {
Put(*Album) error
Get(id string) (*Album, error)
GetAll(...QueryOptions) (Albums, error)
GetAllWithoutGenres(...QueryOptions) (Albums, error)
Search(q string, offset int, size int) (Albums, error)
Refresh(ids ...string) error
AnnotatedRepository

View File

@ -93,7 +93,18 @@ func (r *albumRepository) Exists(id string) (bool, error) {
func (r *albumRepository) selectAlbum(options ...model.QueryOptions) SelectBuilder {
sql := r.newSelectWithAnnotation("album.id", options...).Columns("album.*")
return r.withGenres(sql).GroupBy("album.id")
if len(options) > 0 && options[0].Filters != nil {
s, _, _ := options[0].Filters.ToSql()
// If there's any reference of genre in the filter, joins with genre
if strings.Contains(s, "genre") {
sql = r.withGenres(sql)
// If there's no filter on genre_id, group the results by media_file.id
if !strings.Contains(s, "genre_id") {
sql = sql.GroupBy("album.id")
}
}
}
return sql
}
func (r *albumRepository) Get(id string) (*model.Album, error) {
@ -118,13 +129,21 @@ func (r *albumRepository) Put(m *model.Album) error {
}
func (r *albumRepository) GetAll(options ...model.QueryOptions) (model.Albums, error) {
res, err := r.GetAllWithoutGenres(options...)
if err != nil {
return nil, err
}
err = r.loadAlbumGenres(&res)
return res, err
}
func (r *albumRepository) GetAllWithoutGenres(options ...model.QueryOptions) (model.Albums, error) {
sq := r.selectAlbum(options...)
res := model.Albums{}
err := r.queryAll(sq, &res)
if err != nil {
return nil, err
}
err = r.loadAlbumGenres(&res)
return res, err
}

View File

@ -45,7 +45,7 @@ func (r *sqlRepository) loadMediaFileGenres(mfs *model.MediaFiles) error {
m[mf.ID] = mf
}
return utils.RangeByChunks(ids, 100, func(ids []string) error {
return utils.RangeByChunks(ids, 900, func(ids []string) error {
sql := Select("g.*", "mg.media_file_id").From("genre g").Join("media_file_genres mg on mg.genre_id = g.id").
Where(Eq{"mg.media_file_id": ids}).OrderBy("mg.media_file_id", "mg.rowid")
var genres []struct {
@ -74,7 +74,7 @@ func (r *sqlRepository) loadAlbumGenres(mfs *model.Albums) error {
m[mf.ID] = mf
}
return utils.RangeByChunks(ids, 100, func(ids []string) error {
return utils.RangeByChunks(ids, 900, func(ids []string) error {
sql := Select("g.*", "ag.album_id").From("genre g").Join("album_genres ag on ag.genre_id = g.id").
Where(Eq{"ag.album_id": ids}).OrderBy("ag.album_id", "ag.rowid")
var genres []struct {
@ -103,7 +103,7 @@ func (r *sqlRepository) loadArtistGenres(mfs *model.Artists) error {
m[mf.ID] = mf
}
return utils.RangeByChunks(ids, 100, func(ids []string) error {
return utils.RangeByChunks(ids, 900, func(ids []string) error {
sql := Select("g.*", "ag.artist_id").From("genre g").Join("artist_genres ag on ag.genre_id = g.id").
Where(Eq{"ag.artist_id": ids}).OrderBy("ag.artist_id", "ag.rowid")
var genres []struct {

View File

@ -63,7 +63,7 @@ func (c *AlbumListController) getAlbumList(r *http.Request) (model.Albums, int64
opts.Offset = utils.ParamInt(r, "offset", 0)
opts.Max = utils.MinInt(utils.ParamInt(r, "size", 10), 500)
albums, err := c.ds.Album(r.Context()).GetAll(opts)
albums, err := c.ds.Album(r.Context()).GetAllWithoutGenres(opts)
if err != nil {
log.Error(r, "Error retrieving albums", "error", err)
@ -113,7 +113,7 @@ func (c *AlbumListController) GetStarred(w http.ResponseWriter, r *http.Request)
log.Error(r, "Error retrieving starred artists", "error", err)
return nil, err
}
albums, err := c.ds.Album(ctx).GetAll(options)
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(options)
if err != nil {
log.Error(r, "Error retrieving starred albums", "error", err)
return nil, err

View File

@ -149,7 +149,7 @@ func (c *BrowsingController) GetArtist(w http.ResponseWriter, r *http.Request) (
return nil, err
}
albums, err := c.ds.Album(ctx).GetAll(filter.AlbumsByArtistID(id))
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(id))
if err != nil {
log.Error(ctx, "Error retrieving albums by artist", "id", id, "name", artist.Name, err)
return nil, err
@ -337,7 +337,7 @@ func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *m
dir.Starred = &artist.StarredAt
}
albums, err := c.ds.Album(ctx).GetAll(filter.AlbumsByArtistID(artist.ID))
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(artist.ID))
if err != nil {
return nil, err
}

View File

@ -74,6 +74,10 @@ func (m *MockAlbumRepo) GetAll(qo ...model.QueryOptions) (model.Albums, error) {
return m.all, nil
}
func (m *MockAlbumRepo) GetAllWithoutGenres(qo ...model.QueryOptions) (model.Albums, error) {
return m.GetAll(qo...)
}
func (m *MockAlbumRepo) IncPlayCount(id string, timestamp time.Time) error {
if m.err {
return errors.New("error")