feat: add summoner/champions endpoint

This commit is contained in:
Valentin Kaelin 2020-10-05 21:33:17 +02:00
parent 3862043980
commit 8184f17fbb
4 changed files with 160 additions and 15 deletions

View file

@ -5,6 +5,7 @@ import Jax from 'App/Services/Jax'
import MatchService from 'App/Services/MatchService' import MatchService from 'App/Services/MatchService'
import SummonerService from 'App/Services/SummonerService' import SummonerService from 'App/Services/SummonerService'
import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator' import SummonerBasicValidator from 'App/Validators/SummonerBasicValidator'
import SummonerChampionValidator from 'App/Validators/SummonerChampionValidator'
export default class SummonersController { export default class SummonersController {
/** /**
@ -22,8 +23,8 @@ export default class SummonersController {
*/ */
public async basic ({ request, response }: HttpContextContract) { public async basic ({ request, response }: HttpContextContract) {
console.time('all') console.time('all')
const { summoner, region} = await request.validate(SummonerBasicValidator) const { summoner, region } = await request.validate(SummonerBasicValidator)
const finalJSON:any = {} const finalJSON: any = {}
try { try {
const account = await SummonerService.getAccount(summoner, region) const account = await SummonerService.getAccount(summoner, region)
@ -36,7 +37,7 @@ export default class SummonersController {
// Summoner in DB // Summoner in DB
let summonerDB = await Summoner.findOne({ puuid: account.puuid }) let summonerDB = await Summoner.findOne({ puuid: account.puuid })
if(!summonerDB) { if (!summonerDB) {
summonerDB = await Summoner.create({ puuid: account.puuid }) summonerDB = await Summoner.create({ puuid: account.puuid })
} }
@ -69,4 +70,16 @@ export default class SummonersController {
console.timeEnd('all') console.timeEnd('all')
return response.json(finalJSON) return response.json(finalJSON)
} }
/**
* POST: get champions view summoner data
* @param ctx
*/
public async champions ({ request, response }) {
console.time('championsRequest')
const { puuid, queue, season } = await request.validate(SummonerChampionValidator)
const championStats = await MatchRepository.championCompleteStats(puuid, queue, season)
console.timeEnd('championsRequest')
return response.json(championStats)
}
} }

View file

@ -2,39 +2,114 @@ import mongodb from '@ioc:Mongodb/Database'
import { Collection } from 'mongodb' import { Collection } from 'mongodb'
class MatchRepository { class MatchRepository {
private season?: number
private collection: Collection private collection: Collection
constructor () { constructor () {
this.getCollection() this.getCollection()
} }
/**
* Get MongoDB matches collection
*/
private async getCollection () {
this.collection = await mongodb.connection().collection('matches')
}
/** /**
* Basic matchParams used in a lot of requests * Basic matchParams used in a lot of requests
* @param puuid of the summoner * @param puuid of the summoner
*/ */
private matchParams (puuid: string) { private matchParams (puuid: string, season?: number) {
return { return {
summoner_puuid: puuid, summoner_puuid: puuid,
result: { $not: { $eq: 'Remake' } }, result: { $not: { $eq: 'Remake' } },
gamemode: { $nin: [800, 810, 820, 830, 840, 850] }, gamemode: { $nin: [800, 810, 820, 830, 840, 850] },
season: this.season ? this.season : { $exists: true }, season: season ? season : { $exists: true },
} }
} }
/**
* Build the aggregate mongo query
* @param puuid
* @param matchParams
* @param intermediateSteps
* @param groupId
* @param groupParams
* @param finalSteps
*/
private async aggregate (
puuid: string,
matchParams: object,
intermediateSteps: any[],
groupId: any,
groupParams: object,
finalSteps: any[],
season?: number,
) {
return this.collection.aggregate([
{
$match: {
...this.matchParams(puuid, season),
...matchParams,
},
},
...intermediateSteps,
{
$group: {
_id: groupId,
count: { $sum: 1 },
wins: {
$sum: {
$cond: [{ $eq: ['$result', 'Win'] }, 1, 0],
},
},
losses: {
$sum: {
$cond: [{ $eq: ['$result', 'Fail'] }, 1, 0],
},
},
...groupParams,
},
},
...finalSteps,
]).toArray()
}
/**
* Get MongoDB matches collection
*/
public async getCollection () {
if (!this.collection) {
this.collection = await mongodb.connection().collection('matches')
}
}
/**
* Get Summoner's complete statistics for the all played champs
* @param puuid of the summoner
* @param queue of the matches to fetch, if not set: get all matches
* @param season of the matches to fetch, if not set: get all seasons
*/
public async championCompleteStats (puuid: string, queue?: number, season?: number) {
const matchParams = queue ? { gamemode: { $eq: Number(queue) } } : {}
const groupParams = {
time: { $sum: '$time' },
gameLength: { $avg: '$time' },
date: { $max: '$date' },
champion: { $first: '$champion' },
kills: { $sum: '$stats.kills' },
deaths: { $sum: '$stats.deaths' },
assists: { $sum: '$stats.assists' },
minions: { $avg: '$stats.minions' },
gold: { $avg: '$stats.gold' },
dmgChamp: { $avg: '$stats.dmgChamp' },
dmgTaken: { $avg: '$stats.dmgTaken' },
kp: { $avg: '$stats.kp' },
}
const finalSteps = [
{ $sort: { 'count': -1, 'champion.name': 1 } },
]
return this.aggregate(puuid, matchParams, [], '$champion.id', groupParams, finalSteps, season)
}
/** /**
* Get Summoner's played seasons * Get Summoner's played seasons
* @param puuid of the summoner * @param puuid of the summoner
*/ */
public async seasons (puuid: string) { public async seasons (puuid: string) {
this.season = undefined
return this.collection.aggregate([ return this.collection.aggregate([
{ {
$match: { $match: {

View file

@ -0,0 +1,54 @@
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { schema } from '@ioc:Adonis/Core/Validator'
export default class SummonerChampionValidator {
constructor (private ctx: HttpContextContract) {
}
/**
* Defining a 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(),
})
/**
* The `schema` first gets compiled to a reusable function and then that compiled
* function validates the data at runtime.
*
* Since, compiling the schema is an expensive operation, you must always cache it by
* defining a unique cache key. The simplest way is to use the current request route
* key, which is a combination of the route pattern and HTTP method.
*/
public cacheKey = this.ctx.routeKey
/**
* 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 = {}
}

View file

@ -8,8 +8,11 @@ export default class AppProvider {
// Register your own bindings // Register your own bindings
} }
public boot () { public async boot () {
// IoC container is ready // IoC container is ready
// Load Match Collections
await import('App/Repositories/MatchRepository')
} }
public shutdown () { public shutdown () {