leaderboard and ranked systems
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
const db = require('../db');
|
||||
|
||||
async function upsertLeaderboardEntry(userId, grade, { elo, bestTime, correctAnswers = 0 } = {}) {
|
||||
const existing = await db.leaderboardEntry.findUnique({
|
||||
where: { userId_grade: { userId, grade } },
|
||||
});
|
||||
|
||||
return db.leaderboardEntry.upsert({
|
||||
where: { userId_grade: { userId, grade } },
|
||||
create: {
|
||||
userId,
|
||||
grade,
|
||||
elo: elo ?? 800,
|
||||
bestTime: bestTime ?? null,
|
||||
gamesPlayed: 1,
|
||||
totalCorrect: correctAnswers,
|
||||
},
|
||||
update: {
|
||||
...(elo !== undefined && { elo }),
|
||||
...(bestTime !== undefined && existing?.bestTime == null || bestTime < (existing?.bestTime ?? Infinity)
|
||||
? { bestTime }
|
||||
: {}),
|
||||
gamesPlayed: { increment: 1 },
|
||||
totalCorrect: { increment: correctAnswers },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function getLeaderboard(grade, sortBy = 'elo', limit = 10) {
|
||||
const orderBy = sortBy === 'bestTime'
|
||||
? { bestTime: { sort: 'asc', nulls: 'last' } }
|
||||
: { elo: 'desc' };
|
||||
|
||||
const entries = await db.leaderboardEntry.findMany({
|
||||
where: { grade },
|
||||
orderBy,
|
||||
take: limit,
|
||||
include: {
|
||||
user: { select: { displayName: true, avatarUrl: true } },
|
||||
},
|
||||
});
|
||||
|
||||
return entries.map((entry, index) => ({ ...entry, rank: index + 1 }));
|
||||
}
|
||||
|
||||
async function getUserRank(userId, grade, sortBy = 'elo') {
|
||||
const entry = await db.leaderboardEntry.findUnique({
|
||||
where: { userId_grade: { userId, grade } },
|
||||
});
|
||||
|
||||
if (!entry) return null;
|
||||
|
||||
if (sortBy === 'bestTime') {
|
||||
if (entry.bestTime === null) return { rank: null, entry };
|
||||
const count = await db.leaderboardEntry.count({
|
||||
where: {
|
||||
grade,
|
||||
AND: [
|
||||
{ bestTime: { not: null } },
|
||||
{ bestTime: { lt: entry.bestTime } },
|
||||
],
|
||||
},
|
||||
});
|
||||
return { rank: count + 1, entry };
|
||||
}
|
||||
|
||||
const count = await db.leaderboardEntry.count({
|
||||
where: { grade, elo: { gt: entry.elo } },
|
||||
});
|
||||
return { rank: count + 1, entry };
|
||||
}
|
||||
|
||||
module.exports = { upsertLeaderboardEntry, getLeaderboard, getUserRank };
|
||||
Reference in New Issue
Block a user