diff --git a/persistence/album_repository.go b/persistence/album_repository.go index bc9eee365..8511106d7 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -33,7 +33,8 @@ func (r *albumRepository) Exists(id string) (bool, error) { } func (r *albumRepository) Put(a *model.Album) error { - return r.put(a.ID, a) + _, err := r.put(a.ID, a) + return err } func (r *albumRepository) selectAlbum(options ...model.QueryOptions) SelectBuilder { diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index 2210f54eb..78bf5d146 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -53,7 +53,8 @@ func (r *artistRepository) getIndexKey(a *model.Artist) string { } func (r *artistRepository) Put(a *model.Artist) error { - return r.put(a.ID, a) + _, err := r.put(a.ID, a) + return err } func (r *artistRepository) Get(id string) (*model.Artist, error) { diff --git a/persistence/mediafile_repository.go b/persistence/mediafile_repository.go index e304ce713..6e2e1e9c2 100644 --- a/persistence/mediafile_repository.go +++ b/persistence/mediafile_repository.go @@ -2,13 +2,11 @@ package persistence import ( "context" - "strings" . "github.com/Masterminds/squirrel" "github.com/astaxie/beego/orm" "github.com/deluan/navidrome/model" "github.com/deluan/rest" - "github.com/kennygrant/sanitize" ) type mediaFileRepository struct { @@ -32,7 +30,12 @@ func (r mediaFileRepository) Exists(id string) (bool, error) { } func (r mediaFileRepository) Put(m *model.MediaFile) error { - return r.put(m.ID, m) + _, err := r.put(m.ID, m) + if err != nil { + return err + } + r.index(m.ID, m.Title) + return nil } func (r mediaFileRepository) selectMediaFile(options ...model.QueryOptions) SelectBuilder { @@ -103,26 +106,8 @@ func (r mediaFileRepository) DeleteByPath(path string) error { } func (r mediaFileRepository) Search(q string, offset int, size int) (model.MediaFiles, error) { - q = strings.TrimSpace(sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))) - if len(q) <= 2 { - return model.MediaFiles{}, nil - } - sq := Select("*").From(r.tableName) - sq = sq.Limit(uint64(size)).Offset(uint64(offset)).OrderBy("title") - sq = sq.Join("search").Where("search.id = " + r.tableName + ".id") - parts := strings.Split(q, " ") - for _, part := range parts { - sq = sq.Where(Or{ - Like{"full_text": part + "%"}, - Like{"full_text": "%" + part + "%"}, - }) - } - sql, args, err := r.toSql(sq) - if err != nil { - return nil, err - } var results model.MediaFiles - _, err = r.ormer.Raw(sql, args...).QueryRows(results) + err := r.doSearch(q, offset, size, &results, "title") return results, err } diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go index 7477dc59d..1f50667ed 100644 --- a/persistence/playlist_repository.go +++ b/persistence/playlist_repository.go @@ -7,7 +7,6 @@ import ( . "github.com/Masterminds/squirrel" "github.com/astaxie/beego/orm" "github.com/deluan/navidrome/model" - "github.com/google/uuid" ) type playlist struct { @@ -45,12 +44,9 @@ func (r *playlistRepository) Delete(id string) error { } func (r *playlistRepository) Put(p *model.Playlist) error { - if p.ID == "" { - id, _ := uuid.NewRandom() - p.ID = id.String() - } pls := r.fromModel(p) - return r.put(p.ID, &pls) + _, err := r.put(pls.ID, pls) + return err } func (r *playlistRepository) Get(id string) (*model.Playlist, error) { diff --git a/persistence/search.go b/persistence/search.go new file mode 100644 index 000000000..404872738 --- /dev/null +++ b/persistence/search.go @@ -0,0 +1,56 @@ +package persistence + +import ( + "strings" + + . "github.com/Masterminds/squirrel" + "github.com/kennygrant/sanitize" +) + +const searchTable = "search" + +func (r sqlRepository) index(id string, text string) error { + sanitizedText := strings.TrimSpace(sanitize.Accents(strings.ToLower(text))) + + values := map[string]interface{}{ + "id": id, + "full_text": sanitizedText, + } + update := Update(searchTable).Where(Eq{"id": id}).SetMap(values) + count, err := r.executeSQL(update) + if err != nil { + return err + } + if count > 0 { + return nil + } + insert := Insert(searchTable).SetMap(values) + _, err = r.executeSQL(insert) + return err +} + +func (r sqlRepository) doSearch(q string, offset, size int, results interface{}, orderBys ...string) error { + q = strings.TrimSpace(sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))) + if len(q) <= 2 { + return nil + } + sq := Select("*").From(r.tableName) + sq = sq.Limit(uint64(size)).Offset(uint64(offset)) + if len(orderBys) > 0 { + sq = sq.OrderBy(orderBys...) + } + sq = sq.Join("search").Where("search.id = " + r.tableName + ".id") + parts := strings.Split(q, " ") + for _, part := range parts { + sq = sq.Where(Or{ + Like{"full_text": part + "%"}, + Like{"full_text": "%" + part + "%"}, + }) + } + sql, args, err := r.toSql(sq) + if err != nil { + return err + } + _, err = r.ormer.Raw(sql, args...).QueryRows(results) + return err +} diff --git a/persistence/sql_repository.go b/persistence/sql_repository.go index 7eb66a873..7313de929 100644 --- a/persistence/sql_repository.go +++ b/persistence/sql_repository.go @@ -137,26 +137,27 @@ func (r sqlRepository) count(countQuery SelectBuilder, options ...model.QueryOpt return res.Count, nil } -func (r *sqlRepository) put(id string, m interface{}) error { +func (r *sqlRepository) put(id string, m interface{}) (newId string, err error) { values, _ := toSqlArgs(m) if id != "" { update := Update(r.tableName).Where(Eq{"id": id}).SetMap(values) count, err := r.executeSQL(update) if err != nil { - return err + return "", err } if count > 0 { - return nil + return id, nil } } // if does not have an id OR could not update (new record with predefined id) if id == "" { rand, _ := uuid.NewRandom() - values["id"] = rand.String() + id = rand.String() + values["id"] = id } insert := Insert(r.tableName).SetMap(values) - _, err := r.executeSQL(insert) - return err + _, err = r.executeSQL(insert) + return id, err } func (r sqlRepository) delete(cond Sqlizer) error {