From 629cad12fb46388ce10212b3db16756cab36a55e Mon Sep 17 00:00:00 2001 From: Valentin Kaelin Date: Sat, 18 Sep 2021 21:21:13 +0200 Subject: [PATCH] feat: add champions tab back (without filtering by queue for now) --- .../Controllers/Http/SummonersController.ts | 19 +++++++ server-v2/app/Repositories/MatchRepository.ts | 55 +++++++++++-------- .../Validators/SummonerChampionValidator.ts | 44 +++++++++++++++ server-v2/start/routes.ts | 2 +- 4 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 server-v2/app/Validators/SummonerChampionValidator.ts diff --git a/server-v2/app/Controllers/Http/SummonersController.ts b/server-v2/app/Controllers/Http/SummonersController.ts index 4967ad9..8fde1f1 100644 --- a/server-v2/app/Controllers/Http/SummonersController.ts +++ b/server-v2/app/Controllers/Http/SummonersController.ts @@ -9,6 +9,7 @@ import MatchService from 'App/Services/MatchService' import StatsService from 'App/Services/StatsService' import SummonerService from 'App/Services/SummonerService' import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator' +import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator' import SummonerLiveValidator from 'App/Validators/SummonerLiveValidator' import SummonerOverviewValidator from 'App/Validators/SummonerOverviewValidator' import SummonerRecordValidator from 'App/Validators/SummonerRecordValidator' @@ -88,6 +89,24 @@ export default class SummonersController { return response.json(finalJSON) } + /** + * POST: get champions view summoner data + * @param ctx + */ + public async champions({ request, response }: HttpContextContract) { + console.time('championsRequest') + const { puuid, queue, season } = await request.validate(SummonerChampionValidator) + const championStats = await MatchRepository.championCompleteStats(puuid, queue, season) + const championStatsSerialized = championStats.map((champion) => { + return { + ...champion, + champion: BasicMatchSerializer.getChampion(champion.id), + } + }) + console.timeEnd('championsRequest') + return response.json(championStatsSerialized) + } + /** * POST: get records view summoner data * @param ctx diff --git a/server-v2/app/Repositories/MatchRepository.ts b/server-v2/app/Repositories/MatchRepository.ts index 445a0b5..9463850 100644 --- a/server-v2/app/Repositories/MatchRepository.ts +++ b/server-v2/app/Repositories/MatchRepository.ts @@ -54,28 +54,6 @@ class MatchRepository { ` const { rows } = await Database.rawQuery(query, { puuid }) return rows[0] - // return Database.from('match_players') - // .where('summoner_puuid', puuid) - // .join('matches', 'match_players.match_id', 'matches.id') - // .join('match_teams', (query) => { - // query - // .on('match_teams.match_id', '=', 'match_players.match_id') - // .andOn('match_teams.color', '=', 'match_players.team') - // }) - // .sum({ - // assists: 'assists', - // deaths: 'deaths', - // kills: 'kills', - // minions: 'minions', - // time: 'matches.game_duration', - // vision: 'vision_score', - // result: 'match_teams.result', - // }) - // .count({ - // count: 'assists', - // }) - // .avg('kp') - // .first() } public async gamemodeStats(puuid: string) { @@ -166,6 +144,39 @@ class MatchRepository { return rows } + public async championCompleteStats(puuid: string, queue?: number, season?: number) { + const query = ` + SELECT + match_players.champion_id as id, + SUM(match_players.assists) as assists, + SUM(match_players.deaths) as deaths, + SUM(match_players.kills) as kills, + COUNT(match_players.id) as count, + SUM(match_players.win) as wins, + SUM(match_players.loss) as losses, + SUM(matches.game_duration) as time, + AVG(matches.game_duration)::int as "gameLength", + AVG(match_players.minions)::int as minions, + AVG(match_players.gold)::int as gold, + AVG(match_players.damage_dealt_champions)::int as "dmgChamp", + AVG(match_players.damage_taken)::int as "dmgTaken", + AVG(match_players.kp) as kp, + AVG(match_players.kda) as kda, + MAX(matches.date) as date + FROM + match_players + ${this.JOIN_MATCHES} + WHERE + ${this.GLOBAL_FILTERS} + GROUP BY + match_players.champion_id + ORDER BY + count DESC, match_players.champion_id + ` + const { rows } = await Database.rawQuery(query, { puuid }) + return rows + } + public async mates(puuid: string) { const query = ` SELECT diff --git a/server-v2/app/Validators/SummonerChampionValidator.ts b/server-v2/app/Validators/SummonerChampionValidator.ts new file mode 100644 index 0000000..2b161ea --- /dev/null +++ b/server-v2/app/Validators/SummonerChampionValidator.ts @@ -0,0 +1,44 @@ +import { schema } from '@ioc:Adonis/Core/Validator' +import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' + +export default class SummonerChampionValidator { + constructor(protected ctx: HttpContextContract) {} + + /* + * Define schema to validate the "shape", "type", "formatting" and "integrity" of data. + * + * For example: + * 1. The username must be of data type string. But then also, it should + * not contain special characters or numbers. + * ``` + * schema.string({}, [ rules.alpha() ]) + * ``` + * + * 2. The email must be of data type string, formatted as a valid + * email. But also, not used by any other user. + * ``` + * schema.string({}, [ + * rules.email(), + * rules.unique({ table: 'users', column: 'email' }), + * ]) + * ``` + */ + public schema = schema.create({ + puuid: schema.string(), + queue: schema.number.optional(), + season: schema.number.optional(), + }) + + /** + * Custom messages for validation failures. You can make use of dot notation `(.)` + * for targeting nested fields and array expressions `(*)` for targeting all + * children of an array. For example: + * + * { + * 'profile.username.required': 'Username is required', + * 'scores.*.number': 'Define scores as valid numbers' + * } + * + */ + public messages = {} +} diff --git a/server-v2/start/routes.ts b/server-v2/start/routes.ts index 45a7de5..f408d4e 100644 --- a/server-v2/start/routes.ts +++ b/server-v2/start/routes.ts @@ -31,7 +31,7 @@ Route.get('/health', async () => ({ report: await HealthCheck.getReport() })) Route.post('/summoner/basic', 'SummonersController.basic') Route.post('/summoner/overview', 'SummonersController.overview') -// Route.post('/summoner/champions', 'SummonersController.champions') +Route.post('/summoner/champions', 'SummonersController.champions') Route.post('/summoner/records', 'SummonersController.records') Route.post('/summoner/live', 'SummonersController.liveMatchDetails')