navidrome/persistence/sql_annotations.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

112 lines
3.2 KiB
Go
Raw Permalink Normal View History

2020-02-01 03:09:23 +01:00
package persistence
import (
"database/sql"
2022-10-01 00:54:25 +02:00
"errors"
2020-02-01 03:09:23 +01:00
"time"
. "github.com/Masterminds/squirrel"
"github.com/google/uuid"
2024-05-02 02:05:36 +02:00
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
2020-02-01 18:15:12 +01:00
"github.com/navidrome/navidrome/log"
2020-02-01 03:09:23 +01:00
"github.com/navidrome/navidrome/model"
)
const annotationTable = "annotation"
func (r sqlRepository) newSelectWithAnnotation(idField string, options ...model.QueryOptions) SelectBuilder {
2024-05-02 02:05:36 +02:00
query := r.newSelect(options...).
2020-02-01 03:09:23 +01:00
LeftJoin("annotation on ("+
"annotation.item_id = "+idField+
" AND annotation.item_type = '"+r.tableName+"'"+
" AND annotation.user_id = '"+userId(r.ctx)+"')").
Columns(
"coalesce(starred, 0) as starred",
"coalesce(rating, 0) as rating",
"starred_at",
"play_date",
)
2024-05-02 02:05:36 +02:00
if conf.Server.AlbumPlayCountMode == consts.AlbumPlayCountModeNormalized && r.tableName == "album" {
query = query.Columns("round(coalesce(round(cast(play_count as float) / coalesce(song_count, 1), 1), 0)) as play_count")
2024-05-02 02:05:36 +02:00
} else {
query = query.Columns("coalesce(play_count, 0) as play_count")
}
return query
2020-02-01 03:09:23 +01:00
}
func (r sqlRepository) annId(itemID ...string) And {
return And{
Eq{annotationTable + ".user_id": userId(r.ctx)},
Eq{annotationTable + ".item_type": r.tableName},
Eq{annotationTable + ".item_id": itemID},
}
}
2020-02-01 03:09:23 +01:00
func (r sqlRepository) annUpsert(values map[string]interface{}, itemIDs ...string) error {
upd := Update(annotationTable).Where(r.annId(itemIDs...))
for f, v := range values {
upd = upd.Set(f, v)
}
c, err := r.executeSQL(upd)
if c == 0 || errors.Is(err, sql.ErrNoRows) {
2020-02-01 03:09:23 +01:00
for _, itemID := range itemIDs {
values["ann_id"] = uuid.NewString()
2020-02-01 03:09:23 +01:00
values["user_id"] = userId(r.ctx)
values["item_type"] = r.tableName
values["item_id"] = itemID
ins := Insert(annotationTable).SetMap(values)
_, err = r.executeSQL(ins)
if err != nil {
return err
}
}
}
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)
2020-02-01 03:09:23 +01:00
}
func (r sqlRepository) IncPlayCount(itemID string, ts time.Time) error {
upd := Update(annotationTable).Where(r.annId(itemID)).
Set("play_count", Expr("play_count+1")).
Set("play_date", Expr("max(ifnull(play_date,''),?)", ts))
2020-02-01 03:09:23 +01:00
c, err := r.executeSQL(upd)
if c == 0 || errors.Is(err, sql.ErrNoRows) {
2020-02-01 03:09:23 +01:00
values := map[string]interface{}{}
values["ann_id"] = uuid.NewString()
2020-02-01 03:09:23 +01:00
values["user_id"] = userId(r.ctx)
values["item_type"] = r.tableName
values["item_id"] = itemID
values["play_count"] = 1
values["play_date"] = ts
ins := Insert(annotationTable).SetMap(values)
_, err = r.executeSQL(ins)
if err != nil {
return err
}
}
return err
}
2020-02-01 18:15:12 +01:00
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)
if err != nil {
return err
}
if c > 0 {
log.Debug(r.ctx, "Clean-up annotations", "table", r.tableName, "totalDeleted", c)
}
return nil
}