diff --git a/apps/api/src/leaderboards/leaderboard.service.ts b/apps/api/src/leaderboards/leaderboard.service.ts index 58a15af98..06598a862 100644 --- a/apps/api/src/leaderboards/leaderboard.service.ts +++ b/apps/api/src/leaderboards/leaderboard.service.ts @@ -27,6 +27,9 @@ const DAYS_IN_WEEK = { export type LeaderboardAdditionalStats = Record & { name: string }; +const isScore = (value: unknown): value is number => + typeof value === "number" && value !== 0 && !Number.isNaN(value); + @Injectable() export abstract class LeaderboardService { public constructor(@InjectRedis() protected readonly redis: Redis) {} @@ -35,7 +38,8 @@ export abstract class LeaderboardService { constructor: Constructor, instance: Flatten, idField: keyof T, - remove = false + remove = false, + previous?: Flatten | null ) { const fields = getLeaderboardFields(constructor); const transaction = Sentry.getCurrentHub().getScope()?.getTransaction(); @@ -51,10 +55,12 @@ export abstract class LeaderboardService { const id = instance[idField] as unknown as string; for (const [field, metadata] of fields) { - const value = instance[field] as unknown as number; + const value = instance[field]; const key = `${name}.${String(field)}`; - if (remove || value === 0 || Number.isNaN(value) || typeof value !== "number") { + if (remove || !isScore(value)) { + if (previous && !isScore(previous[field] ?? metadata.store.default)) continue; + pipeline.zrem(key, id); continue; } diff --git a/apps/api/src/player/player.service.ts b/apps/api/src/player/player.service.ts index 6bc9d8953..ea873d136 100644 --- a/apps/api/src/player/player.service.ts +++ b/apps/api/src/player/player.service.ts @@ -82,7 +82,8 @@ export class PlayerService { if (mongoPlayer && mongoPlayer.username !== player.username) await this.playerSearchService.delete(mongoPlayer.username); - const flatPlayer = await this.saveOne(player, true); + // A selector only loads part of the stored document + const flatPlayer = await this.saveOne(player, true, selector ? undefined : mongoPlayer); flatPlayer.isNew = !mongoPlayer; @@ -170,7 +171,11 @@ export class PlayerService { return true; } - public async saveOne(player: Player, registerAutocomplete: boolean) { + public async saveOne( + player: Player, + registerAutocomplete: boolean, + previous?: Flatten | null + ) { // Serialize and flatten the player const flatPlayer = flatten(player); const serializedPlayer = serialize(Player, flatPlayer); @@ -183,7 +188,8 @@ export class PlayerService { Player, flatPlayer, "uuid", - false + false, + previous ), ];