Add referential integrity to player and playlist tables

This commit is contained in:
Deluan 2020-06-08 17:29:09 -04:00 committed by Deluan Quintão
parent c9bcb333ae
commit 94d88395e7
6 changed files with 142 additions and 5 deletions

View File

@ -37,6 +37,11 @@ update-snapshots: check_go_env
UPDATE_SNAPSHOTS=true ginkgo ./server/subsonic/...
.PHONY: update-snapshots
create-migration:
@if [ -z "${name}" ]; then echo "Usage: make create-migration name=name_of_migration_file"; exit 1; fi
goose -dir db/migration create ${name}
.PHONY: create-migration
setup:
@which go-bindata || (echo "Installing BinData" && GO111MODULE=off go get -u github.com/go-bindata/go-bindata/...)
go mod download

View File

@ -11,7 +11,7 @@ const (
AppName = "navidrome"
LocalConfigFile = "./navidrome.toml"
DefaultDbPath = "navidrome.db?cache=shared&_busy_timeout=15000&_journal_mode=WAL"
DefaultDbPath = "navidrome.db?cache=shared&_busy_timeout=15000&_journal_mode=WAL&_foreign_keys=on"
InitialSetupFlagKey = "InitialSetup"
UIAuthorizationHeader = "X-ND-Authorization"

View File

@ -27,7 +27,7 @@ func Db() *sql.DB {
var err error
Path = conf.Server.DbPath
if Path == ":memory:" {
Path = "file::memory:?cache=shared"
Path = "file::memory:?cache=shared&_foreign_keys=on"
conf.Server.DbPath = Path
}
log.Debug("Opening DataBase", "dbPath", Path, "driver", Driver)

View File

@ -0,0 +1,123 @@
package migration
import (
"database/sql"
"github.com/pressly/goose"
)
func init() {
goose.AddMigration(Up20200608153717, Down20200608153717)
}
func Up20200608153717(tx *sql.Tx) error {
// First delete dangling players
_, err := tx.Exec(`
delete from player where user_name not in (select user_name from user)`)
if err != nil {
return err
}
// Add foreign key to player table
err = updatePlayer_20200608153717(tx)
if err != nil {
return err
}
// Add foreign key to playlist table
err = updatePlaylist_20200608153717(tx)
if err != nil {
return err
}
// Add foreign keys to playlist_tracks table
return updatePlaylistTracks_20200608153717(tx)
}
func updatePlayer_20200608153717(tx *sql.Tx) error {
_, err := tx.Exec(`
create table player_dg_tmp
(
id varchar(255) not null
primary key,
name varchar not null
unique,
type varchar,
user_name varchar not null
references user (user_name)
on update cascade on delete cascade,
client varchar not null,
ip_address varchar,
last_seen timestamp,
max_bit_rate int default 0,
transcoding_id varchar null
);
insert into player_dg_tmp(id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id) select id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id from player;
drop table player;
alter table player_dg_tmp rename to player;
`)
return err
}
func updatePlaylist_20200608153717(tx *sql.Tx) error {
_, err := tx.Exec(`
create table playlist_dg_tmp
(
id varchar(255) not null
primary key,
name varchar(255) default '' not null,
comment varchar(255) default '' not null,
duration real default 0 not null,
song_count integer default 0 not null,
owner varchar(255) default '' not null
constraint playlist_user_user_name_fk
references user (user_name)
on update cascade on delete cascade,
public bool default FALSE not null,
created_at datetime,
updated_at datetime
);
insert into playlist_dg_tmp(id, name, comment, duration, song_count, owner, public, created_at, updated_at) select id, name, comment, duration, song_count, owner, public, created_at, updated_at from playlist;
drop table playlist;
alter table playlist_dg_tmp rename to playlist;
create index playlist_name
on playlist (name);
`)
return err
}
func updatePlaylistTracks_20200608153717(tx *sql.Tx) error {
_, err := tx.Exec(`
create table playlist_tracks_dg_tmp
(
id integer default 0 not null,
playlist_id varchar(255) not null
constraint playlist_tracks_playlist_id_fk
references playlist
on update cascade on delete cascade,
media_file_id varchar(255) not null
);
insert into playlist_tracks_dg_tmp(id, playlist_id, media_file_id) select id, playlist_id, media_file_id from playlist_tracks;
drop table playlist_tracks;
alter table playlist_tracks_dg_tmp rename to playlist_tracks;
create unique index playlist_tracks_pos
on playlist_tracks (playlist_id, id);
`)
return err
}
func Down20200608153717(tx *sql.Tx) error {
return nil
}

View File

@ -46,11 +46,19 @@ func (r *playerRepository) FindByName(client, userName string) (*model.Player, e
func (r *playerRepository) newRestSelect(options ...model.QueryOptions) SelectBuilder {
s := r.newSelect(options...)
return s.Where(r.addRestriction())
}
func (r *playerRepository) addRestriction(sql ...Sqlizer) Sqlizer {
s := And{}
if len(sql) > 0 {
s = append(s, sql[0])
}
u := loggedUser(r.ctx)
if u.IsAdmin {
return s
}
return s.Where(Eq{"user_name": u.UserName})
return append(s, Eq{"user_name": u.UserName})
}
func (r *playerRepository) Count(options ...rest.QueryOptions) (int64, error) {
@ -109,7 +117,8 @@ func (r *playerRepository) Update(entity interface{}, cols ...string) error {
}
func (r *playerRepository) Delete(id string) error {
err := r.delete(And{Eq{"id": id}, Eq{"user_name": loggedUser(r.ctx).UserName}})
filter := r.addRestriction(And{Eq{"id": id}})
err := r.delete(filter)
if err == model.ErrNotFound {
return rest.ErrNotFound
}

View File

@ -1 +1 @@
-s -r "(\.go$$|navidrome.toml|resources)" -R "(Jamstash-master|^ui|^data)" -- go run .
-s -r "(\.go$$|navidrome.toml|resources)" -R "(Jamstash-master|^ui|^data|^db/migration)" -- go run .