From b9815fc65395d1d756bf5cbf8e4f34df0a40f512 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 12 Jan 2020 18:55:55 -0500 Subject: [PATCH] SQL/Orm AlbumRepository complete --- persistence/db_sql/album_repository.go | 102 +++++++++++++++++++ persistence/db_sql/album_repository_test.go | 67 ++++++++++++ persistence/db_sql/artist_repository_test.go | 2 +- persistence/db_sql/mediafile_repository.go | 16 --- persistence/db_sql/sql.go | 1 + persistence/db_sql/sql_repository.go | 16 +++ persistence/db_sql/sql_suite_test.go | 7 ++ persistence/db_sql/wire_provider.go | 2 +- wire_gen.go | 2 +- 9 files changed, 196 insertions(+), 19 deletions(-) create mode 100644 persistence/db_sql/album_repository.go create mode 100644 persistence/db_sql/album_repository_test.go diff --git a/persistence/db_sql/album_repository.go b/persistence/db_sql/album_repository.go new file mode 100644 index 000000000..92104d99d --- /dev/null +++ b/persistence/db_sql/album_repository.go @@ -0,0 +1,102 @@ +package db_sql + +import ( + "time" + + "github.com/astaxie/beego/orm" + "github.com/cloudsonic/sonic-server/domain" +) + +type Album struct { + ID string `orm:"pk;column(id)"` + Name string `orm:"index"` + ArtistID string `orm:"column(artist_id);index"` + CoverArtPath string `` + CoverArtId string `` + Artist string `orm:"index"` + AlbumArtist string `` + Year int `orm:"index"` + Compilation bool `` + Starred bool `orm:"index"` + PlayCount int `orm:"index"` + PlayDate time.Time `orm:"null;index"` + SongCount int `` + Duration int `` + Rating int `orm:"index"` + Genre string `` + StarredAt time.Time `orm:"null"` + CreatedAt time.Time `orm:"null"` + UpdatedAt time.Time `orm:"null"` +} + +type albumRepository struct { + sqlRepository +} + +func NewAlbumRepository() domain.AlbumRepository { + r := &albumRepository{} + r.entityName = "album" + return r +} + +func (r *albumRepository) Put(a *domain.Album) error { + ta := Album(*a) + return r.put(a.ID, &ta) +} + +func (r *albumRepository) Get(id string) (*domain.Album, error) { + ta := Album{ID: id} + err := Db().Read(&ta) + if err == orm.ErrNoRows { + return nil, domain.ErrNotFound + } + if err != nil { + return nil, err + } + a := domain.Album(ta) + return &a, err +} + +func (r *albumRepository) FindByArtist(artistId string) (domain.Albums, error) { + var albums []Album + _, err := r.newQuery(Db()).Filter("artist_id", artistId).OrderBy("year", "name").All(&albums) + if err != nil { + return nil, err + } + return r.toAlbums(albums) +} + +func (r *albumRepository) GetAll(options ...domain.QueryOptions) (domain.Albums, error) { + var all []Album + _, err := r.newQuery(Db(), options...).All(&all) + if err != nil { + return nil, err + } + return r.toAlbums(all) +} + +func (r *albumRepository) toAlbums(all []Album) (domain.Albums, error) { + result := make(domain.Albums, len(all)) + for i, a := range all { + result[i] = domain.Album(a) + } + return result, nil +} + +func (r *albumRepository) PurgeInactive(activeList domain.Albums) ([]string, error) { + return r.purgeInactive(activeList, func(item interface{}) string { + return item.(domain.Album).ID + }) +} + +func (r *albumRepository) GetStarred(options ...domain.QueryOptions) (domain.Albums, error) { + var starred []Album + _, err := r.newQuery(Db(), options...).Filter("starred", true).All(&starred) + if err != nil { + return nil, err + } + return r.toAlbums(starred) +} + +var _ domain.AlbumRepository = (*albumRepository)(nil) +var _ = domain.Album(Album{}) diff --git a/persistence/db_sql/album_repository_test.go b/persistence/db_sql/album_repository_test.go new file mode 100644 index 000000000..e43ab92ae --- /dev/null +++ b/persistence/db_sql/album_repository_test.go @@ -0,0 +1,67 @@ +package db_sql + +import ( + "github.com/cloudsonic/sonic-server/domain" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AlbumRepository", func() { + var repo domain.AlbumRepository + + BeforeEach(func() { + repo = NewAlbumRepository() + }) + + Describe("GetAll", func() { + It("returns all records", func() { + Expect(repo.GetAll()).To(Equal(testAlbums)) + }) + + It("returns all records sorted", func() { + Expect(repo.GetAll(domain.QueryOptions{SortBy: "Name"})).To(Equal(domain.Albums{ + {ID: "2", Name: "Abbey Road", Artist: "The Beatles", ArtistID: "1"}, + {ID: "3", Name: "Radioactivity", Artist: "Kraftwerk", ArtistID: "2", Starred: true}, + {ID: "1", Name: "Sgt Peppers", Artist: "The Beatles", ArtistID: "1"}, + })) + }) + + It("returns all records sorted desc", func() { + Expect(repo.GetAll(domain.QueryOptions{SortBy: "Name", Desc: true})).To(Equal(domain.Albums{ + {ID: "1", Name: "Sgt Peppers", Artist: "The Beatles", ArtistID: "1"}, + {ID: "3", Name: "Radioactivity", Artist: "Kraftwerk", ArtistID: "2", Starred: true}, + {ID: "2", Name: "Abbey Road", Artist: "The Beatles", ArtistID: "1"}, + })) + }) + + It("paginates the result", func() { + Expect(repo.GetAll(domain.QueryOptions{Offset: 1, Size: 1})).To(Equal(domain.Albums{ + {ID: "2", Name: "Abbey Road", Artist: "The Beatles", ArtistID: "1"}, + })) + }) + }) + + Describe("GetAllIds", func() { + It("returns all records", func() { + Expect(repo.GetAllIds()).To(Equal([]string{"1", "2", "3"})) + }) + }) + + Describe("GetStarred", func() { + It("returns all starred records", func() { + Expect(repo.GetStarred(domain.QueryOptions{})).To(Equal(domain.Albums{ + {ID: "3", Name: "Radioactivity", Artist: "Kraftwerk", ArtistID: "2", Starred: true}, + })) + }) + }) + + Describe("FindByArtist", func() { + It("returns all records from a given ArtistID", func() { + Expect(repo.FindByArtist("1")).To(Equal(domain.Albums{ + {ID: "2", Name: "Abbey Road", Artist: "The Beatles", ArtistID: "1"}, + {ID: "1", Name: "Sgt Peppers", Artist: "The Beatles", ArtistID: "1"}, + })) + }) + }) + +}) diff --git a/persistence/db_sql/artist_repository_test.go b/persistence/db_sql/artist_repository_test.go index 190684555..4dce730f7 100644 --- a/persistence/db_sql/artist_repository_test.go +++ b/persistence/db_sql/artist_repository_test.go @@ -27,7 +27,7 @@ var _ = Describe("ArtistRepository", func() { Expect(err).To(MatchError(domain.ErrNotFound)) }) - FDescribe("PurgeInactive", func() { + Describe("PurgeInactive", func() { BeforeEach(func() { for _, a := range testArtists { repo.Put(&a) diff --git a/persistence/db_sql/mediafile_repository.go b/persistence/db_sql/mediafile_repository.go index cde278cfd..f258f6338 100644 --- a/persistence/db_sql/mediafile_repository.go +++ b/persistence/db_sql/mediafile_repository.go @@ -5,7 +5,6 @@ import ( "github.com/astaxie/beego/orm" "github.com/cloudsonic/sonic-server/domain" - "github.com/cloudsonic/sonic-server/persistence" ) type MediaFile struct { @@ -90,21 +89,6 @@ func (r *mediaFileRepository) GetStarred(options ...domain.QueryOptions) (domain return r.toMediaFiles(starred) } -func (r *mediaFileRepository) GetAllIds() ([]string, error) { - qs := r.newQuery(Db()) - var values []orm.Params - num, err := qs.Values(&values, "id") - if num == 0 { - return nil, err - } - - result := persistence.CollectValue(values, func(item interface{}) string { - return item.(orm.Params)["ID"].(string) - }) - - return result, nil -} - func (r *mediaFileRepository) PurgeInactive(activeList domain.MediaFiles) ([]string, error) { return r.purgeInactive(activeList, func(item interface{}) string { return item.(domain.MediaFile).ID diff --git a/persistence/db_sql/sql.go b/persistence/db_sql/sql.go index c31c90b14..78978464a 100644 --- a/persistence/db_sql/sql.go +++ b/persistence/db_sql/sql.go @@ -55,6 +55,7 @@ func WithTx(block func(orm.Ormer) error) error { func initORM(dbPath string) error { orm.Debug = true orm.RegisterModel(new(Artist)) + orm.RegisterModel(new(Album)) orm.RegisterModel(new(MediaFile)) err := orm.RegisterDataBase("default", "sqlite3", dbPath) if err != nil { diff --git a/persistence/db_sql/sql_repository.go b/persistence/db_sql/sql_repository.go index 51cc2ae94..b7853370e 100644 --- a/persistence/db_sql/sql_repository.go +++ b/persistence/db_sql/sql_repository.go @@ -38,6 +38,22 @@ func (r *sqlRepository) Exists(id string) (bool, error) { return c == 1, err } +// TODO This is used to generate random lists. Can be optimized in SQL: https://stackoverflow.com/a/19419 +func (r *sqlRepository) GetAllIds() ([]string, error) { + qs := r.newQuery(Db()) + var values []orm.Params + num, err := qs.Values(&values, "id") + if num == 0 { + return nil, err + } + + result := persistence.CollectValue(values, func(item interface{}) string { + return item.(orm.Params)["ID"].(string) + }) + + return result, nil +} + func (r *sqlRepository) put(id string, a interface{}) error { return WithTx(func(o orm.Ormer) error { c, err := r.newQuery(o).Filter("id", id).Count() diff --git a/persistence/db_sql/sql_suite_test.go b/persistence/db_sql/sql_suite_test.go index 8fec2c989..5d05e88cd 100644 --- a/persistence/db_sql/sql_suite_test.go +++ b/persistence/db_sql/sql_suite_test.go @@ -38,5 +38,12 @@ var _ = Describe("Initialize test DB", func() { for _, a := range testArtists { artistRepo.Put(&a) } + albumRepository := NewAlbumRepository() + for _, a := range testAlbums { + err := albumRepository.Put(&a) + if err != nil { + panic(err) + } + } }) }) diff --git a/persistence/db_sql/wire_provider.go b/persistence/db_sql/wire_provider.go index 27f07c4f5..3868bf1bb 100644 --- a/persistence/db_sql/wire_provider.go +++ b/persistence/db_sql/wire_provider.go @@ -9,8 +9,8 @@ import ( var Set = wire.NewSet( NewArtistRepository, NewMediaFileRepository, + NewAlbumRepository, db_ledis.NewPropertyRepository, - db_ledis.NewAlbumRepository, db_ledis.NewArtistIndexRepository, db_ledis.NewPlaylistRepository, db_ledis.NewCheckSumRepository, diff --git a/wire_gen.go b/wire_gen.go index 58977b378..20bc7a61f 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -63,7 +63,7 @@ func CreateSubsonicAPIRouter(p persistence.ProviderIdentifier) *api.Router { } func createSQLProvider() *Provider { - albumRepository := db_ledis.NewAlbumRepository() + albumRepository := db_sql.NewAlbumRepository() artistRepository := db_sql.NewArtistRepository() checkSumRepository := db_ledis.NewCheckSumRepository() artistIndexRepository := db_ledis.NewArtistIndexRepository()