From 029290f3046a584ccf91f8bace3eec0501d2041e Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 8 Feb 2020 22:55:05 -0500 Subject: [PATCH] fix: set default play_count to 0 IncPlayCount was not incrementing when the annotation already existed with play_count = null --- db/db.go | 2 +- .../20200130083147_create_schema.go | 2 +- .../20200131183653_standardize_item_type.go | 2 +- ...00208222418_add_defaults_to_annotations.go | 56 +++++++++++++++++++ persistence/mediafile_repository_test.go | 30 ++++++++++ persistence/sql_annotations.go | 30 +++++----- 6 files changed, 104 insertions(+), 18 deletions(-) rename db/{migrations => migration}/20200130083147_create_schema.go (99%) rename db/{migrations => migration}/20200131183653_standardize_item_type.go (98%) create mode 100644 db/migration/20200208222418_add_defaults_to_annotations.go diff --git a/db/db.go b/db/db.go index 1023ce827..1e93445a1 100644 --- a/db/db.go +++ b/db/db.go @@ -6,7 +6,7 @@ import ( "sync" "github.com/deluan/navidrome/conf" - _ "github.com/deluan/navidrome/db/migrations" + _ "github.com/deluan/navidrome/db/migration" "github.com/deluan/navidrome/log" _ "github.com/mattn/go-sqlite3" "github.com/pressly/goose" diff --git a/db/migrations/20200130083147_create_schema.go b/db/migration/20200130083147_create_schema.go similarity index 99% rename from db/migrations/20200130083147_create_schema.go rename to db/migration/20200130083147_create_schema.go index 953a871f5..56babb343 100644 --- a/db/migrations/20200130083147_create_schema.go +++ b/db/migration/20200130083147_create_schema.go @@ -1,4 +1,4 @@ -package migrations +package migration import ( "database/sql" diff --git a/db/migrations/20200131183653_standardize_item_type.go b/db/migration/20200131183653_standardize_item_type.go similarity index 98% rename from db/migrations/20200131183653_standardize_item_type.go rename to db/migration/20200131183653_standardize_item_type.go index 5f1462fe6..fb15fe864 100644 --- a/db/migrations/20200131183653_standardize_item_type.go +++ b/db/migration/20200131183653_standardize_item_type.go @@ -1,4 +1,4 @@ -package migrations +package migration import ( "database/sql" diff --git a/db/migration/20200208222418_add_defaults_to_annotations.go b/db/migration/20200208222418_add_defaults_to_annotations.go new file mode 100644 index 000000000..124aa1fe2 --- /dev/null +++ b/db/migration/20200208222418_add_defaults_to_annotations.go @@ -0,0 +1,56 @@ +package migration + +import ( + "database/sql" + + "github.com/pressly/goose" +) + +func init() { + goose.AddMigration(Up20200208222418, Down20200208222418) +} + +func Up20200208222418(tx *sql.Tx) error { + _, err := tx.Exec(` +update annotation set play_count = 0 where play_count is null; +update annotation set rating = 0 where rating is null; +create table annotation_dg_tmp +( + ann_id varchar(255) not null + primary key, + user_id varchar(255) default '' not null, + item_id varchar(255) default '' not null, + item_type varchar(255) default '' not null, + play_count integer default 0, + play_date datetime, + rating integer default 0, + starred bool default FALSE not null, + starred_at datetime, + unique (user_id, item_id, item_type) +); + +insert into annotation_dg_tmp(ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at) select ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at from annotation; + +drop table annotation; + +alter table annotation_dg_tmp rename to annotation; + +create index annotation_play_count + on annotation (play_count); + +create index annotation_play_date + on annotation (play_date); + +create index annotation_rating + on annotation (rating); + +create index annotation_starred + on annotation (starred); +`) + return err +} + +func Down20200208222418(tx *sql.Tx) error { + // This code is executed when the migration is rolled back. + return nil +} diff --git a/persistence/mediafile_repository_test.go b/persistence/mediafile_repository_test.go index db1f478b6..5bff8310f 100644 --- a/persistence/mediafile_repository_test.go +++ b/persistence/mediafile_repository_test.go @@ -2,6 +2,7 @@ package persistence import ( "context" + "time" "github.com/astaxie/beego/orm" "github.com/deluan/navidrome/log" @@ -86,4 +87,33 @@ var _ = Describe("MediaRepository", func() { _, err := mr.Get(id3) Expect(err).To(MatchError(model.ErrNotFound)) }) + + Context("Annotations", func() { + It("increments play count when the tracks does not have annotations", func() { + id := "incplay.firsttime" + Expect(mr.Put(&model.MediaFile{ID: id})).To(BeNil()) + playDate := time.Now() + Expect(mr.IncPlayCount(id, playDate)).To(BeNil()) + + mf, err := mr.Get(id) + Expect(err).To(BeNil()) + + Expect(mf.PlayDate.Unix()).To(Equal(playDate.Unix())) + Expect(mf.PlayCount).To(Equal(1)) + }) + + It("increments play count on newly starred items", func() { + id := "star.incplay" + Expect(mr.Put(&model.MediaFile{ID: id})).To(BeNil()) + Expect(mr.SetStar(true, id)).To(BeNil()) + playDate := time.Now() + Expect(mr.IncPlayCount(id, playDate)).To(BeNil()) + + mf, err := mr.Get(id) + Expect(err).To(BeNil()) + + Expect(mf.PlayDate.Unix()).To(Equal(playDate.Unix())) + Expect(mf.PlayCount).To(Equal(1)) + }) + }) }) diff --git a/persistence/sql_annotations.go b/persistence/sql_annotations.go index 298cc23cc..c1bd23f9f 100644 --- a/persistence/sql_annotations.go +++ b/persistence/sql_annotations.go @@ -33,6 +33,14 @@ func (r sqlRepository) newSelectWithAnnotation(idField string, options ...model. Columns("starred", "starred_at", "play_count", "play_date", "rating") } +func (r sqlRepository) annId(itemID ...string) And { + return And{ + Eq{"user_id": userId(r.ctx)}, + Eq{"item_type": r.tableName}, + Eq{"item_id": itemID}, + } +} + func (r sqlRepository) annUpsert(values map[string]interface{}, itemIDs ...string) error { upd := Update(annotationTable).Where(r.annId(itemIDs...)) for f, v := range values { @@ -56,12 +64,13 @@ func (r sqlRepository) annUpsert(values map[string]interface{}, itemIDs ...strin return err } -func (r sqlRepository) annId(itemID ...string) And { - return And{ - Eq{"user_id": userId(r.ctx)}, - Eq{"item_type": r.tableName}, - Eq{"item_id": itemID}, - } +func (r sqlRepository) SetStar(starred bool, ids ...string) error { + starredAt := time.Now() + return r.annUpsert(map[string]interface{}{"starred": starred, "starred_at": starredAt}, ids...) +} + +func (r sqlRepository) SetRating(rating int, itemID string) error { + return r.annUpsert(map[string]interface{}{"rating": rating}, itemID) } func (r sqlRepository) IncPlayCount(itemID string, ts time.Time) error { @@ -88,15 +97,6 @@ func (r sqlRepository) IncPlayCount(itemID string, ts time.Time) error { return err } -func (r sqlRepository) SetStar(starred bool, ids ...string) error { - starredAt := time.Now() - return r.annUpsert(map[string]interface{}{"starred": starred, "starred_at": starredAt}, ids...) -} - -func (r sqlRepository) SetRating(rating int, itemID string) error { - return r.annUpsert(map[string]interface{}{"rating": rating}, itemID) -} - func (r sqlRepository) cleanAnnotations() error { del := Delete(annotationTable).Where(Eq{"item_type": r.tableName}).Where("item_id not in (select id from " + r.tableName + ")") c, err := r.executeSQL(del)