Add player leaderboard and homepage preview
This commit is contained in:
61
supabase/migrations/20261006093345_player_leaderboard.sql
Normal file
61
supabase/migrations/20261006093345_player_leaderboard.sql
Normal file
@@ -0,0 +1,61 @@
|
||||
-- Read through the server only: never expose session secrets or round answers.
|
||||
create index game_sessions_leaderboard_idx
|
||||
on public.game_sessions (difficulty, owner_id)
|
||||
where current_round = 5 and owner_id is not null;
|
||||
|
||||
create function public.player_leaderboard(
|
||||
p_difficulty text default 'all',
|
||||
p_search text default '',
|
||||
p_page integer default 1,
|
||||
p_limit integer default 25
|
||||
) returns jsonb
|
||||
language sql stable security invoker set search_path = '' as $$
|
||||
with completed as (
|
||||
select s.id, s.owner_id, sum((r.result->>'score')::integer) as score
|
||||
from public.game_sessions s
|
||||
join public.game_rounds r on r.session_id = s.id
|
||||
where s.current_round = 5 and s.owner_id is not null
|
||||
and (p_difficulty = 'all' or s.difficulty = p_difficulty)
|
||||
group by s.id, s.owner_id
|
||||
having count(*) = 5 and count(r.result) = 5
|
||||
), players as (
|
||||
select p.id as player_id, p.display_name,
|
||||
max(c.score) as best_score, avg(c.score) as average_score,
|
||||
count(*) as games_played
|
||||
from completed c join public.profiles p on p.id = c.owner_id
|
||||
group by p.id, p.display_name
|
||||
), ranked as (
|
||||
select row_number() over (
|
||||
order by best_score desc, average_score desc, games_played desc, player_id
|
||||
) as rank, player_id, display_name, best_score,
|
||||
round(average_score)::integer as average_score, games_played
|
||||
from players
|
||||
), matched as (
|
||||
select * from ranked
|
||||
where strpos(lower(display_name), lower(left(trim(coalesce(p_search, '')), 64))) > 0
|
||||
), settings as (
|
||||
select greatest(1, least(coalesce(p_limit, 25), 100)) as page_size
|
||||
), counts as (
|
||||
select (select count(*) from matched) as matching_players,
|
||||
greatest(1, ceil((select count(*) from matched)::numeric / settings.page_size)::integer) as pages
|
||||
from settings
|
||||
), pagination as (
|
||||
select *, greatest(1, least(coalesce(p_page, 1), pages)) as page
|
||||
from counts cross join settings
|
||||
), entries as (
|
||||
select * from matched order by rank
|
||||
limit (select page_size from pagination)
|
||||
offset (select (page - 1) * page_size from pagination)
|
||||
)
|
||||
select jsonb_build_object(
|
||||
'entries', coalesce((select jsonb_agg(to_jsonb(e) order by rank) from entries e), '[]'::jsonb),
|
||||
'leaders', coalesce((select jsonb_agg(to_jsonb(r) order by rank) from
|
||||
(select * from ranked order by rank limit 3) r), '[]'::jsonb),
|
||||
'total_players', (select count(*) from ranked),
|
||||
'total_games', (select count(*) from completed),
|
||||
'matching_players', matching_players, 'page', page, 'pages', pages
|
||||
) from pagination;
|
||||
$$;
|
||||
|
||||
revoke all on function public.player_leaderboard(text, text, integer, integer) from public, anon, authenticated;
|
||||
grant execute on function public.player_leaderboard(text, text, integer, integer) to service_role;
|
||||
Reference in New Issue
Block a user