feat: Rename game to soundtrack throughout codebase

- Database migration: rename game table to soundtrack
- Rename game_name to soundtrack_name, game_id to soundtrack_id
- Update all SQL queries in soundtrack.sql, song.sql, song_list.sql, statistics.sql
- Regenerate sqlc code (soundtrack.sql.go, song.sql.go, etc.)
- Update backend: music.go, sync.go, statistics.go
- Update server: musicHandler.go, syncHandler.go, routes.go
- Update frontend: hello.go
- Keep URL paths as /games for backward compatibility

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-06-01 20:23:05 +02:00
parent c63202242b
commit 90d621c195
20 changed files with 760 additions and 694 deletions
+131 -131
View File
@@ -12,10 +12,10 @@ import (
const getLastPlayedGames = `-- name: GetLastPlayedGames :many
SELECT
g.id as game_id,
g.game_name,
g.times_played as game_played,
g.last_played as game_last_played,
g.id as soundtrack_id,
g.soundtrack_name,
g.times_played as soundtrack_played,
g.last_played as soundtrack_last_played,
json_agg(
json_build_object(
'song_name', s.song_name,
@@ -23,23 +23,23 @@ SELECT
'times_played', s.times_played
)
) as songs
FROM game g
LEFT JOIN song s ON g.id = s.game_id
FROM soundtrack g
LEFT JOIN song s ON g.id = s.soundtrack_id
WHERE g.deleted IS NULL AND g.last_played IS NOT NULL
GROUP BY g.id, g.game_name, g.times_played, g.last_played
GROUP BY g.id, g.soundtrack_name, g.times_played, g.last_played
ORDER BY g.last_played DESC
LIMIT $1
`
type GetLastPlayedGamesRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
GamePlayed int32 `json:"game_played"`
GameLastPlayed *time.Time `json:"game_last_played"`
Songs []byte `json:"songs"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SoundtrackPlayed int32 `json:"soundtrack_played"`
SoundtrackLastPlayed *time.Time `json:"soundtrack_last_played"`
Songs []byte `json:"songs"`
}
// Last played games (most recently played)
// Last played soundtracks (most recently played)
func (q *Queries) GetLastPlayedGames(ctx context.Context, limit int32) ([]GetLastPlayedGamesRow, error) {
rows, err := q.db.Query(ctx, getLastPlayedGames, limit)
if err != nil {
@@ -50,10 +50,10 @@ func (q *Queries) GetLastPlayedGames(ctx context.Context, limit int32) ([]GetLas
for rows.Next() {
var i GetLastPlayedGamesRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.GamePlayed,
&i.GameLastPlayed,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SoundtrackPlayed,
&i.SoundtrackLastPlayed,
&i.Songs,
); err != nil {
return nil, err
@@ -68,10 +68,10 @@ func (q *Queries) GetLastPlayedGames(ctx context.Context, limit int32) ([]GetLas
const getLeastPlayedGamesWithSongs = `-- name: GetLeastPlayedGamesWithSongs :many
SELECT
g.id as game_id,
g.game_name,
g.times_played as game_played,
g.last_played as game_last_played,
g.id as soundtrack_id,
g.soundtrack_name,
g.times_played as soundtrack_played,
g.last_played as soundtrack_last_played,
json_agg(
json_build_object(
'song_name', s.song_name,
@@ -80,23 +80,23 @@ SELECT
'file_name', s.file_name
)
) as songs
FROM game g
LEFT JOIN song s ON g.id = s.game_id
FROM soundtrack g
LEFT JOIN song s ON g.id = s.soundtrack_id
WHERE g.deleted IS NULL
GROUP BY g.id, g.game_name, g.times_played, g.last_played
ORDER BY g.times_played ASC, g.game_name
GROUP BY g.id, g.soundtrack_name, g.times_played, g.last_played
ORDER BY g.times_played ASC, g.soundtrack_name
LIMIT $1
`
type GetLeastPlayedGamesWithSongsRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
GamePlayed int32 `json:"game_played"`
GameLastPlayed *time.Time `json:"game_last_played"`
Songs []byte `json:"songs"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SoundtrackPlayed int32 `json:"soundtrack_played"`
SoundtrackLastPlayed *time.Time `json:"soundtrack_last_played"`
Songs []byte `json:"songs"`
}
// Least played games with their songs
// Least played soundtracks with their songs
func (q *Queries) GetLeastPlayedGamesWithSongs(ctx context.Context, limit int32) ([]GetLeastPlayedGamesWithSongsRow, error) {
rows, err := q.db.Query(ctx, getLeastPlayedGamesWithSongs, limit)
if err != nil {
@@ -107,10 +107,10 @@ func (q *Queries) GetLeastPlayedGamesWithSongs(ctx context.Context, limit int32)
for rows.Next() {
var i GetLeastPlayedGamesWithSongsRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.GamePlayed,
&i.GameLastPlayed,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SoundtrackPlayed,
&i.SoundtrackLastPlayed,
&i.Songs,
); err != nil {
return nil, err
@@ -125,29 +125,29 @@ func (q *Queries) GetLeastPlayedGamesWithSongs(ctx context.Context, limit int32)
const getLeastPlayedSongsWithGame = `-- name: GetLeastPlayedSongsWithGame :many
SELECT
s.game_id as game_id,
g.game_name,
s.soundtrack_id as soundtrack_id,
g.soundtrack_name,
s.song_name,
s.path,
s.times_played,
s.file_name
FROM song s
JOIN game g ON s.game_id = g.id
JOIN soundtrack g ON s.soundtrack_id = g.id
WHERE g.deleted IS NULL
ORDER BY s.times_played ASC, s.song_name
LIMIT $1
`
type GetLeastPlayedSongsWithGameRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
SongName string `json:"song_name"`
Path string `json:"path"`
TimesPlayed int32 `json:"times_played"`
FileName *string `json:"file_name"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SongName string `json:"song_name"`
Path string `json:"path"`
TimesPlayed int32 `json:"times_played"`
FileName *string `json:"file_name"`
}
// Least played songs with their game info
// Least played songs with their soundtrack info
func (q *Queries) GetLeastPlayedSongsWithGame(ctx context.Context, limit int32) ([]GetLeastPlayedSongsWithGameRow, error) {
rows, err := q.db.Query(ctx, getLeastPlayedSongsWithGame, limit)
if err != nil {
@@ -158,8 +158,8 @@ func (q *Queries) GetLeastPlayedSongsWithGame(ctx context.Context, limit int32)
for rows.Next() {
var i GetLeastPlayedSongsWithGameRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SongName,
&i.Path,
&i.TimesPlayed,
@@ -177,10 +177,10 @@ func (q *Queries) GetLeastPlayedSongsWithGame(ctx context.Context, limit int32)
const getMostPlayedGamesWithSongs = `-- name: GetMostPlayedGamesWithSongs :many
SELECT
g.id as game_id,
g.game_name,
g.times_played as game_played,
g.last_played as game_last_played,
g.id as soundtrack_id,
g.soundtrack_name,
g.times_played as soundtrack_played,
g.last_played as soundtrack_last_played,
json_agg(
json_build_object(
'song_name', s.song_name,
@@ -189,23 +189,23 @@ SELECT
'file_name', s.file_name
)
) as songs
FROM game g
LEFT JOIN song s ON g.id = s.game_id
FROM soundtrack g
LEFT JOIN song s ON g.id = s.soundtrack_id
WHERE g.deleted IS NULL
GROUP BY g.id, g.game_name, g.times_played, g.last_played
ORDER BY g.times_played DESC, g.game_name
GROUP BY g.id, g.soundtrack_name, g.times_played, g.last_played
ORDER BY g.times_played DESC, g.soundtrack_name
LIMIT $1
`
type GetMostPlayedGamesWithSongsRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
GamePlayed int32 `json:"game_played"`
GameLastPlayed *time.Time `json:"game_last_played"`
Songs []byte `json:"songs"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SoundtrackPlayed int32 `json:"soundtrack_played"`
SoundtrackLastPlayed *time.Time `json:"soundtrack_last_played"`
Songs []byte `json:"songs"`
}
// Most played games with their songs
// Most played soundtracks with their songs
func (q *Queries) GetMostPlayedGamesWithSongs(ctx context.Context, limit int32) ([]GetMostPlayedGamesWithSongsRow, error) {
rows, err := q.db.Query(ctx, getMostPlayedGamesWithSongs, limit)
if err != nil {
@@ -216,10 +216,10 @@ func (q *Queries) GetMostPlayedGamesWithSongs(ctx context.Context, limit int32)
for rows.Next() {
var i GetMostPlayedGamesWithSongsRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.GamePlayed,
&i.GameLastPlayed,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SoundtrackPlayed,
&i.SoundtrackLastPlayed,
&i.Songs,
); err != nil {
return nil, err
@@ -234,29 +234,29 @@ func (q *Queries) GetMostPlayedGamesWithSongs(ctx context.Context, limit int32)
const getMostPlayedSongsWithGame = `-- name: GetMostPlayedSongsWithGame :many
SELECT
s.game_id as game_id,
g.game_name,
s.soundtrack_id as soundtrack_id,
g.soundtrack_name,
s.song_name,
s.path,
s.times_played,
s.file_name
FROM song s
JOIN game g ON s.game_id = g.id
JOIN soundtrack g ON s.soundtrack_id = g.id
WHERE g.deleted IS NULL
ORDER BY s.times_played DESC, s.song_name
LIMIT $1
`
type GetMostPlayedSongsWithGameRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
SongName string `json:"song_name"`
Path string `json:"path"`
TimesPlayed int32 `json:"times_played"`
FileName *string `json:"file_name"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SongName string `json:"song_name"`
Path string `json:"path"`
TimesPlayed int32 `json:"times_played"`
FileName *string `json:"file_name"`
}
// Most played songs with their game info
// Most played songs with their soundtrack info
func (q *Queries) GetMostPlayedSongsWithGame(ctx context.Context, limit int32) ([]GetMostPlayedSongsWithGameRow, error) {
rows, err := q.db.Query(ctx, getMostPlayedSongsWithGame, limit)
if err != nil {
@@ -267,8 +267,8 @@ func (q *Queries) GetMostPlayedSongsWithGame(ctx context.Context, limit int32) (
for rows.Next() {
var i GetMostPlayedSongsWithGameRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SongName,
&i.Path,
&i.TimesPlayed,
@@ -286,9 +286,9 @@ func (q *Queries) GetMostPlayedSongsWithGame(ctx context.Context, limit int32) (
const getNeverPlayedGames = `-- name: GetNeverPlayedGames :many
SELECT
g.id as game_id,
g.game_name,
g.times_played as game_played,
g.id as soundtrack_id,
g.soundtrack_name,
g.times_played as soundtrack_played,
g.added,
json_agg(
json_build_object(
@@ -297,19 +297,19 @@ SELECT
'times_played', s.times_played
)
) as songs
FROM game g
LEFT JOIN song s ON g.id = s.game_id
FROM soundtrack g
LEFT JOIN song s ON g.id = s.soundtrack_id
WHERE g.deleted IS NULL AND g.times_played = 0
GROUP BY g.id, g.game_name, g.times_played, g.added
ORDER BY g.game_name
GROUP BY g.id, g.soundtrack_name, g.times_played, g.added
ORDER BY g.soundtrack_name
`
type GetNeverPlayedGamesRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
GamePlayed int32 `json:"game_played"`
Added time.Time `json:"added"`
Songs []byte `json:"songs"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SoundtrackPlayed int32 `json:"soundtrack_played"`
Added time.Time `json:"added"`
Songs []byte `json:"songs"`
}
// Games that have never been played (times_played = 0)
@@ -323,9 +323,9 @@ func (q *Queries) GetNeverPlayedGames(ctx context.Context) ([]GetNeverPlayedGame
for rows.Next() {
var i GetNeverPlayedGamesRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.GamePlayed,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SoundtrackPlayed,
&i.Added,
&i.Songs,
); err != nil {
@@ -341,10 +341,10 @@ func (q *Queries) GetNeverPlayedGames(ctx context.Context) ([]GetNeverPlayedGame
const getOldestPlayedGames = `-- name: GetOldestPlayedGames :many
SELECT
g.id as game_id,
g.game_name,
g.times_played as game_played,
g.last_played as game_last_played,
g.id as soundtrack_id,
g.soundtrack_name,
g.times_played as soundtrack_played,
g.last_played as soundtrack_last_played,
json_agg(
json_build_object(
'song_name', s.song_name,
@@ -352,23 +352,23 @@ SELECT
'times_played', s.times_played
)
) as songs
FROM game g
LEFT JOIN song s ON g.id = s.game_id
FROM soundtrack g
LEFT JOIN song s ON g.id = s.soundtrack_id
WHERE g.deleted IS NULL AND g.last_played IS NOT NULL
GROUP BY g.id, g.game_name, g.times_played, g.last_played
GROUP BY g.id, g.soundtrack_name, g.times_played, g.last_played
ORDER BY g.last_played ASC
LIMIT $1
`
type GetOldestPlayedGamesRow struct {
GameID int32 `json:"game_id"`
GameName string `json:"game_name"`
GamePlayed int32 `json:"game_played"`
GameLastPlayed *time.Time `json:"game_last_played"`
Songs []byte `json:"songs"`
SoundtrackID int32 `json:"soundtrack_id"`
SoundtrackName string `json:"soundtrack_name"`
SoundtrackPlayed int32 `json:"soundtrack_played"`
SoundtrackLastPlayed *time.Time `json:"soundtrack_last_played"`
Songs []byte `json:"songs"`
}
// Oldest played games (least recently played, but has been played at least once)
// Oldest played soundtracks (least recently played, but has been played at least once)
func (q *Queries) GetOldestPlayedGames(ctx context.Context, limit int32) ([]GetOldestPlayedGamesRow, error) {
rows, err := q.db.Query(ctx, getOldestPlayedGames, limit)
if err != nil {
@@ -379,10 +379,10 @@ func (q *Queries) GetOldestPlayedGames(ctx context.Context, limit int32) ([]GetO
for rows.Next() {
var i GetOldestPlayedGamesRow
if err := rows.Scan(
&i.GameID,
&i.GameName,
&i.GamePlayed,
&i.GameLastPlayed,
&i.SoundtrackID,
&i.SoundtrackName,
&i.SoundtrackPlayed,
&i.SoundtrackLastPlayed,
&i.Songs,
); err != nil {
return nil, err
@@ -397,25 +397,25 @@ func (q *Queries) GetOldestPlayedGames(ctx context.Context, limit int32) ([]GetO
const getStatisticsSummary = `-- name: GetStatisticsSummary :one
SELECT
COUNT(*) as total_games,
SUM(CASE WHEN times_played > 0 THEN 1 ELSE 0 END) as played_games,
SUM(CASE WHEN times_played = 0 THEN 1 ELSE 0 END) as never_played_games,
COALESCE(SUM(times_played), 0)::bigint as total_game_plays,
COALESCE(AVG(times_played), 0)::float as avg_game_plays,
COALESCE(MAX(times_played), 0)::bigint as max_game_plays,
COALESCE(MIN(times_played), 0)::bigint as min_game_plays
FROM game
COUNT(*) as total_soundtracks,
SUM(CASE WHEN times_played > 0 THEN 1 ELSE 0 END) as played_soundtracks,
SUM(CASE WHEN times_played = 0 THEN 1 ELSE 0 END) as never_played_soundtracks,
COALESCE(SUM(times_played), 0)::bigint as total_soundtrack_plays,
COALESCE(AVG(times_played), 0)::float as avg_soundtrack_plays,
COALESCE(MAX(times_played), 0)::bigint as max_soundtrack_plays,
COALESCE(MIN(times_played), 0)::bigint as min_soundtrack_plays
FROM soundtrack
WHERE deleted IS NULL
`
type GetStatisticsSummaryRow struct {
TotalGames int64 `json:"total_games"`
PlayedGames int64 `json:"played_games"`
NeverPlayedGames int64 `json:"never_played_games"`
TotalGamePlays int64 `json:"total_game_plays"`
AvgGamePlays float64 `json:"avg_game_plays"`
MaxGamePlays int64 `json:"max_game_plays"`
MinGamePlays int64 `json:"min_game_plays"`
TotalSoundtracks int64 `json:"total_soundtracks"`
PlayedSoundtracks int64 `json:"played_soundtracks"`
NeverPlayedSoundtracks int64 `json:"never_played_soundtracks"`
TotalSoundtrackPlays int64 `json:"total_soundtrack_plays"`
AvgSoundtrackPlays float64 `json:"avg_soundtrack_plays"`
MaxSoundtrackPlays int64 `json:"max_soundtrack_plays"`
MinSoundtrackPlays int64 `json:"min_soundtrack_plays"`
}
// Get statistics summary
@@ -423,13 +423,13 @@ func (q *Queries) GetStatisticsSummary(ctx context.Context) (GetStatisticsSummar
row := q.db.QueryRow(ctx, getStatisticsSummary)
var i GetStatisticsSummaryRow
err := row.Scan(
&i.TotalGames,
&i.PlayedGames,
&i.NeverPlayedGames,
&i.TotalGamePlays,
&i.AvgGamePlays,
&i.MaxGamePlays,
&i.MinGamePlays,
&i.TotalSoundtracks,
&i.PlayedSoundtracks,
&i.NeverPlayedSoundtracks,
&i.TotalSoundtrackPlays,
&i.AvgSoundtrackPlays,
&i.MaxSoundtrackPlays,
&i.MinSoundtrackPlays,
)
return i, err
}