Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions supabase/migrations/20260805000000_fix_leaderboard_pagination.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
-- Fix Issue 1913: Leaderboard pagination causes duplicate user entries between pages
-- Adds l.id ASC to ORDER BY clauses in get_leaderboard to make sorting deterministic

CREATE OR REPLACE FUNCTION public.get_leaderboard(
_timeframe text,
_limit int DEFAULT 100,
_offset int DEFAULT 0
)
RETURNS TABLE (
id uuid,
user_id uuid,
username text,
avatar_url text,
xp bigint,
streak int,
sessions_joined int,
badges text[],
updated_at text
) LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$
BEGIN
IF _timeframe = 'All Time' THEN
RETURN QUERY
SELECT l.id, l.user_id, l.username, l.avatar_url, l.xp::bigint, l.streak, l.sessions_joined, l.badges, ''::text AS updated_at
FROM public.leaderboard l
ORDER BY l.xp DESC, l.id ASC
LIMIT _limit OFFSET _offset;
ELSIF _timeframe = 'Weekly' THEN
RETURN QUERY
SELECT l.id, l.user_id, l.username, l.avatar_url, COALESCE(SUM(t.amount), 0)::bigint AS xp, l.streak, l.sessions_joined, l.badges, ''::text AS updated_at
FROM public.leaderboard l
JOIN public.xp_transactions t ON l.user_id = t.user_id
WHERE t.created_at >= date_trunc('week', now())
GROUP BY l.id, l.user_id, l.username, l.avatar_url, l.streak, l.sessions_joined, l.badges
ORDER BY xp DESC, l.id ASC
LIMIT _limit OFFSET _offset;
ELSIF _timeframe = 'Monthly' THEN
RETURN QUERY
SELECT l.id, l.user_id, l.username, l.avatar_url, COALESCE(SUM(t.amount), 0)::bigint AS xp, l.streak, l.sessions_joined, l.badges, ''::text AS updated_at
FROM public.leaderboard l
JOIN public.xp_transactions t ON l.user_id = t.user_id
WHERE t.created_at >= date_trunc('month', now())
GROUP BY l.id, l.user_id, l.username, l.avatar_url, l.streak, l.sessions_joined, l.badges
ORDER BY xp DESC, l.id ASC
LIMIT _limit OFFSET _offset;
ELSE
RETURN QUERY
SELECT l.id, l.user_id, l.username, l.avatar_url, l.xp::bigint, l.streak, l.sessions_joined, l.badges, ''::text AS updated_at
FROM public.leaderboard l
ORDER BY l.xp DESC, l.id ASC
LIMIT _limit OFFSET _offset;
END IF;
END;
$$;
Loading