Add time period support to leaderboard queries

This commit is contained in:
Brian Beck 2021-09-26 00:25:26 -07:00
parent 01c2b8b37d
commit edd3076b54
3 changed files with 33 additions and 3 deletions

View file

@ -40,6 +40,9 @@ export class TopAccuracyQueryDto {
@IsPositive()
@Max(100)
limit: number;
@IsOptional()
timePeriod: string;
}
export class TopWinsQueryDto {
@ -51,4 +54,7 @@ export class TopWinsQueryDto {
@IsPositive()
@Max(100)
limit: number;
@IsOptional()
timePeriod: string;
}

View file

@ -32,6 +32,7 @@ export class PlayersController {
minGames = 10,
minShots = 100,
limit = 10,
timePeriod,
} = topPlayersQuery;
return this.playerService.findTopAccuracy({
stat,
@ -39,6 +40,7 @@ export class PlayersController {
minGames,
minShots,
limit,
timePeriod,
});
}
@ -48,10 +50,11 @@ export class PlayersController {
summary: 'Return a leaderboard of players for win percentage',
})
findTopWins(@Query() topPlayersQuery: TopWinsQueryDto) {
const { minGames = 100, limit = 10 } = topPlayersQuery;
const { minGames = 100, limit = 10, timePeriod } = topPlayersQuery;
return this.playerService.findTopWins({
minGames,
limit,
timePeriod,
});
}
}

View file

@ -56,6 +56,7 @@ export class PlayersService {
minGames,
minShots,
limit,
timePeriod,
} = topAccuracyQuery;
const shotsStat = {
@ -102,6 +103,8 @@ export class PlayersService {
// Cast to float to avoid integer division truncating the result.
const aggregatedAccuracy = `(${aggregatedHits}::float / ${aggregatedShots}::float)`;
const sinceDate = '(now() - interval :timePeriod)';
// TODO: This whole query could probably be turned into a `ViewEntity` at
// some point, but I couldn't get that to work.
@ -112,6 +115,7 @@ export class PlayersService {
shotsStat,
minGames,
minShots,
timePeriod,
})
.select([
'player.player_guid',
@ -121,6 +125,10 @@ export class PlayersService {
'stats.shots',
'stats.accuracy',
])
.addSelect(
timePeriod ? sinceDate : 'NULL',
'since_date'
)
.innerJoin(
(subQuery) => {
let statsQuery = subQuery
@ -131,6 +139,7 @@ export class PlayersService {
.addSelect(aggregatedShots, 'shots')
.addSelect(aggregatedAccuracy, 'accuracy')
.where(`${shotsValue} > 0`)
.andWhere(timePeriod ? `game.datestamp >= ${sinceDate}` : 'TRUE')
.groupBy('game.player_guid');
if (excludeDiscJumps) {
@ -190,16 +199,20 @@ export class PlayersService {
minGames,
minShots,
limit,
timePeriod,
sinceDate: rows.length ? rows[0].since_date : null,
players,
};
}
async findTopWins(topWinsQuery: TopWinsQueryDto) {
const { minGames, limit } = topWinsQuery;
const { minGames, limit, timePeriod } = topWinsQuery;
const sinceDate = '(now() - interval :timePeriod)';
const query = this.playersRepository
.createQueryBuilder('player')
.setParameters({ minGames })
.setParameters({ minGames, timePeriod })
.select(['stats.player_name', 'stats.player_guid'])
.addSelect('COUNT(stats.game_id)::integer', 'game_count')
.addSelect(
@ -218,6 +231,10 @@ export class PlayersService {
"(COUNT(stats.player_match_result = 'win' OR NULL)::float + COUNT(stats.player_match_result = 'draw' OR NULL)::float / 2.0) / COUNT(stats.game_id)::float",
'win_percent',
)
.addSelect(
timePeriod ? sinceDate : 'NULL',
'since_date'
)
.innerJoin(
(qb) => {
return (
@ -309,6 +326,8 @@ export class PlayersService {
// Each team must have at least 2 players.
.andWhere('join_g.team_size_storm >= 2')
.andWhere('join_g.team_size_inferno >= 2')
// Must fall within the specified time period.
.andWhere(timePeriod ? `game.datestamp >= ${sinceDate}` : 'TRUE')
);
},
'stats',
@ -351,6 +370,8 @@ export class PlayersService {
minGames,
gameType: ['CTFGame', 'SCtFGame'],
limit,
timePeriod,
sinceDate: rows.length ? rows[0].since_date : null,
players,
};
}