f4d1c3cf28
- Add statistics.sql with 8 SQL queries for play count statistics - Generate repository code via sqlc - Add backend/statistics.go with business logic - Add server/statistics_handler.go with Echo handlers - Register protected routes under /api/v1/statistics/ with token auth - Endpoints: games/most-played, games/least-played, games/never-played, games/last-played, games/oldest-played, songs/most-played, songs/least-played, summary Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
149 lines
4.0 KiB
SQL
149 lines
4.0 KiB
SQL
-- Most played games with their songs
|
|
-- 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,
|
|
json_agg(
|
|
json_build_object(
|
|
'song_name', s.song_name,
|
|
'path', s.path,
|
|
'times_played', s.times_played,
|
|
'file_name', s.file_name
|
|
)
|
|
) as songs
|
|
FROM game g
|
|
LEFT JOIN song s ON g.id = s.game_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
|
|
LIMIT $1;
|
|
|
|
-- Least played games with their songs
|
|
-- 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,
|
|
json_agg(
|
|
json_build_object(
|
|
'song_name', s.song_name,
|
|
'path', s.path,
|
|
'times_played', s.times_played,
|
|
'file_name', s.file_name
|
|
)
|
|
) as songs
|
|
FROM game g
|
|
LEFT JOIN song s ON g.id = s.game_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
|
|
LIMIT $1;
|
|
|
|
-- Most played songs with their game info
|
|
-- name: GetMostPlayedSongsWithGame :many
|
|
SELECT
|
|
s.game_id as game_id,
|
|
g.game_name,
|
|
s.song_name,
|
|
s.path,
|
|
s.times_played,
|
|
s.file_name
|
|
FROM song s
|
|
JOIN game g ON s.game_id = g.id
|
|
WHERE g.deleted IS NULL
|
|
ORDER BY s.times_played DESC, s.song_name
|
|
LIMIT $1;
|
|
|
|
-- Least played songs with their game info
|
|
-- name: GetLeastPlayedSongsWithGame :many
|
|
SELECT
|
|
s.game_id as game_id,
|
|
g.game_name,
|
|
s.song_name,
|
|
s.path,
|
|
s.times_played,
|
|
s.file_name
|
|
FROM song s
|
|
JOIN game g ON s.game_id = g.id
|
|
WHERE g.deleted IS NULL
|
|
ORDER BY s.times_played ASC, s.song_name
|
|
LIMIT $1;
|
|
|
|
-- Games that have never been played (times_played = 0)
|
|
-- name: GetNeverPlayedGames :many
|
|
SELECT
|
|
g.id as game_id,
|
|
g.game_name,
|
|
g.times_played as game_played,
|
|
g.added,
|
|
json_agg(
|
|
json_build_object(
|
|
'song_name', s.song_name,
|
|
'path', s.path,
|
|
'times_played', s.times_played
|
|
)
|
|
) as songs
|
|
FROM game g
|
|
LEFT JOIN song s ON g.id = s.game_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;
|
|
|
|
-- Last played games (most recently played)
|
|
-- 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,
|
|
json_agg(
|
|
json_build_object(
|
|
'song_name', s.song_name,
|
|
'path', s.path,
|
|
'times_played', s.times_played
|
|
)
|
|
) as songs
|
|
FROM game g
|
|
LEFT JOIN song s ON g.id = s.game_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
|
|
ORDER BY g.last_played DESC
|
|
LIMIT $1;
|
|
|
|
-- Oldest played games (least recently played, but has been played at least once)
|
|
-- 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,
|
|
json_agg(
|
|
json_build_object(
|
|
'song_name', s.song_name,
|
|
'path', s.path,
|
|
'times_played', s.times_played
|
|
)
|
|
) as songs
|
|
FROM game g
|
|
LEFT JOIN song s ON g.id = s.game_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
|
|
ORDER BY g.last_played ASC
|
|
LIMIT $1;
|
|
|
|
-- Get statistics summary
|
|
-- 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
|
|
WHERE deleted IS NULL;
|