Skip to content

Commit

Permalink
Add Redis leaderboards
Browse files Browse the repository at this point in the history
  • Loading branch information
RubberDuckShobe committed Sep 2, 2023
1 parent ee5dccc commit 9b0088a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
36 changes: 36 additions & 0 deletions scripts/initLeaderboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Redis from "ioredis";
import { PrismaClient } from "@prisma/client";
const redis = new Redis(process.env.REDIS_URL);
const prisma = new PrismaClient();

async function main() {
//Get all users and combine all skillPoints across all their scores
const users = await prisma.user.findMany({
include: {
scores: true,
},
});
const usersTotalSkillPoints = users.map((user) => {
const totalPoints = user.scores.reduce((acc, score) => {
return acc + score.skillPoints;
}, 0);
return { ...user, totalSkillPoints: totalPoints };
});
//Add users with total skill points to sorted list in Redis
for (const user of usersTotalSkillPoints) {
await redis.zadd("leaderboard", user.totalSkillPoints, user.id);
}
}

main()
.then(async () => {
await prisma.$disconnect();
})

.catch(async (e) => {
console.error(e);

await prisma.$disconnect();

process.exit(1);
});
41 changes: 27 additions & 14 deletions util/db.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
import { PrismaClient, Song, User } from "@prisma/client";
import Redis from "ioredis";

export const prisma = new PrismaClient({
log: [
{
emit: "event",
level: "query",
export const redis = new Redis(process.env.REDIS_URL);

const prismaOrig = new PrismaClient();
//potentially hacky solution for leaderboard
export const prisma = prismaOrig.$extends({
name: "leaderboardExt",
query: {
score: {
async upsert({ args, query }) {
//If score already exists, add difference of skillPoints to leaderboard ranking
const score = await prisma.score.findUnique({ where: args.where });
if (score) {
//create.score and update.score are the same, the latter has a weird secondary type so no comparisons allowed
if (score.score < args.create.score) {
const diff = args.create.score - score.score;
await redis.zincrby("leaderboard", diff, score.userId);
}
} else {
await redis.zadd(
"leaderboard",
args.create.score,
args.create.userId
);
}
return query(args);
},
},
],
},
});

export const redis = new Redis(process.env.REDIS_URL);

export interface ExtendedUser extends User {
totalScore: number;
totalPlays: number;
favoriteCharacter?: number;
favoriteSong?: Song;
}

/*
prisma.$on("query", (e) => {
console.log("DB query took " + e.duration + "ms");
});
*/

0 comments on commit 9b0088a

Please sign in to comment.