diff --git a/model/scrobble.go b/model/scrobble.go index 45b219292..175d4c945 100644 --- a/model/scrobble.go +++ b/model/scrobble.go @@ -3,12 +3,10 @@ package model import "time" type Scrobble struct { - MediaFileID string `json:"-"` - UserID string `json:"-"` - + ID int64 `structs:"id" json:"id"` + MediaFileID string `structs:"media_file_id" json:"mediaFileId"` + UserID string `json:"-"` SubmissionTime time.Time `structs:"submission_time" json:"submissionTime"` - RowId int64 `structs:"row_id" json:"rowId"` - MediaFile } type ScrobbleRepository interface { diff --git a/persistence/scrobble_repository.go b/persistence/scrobble_repository.go index 2c6b8901f..7238901cb 100644 --- a/persistence/scrobble_repository.go +++ b/persistence/scrobble_repository.go @@ -16,15 +16,15 @@ type scrobbleRepository struct { } type dbScrobble struct { - dbMediaFile - RowId int64 `structs:"row_id" json:"rowId"` - SubmissionTime int64 `structs:"submission_time" json:"submissionTime"` + MediaFileID string `structs:"media_file_id" json:"mediaFileId"` + RowId int64 `structs:"row_id" json:"rowId"` + SubmissionTime int64 `structs:"submission_time" json:"submissionTime"` } func (m dbScrobble) toScrobble() model.Scrobble { return model.Scrobble{ - MediaFile: *m.MediaFile, - RowId: m.RowId, + MediaFileID: m.MediaFileID, + ID: m.RowId, SubmissionTime: time.Unix(m.SubmissionTime, 0), } } @@ -49,20 +49,7 @@ func (r *scrobbleRepository) baseQuery(options ...model.QueryOptions) SelectBuil user := loggedUser(r.ctx) return r.newSelect(options...). - Columns("scrobbles.ROWID row_id", "submission_time", "media_file.*", "library.path as library_path", "library.name as library_name"). - Join("media_file on media_file.id = media_file_id"). - LeftJoin("library on media_file.library_id = library.id"). - LeftJoin("annotation on ("+ - "annotation.item_id = media_file.id"+ - " AND annotation.item_type = 'media_file'"+ - " AND annotation.user_id = '"+user.ID+"')"). - Columns( - "coalesce(starred, 0) as starred", - "coalesce(rating, 0) as rating", - "starred_at", - "play_date", - "coalesce(play_count, 0) as play_count", - ). + Columns("scrobbles.ROWID row_id", "media_file_id", "submission_time"). Where(Eq{"scrobbles.user_id": user.ID}) } @@ -72,9 +59,8 @@ func NewScrobbleRepository(ctx context.Context, db dbx.Builder) model.ScrobbleRe r.db = db r.tableName = "scrobbles" r.registerModel(&model.Scrobble{}, map[string]filterFunc{ - "from": fromTs, - "to": toTs, - "title": fullTextFilter("media_file"), + "from": fromTs, + "to": toTs, }) r.setSortMappings(map[string]string{ "submission_time": "submission_time", @@ -95,17 +81,9 @@ func (r *scrobbleRepository) RecordScrobble(mediaFileID string, submissionTime t } func (r *scrobbleRepository) CountAll(options ...model.QueryOptions) (int64, error) { - user := loggedUser(r.ctx) - - sel := r.newSelect(). - Columns("count(*) count"). - Join("media_file on media_file.id = media_file_id"). - Where(Eq{"user_id": user.ID}) - - sel = r.applyFilters(sel, options...) - + count := r.baseQuery(options...).RemoveColumns().Column("COUNT() as count").RemoveOffset().RemoveLimit().OrderBy("scrobbles.ROWID") var res struct{ Count int64 } - err := r.queryOne(sel, &res) + err := r.queryOne(count, &res) return res.Count, err } @@ -115,13 +93,13 @@ func (r *scrobbleRepository) Count(options ...rest.QueryOptions) (int64, error) func (r *scrobbleRepository) Get(id string) (*model.Scrobble, error) { sel := r.baseQuery().Where(Eq{"row_id": id}) - res := dbScrobble{} + var res dbScrobble err := r.queryOne(sel, &res) if err != nil { return nil, err } model := res.toScrobble() - return &model, nil + return &model, err } func (r *scrobbleRepository) GetAll(options ...model.QueryOptions) (model.Scrobbles, error) { diff --git a/persistence/scrobble_repository_test.go b/persistence/scrobble_repository_test.go index 4ccf7df83..bf95ab3a2 100644 --- a/persistence/scrobble_repository_test.go +++ b/persistence/scrobble_repository_test.go @@ -104,9 +104,10 @@ var _ = Describe("ScrobbleRepository", func() { It("returns an existing scrobble for the user", func() { scrobble, err := repo.Get("1") Expect(err).To(BeNil()) - scrobble.MediaFile.CreatedAt = time.Time{} - Expect(scrobble.MediaFile).To(Equal(songDayInALife)) - Expect(scrobble.SubmissionTime).To(BeTemporally("==", time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC))) + Expect(scrobble.ID).To(Equal(int64(1))) + Expect(scrobble.MediaFileID).To(Equal("1001")) + Expect(scrobble.SubmissionTime).To(BeTemporally("==", firstScrobble.SubmissionTime)) + }) It("does not return a scrobble that exists for another user", func() { @@ -131,12 +132,13 @@ var _ = Describe("ScrobbleRepository", func() { Expect(err).To(BeNil()) Expect(scrobbles).To(HaveLen(2)) - for idx := range scrobbles { - scrobbles[idx].MediaFile.CreatedAt = time.Time{} - } + Expect(scrobbles[0].ID).To(Equal(int64(3))) + Expect(scrobbles[0].MediaFileID).To(Equal("1002")) + Expect(scrobbles[0].SubmissionTime).To(BeTemporally("==", thirdScrobble.SubmissionTime)) - Expect(scrobbles[1].MediaFile).To(Equal(songDayInALife)) - Expect(scrobbles[0].MediaFile).To(Equal(songComeTogether)) + Expect(scrobbles[1].ID).To(Equal(int64(1))) + Expect(scrobbles[1].MediaFileID).To(Equal("1001")) + Expect(scrobbles[1].SubmissionTime).To(BeTemporally("==", firstScrobble.SubmissionTime)) }) It("returns scrobbles in a range", func() { @@ -146,9 +148,9 @@ var _ = Describe("ScrobbleRepository", func() { Expect(err).To(BeNil()) Expect(scrobbles).To(HaveLen(1)) - scrobbles[0].MediaFile.CreatedAt = time.Time{} - Expect(scrobbles[0].MediaFile).To(Equal(songComeTogether)) - + Expect(scrobbles[0].ID).To(Equal(int64(3))) + Expect(scrobbles[0].MediaFileID).To(Equal("1002")) + Expect(scrobbles[0].SubmissionTime).To(BeTemporally("==", thirdScrobble.SubmissionTime)) }) }) }) @@ -173,9 +175,9 @@ var _ = Describe("ScrobbleRepository", func() { It("returns an existing scrobble for the user", func() { scrobble, err := repo.Get("2") Expect(err).To(BeNil()) - scrobble.MediaFile.CreatedAt = time.Time{} - Expect(scrobble.MediaFile).To(Equal(songRadioactivity)) - Expect(scrobble.SubmissionTime).To(BeTemporally("==", time.Date(1970, 2, 1, 0, 0, 0, 0, time.UTC))) + Expect(scrobble.ID).To(Equal(int64(2))) + Expect(scrobble.MediaFileID).To(Equal("1003")) + Expect(scrobble.SubmissionTime).To(BeTemporally("==", secondScrobble.SubmissionTime)) }) It("does not return a scrobble that exists for another user", func() { @@ -200,8 +202,9 @@ var _ = Describe("ScrobbleRepository", func() { Expect(err).To(BeNil()) Expect(scrobbles).To(HaveLen(1)) - scrobbles[0].MediaFile.CreatedAt = time.Time{} - Expect(scrobbles[0].MediaFile).To(Equal(songRadioactivity)) + Expect(scrobbles[0].ID).To(Equal(int64(2))) + Expect(scrobbles[0].MediaFileID).To(Equal("1003")) + Expect(scrobbles[0].SubmissionTime).To(BeTemporally("==", secondScrobble.SubmissionTime)) }) It("returns scrobbles in a range", func() { @@ -211,8 +214,9 @@ var _ = Describe("ScrobbleRepository", func() { Expect(err).To(BeNil()) Expect(scrobbles).To(HaveLen(1)) - scrobbles[0].MediaFile.CreatedAt = time.Time{} - Expect(scrobbles[0].MediaFile).To(Equal(songRadioactivity)) + Expect(scrobbles[0].ID).To(Equal(int64(2))) + Expect(scrobbles[0].MediaFileID).To(Equal("1003")) + Expect(scrobbles[0].SubmissionTime).To(BeTemporally("==", secondScrobble.SubmissionTime)) }) }) }) diff --git a/tests/mock_scrobble_repo.go b/tests/mock_scrobble_repo.go index bdca6c290..30fe4ee98 100644 --- a/tests/mock_scrobble_repo.go +++ b/tests/mock_scrobble_repo.go @@ -2,6 +2,7 @@ package tests import ( "context" + "strconv" "time" "github.com/navidrome/navidrome/model" @@ -15,7 +16,7 @@ type MockScrobbleRepo struct { func (m *MockScrobbleRepo) Get(id string) (*model.Scrobble, error) { for _, scrobble := range m.RecordedScrobbles { - if scrobble.ID == id { + if strconv.FormatInt(scrobble.ID, 10) == id { return &scrobble, nil } }