refactor: use db transactions when inserting matches to prevent errors

This commit is contained in:
Valentin Kaelin 2022-01-30 18:01:05 +01:00
parent ec6319ec3b
commit 4811f95aa0
3 changed files with 170 additions and 141 deletions

View file

@ -29,6 +29,8 @@ Vue.filter('kilo', (value) => {
}) })
Vue.filter('secToTime', (sec, dotNotation = false) => { Vue.filter('secToTime', (sec, dotNotation = false) => {
if (isNaN(sec)) return 0
const min = Math.floor(sec / 60) const min = Math.floor(sec / 60)
let newSec = Math.floor(sec - min * 60) let newSec = Math.floor(sec - min * 60)
newSec = newSec < 10 ? '0' + newSec : newSec newSec = newSec < 10 ? '0' + newSec : newSec
@ -41,6 +43,8 @@ Vue.filter('percent', (value) => {
}) })
Vue.filter('round', (value, decimals = 2) => { Vue.filter('round', (value, decimals = 2) => {
if (isNaN(value)) return 0
return parseFloat(value.toFixed(decimals)) return parseFloat(value.toFixed(decimals))
}) })

View file

@ -1,4 +1,4 @@
import Database from '@ioc:Adonis/Lucid/Database' import Database, { TransactionClientContract } from '@ioc:Adonis/Lucid/Database'
import { MatchDto } from 'App/Services/Jax/src/Endpoints/MatchEndpoint' import { MatchDto } from 'App/Services/Jax/src/Endpoints/MatchEndpoint'
import Match from 'App/Models/Match' import Match from 'App/Models/Match'
import { getSeasonNumber, queuesWithRole } from 'App/helpers' import { getSeasonNumber, queuesWithRole } from 'App/helpers'
@ -6,14 +6,23 @@ import CDragonService from 'App/Services/CDragonService'
import { ChampionRoles, TeamPosition } from './ParsedType' import { ChampionRoles, TeamPosition } from './ParsedType'
class MatchParser { class MatchParser {
public async parseOneMatch(match: MatchDto) { public async parseOneMatch(match: MatchDto) {
// Parse + store in database let parsedMatch: Match | null = null
let trx: TransactionClientContract | undefined
try {
// Start transaction
trx = await Database.transaction()
const gameDuration = const gameDuration =
match.info.gameDuration > 100_000 match.info.gameDuration > 100_000
? Math.round(match.info.gameDuration / 1000) ? Math.round(match.info.gameDuration / 1000)
: match.info.gameDuration : match.info.gameDuration
const isRemake = gameDuration < 300
// - 1x Match // - 1x Match
const parsedMatch = await Match.create({ parsedMatch = await Match.create(
{
id: match.metadata.matchId, id: match.metadata.matchId,
gameId: match.info.gameId, gameId: match.info.gameId,
map: match.info.mapId, map: match.info.mapId,
@ -23,9 +32,9 @@ class MatchParser {
result: match.info.teams[0].win ? match.info.teams[0].teamId : match.info.teams[1].teamId, result: match.info.teams[0].win ? match.info.teams[0].teamId : match.info.teams[1].teamId,
season: getSeasonNumber(match.info.gameCreation), season: getSeasonNumber(match.info.gameCreation),
gameDuration, gameDuration,
}) },
{ client: trx }
const isRemake = gameDuration < 300 )
// - 2x MatchTeam : Red and Blue // - 2x MatchTeam : Red and Blue
for (const team of match.info.teams) { for (const team of match.info.teams) {
@ -53,13 +62,15 @@ class MatchParser {
const kda = const kda =
player.kills + player.assists !== 0 && player.deaths === 0 player.kills + player.assists !== 0 && player.deaths === 0
? player.kills + player.assists ? player.kills + player.assists
: +(player.deaths === 0 ? 0 : (player.kills + player.assists) / player.deaths).toFixed(2) : +(player.deaths === 0 ? 0 : (player.kills + player.assists) / player.deaths).toFixed(
2
)
const team = const team =
match.info.teams[0].teamId === player.teamId ? match.info.teams[0] : match.info.teams[1] match.info.teams[0].teamId === player.teamId ? match.info.teams[0] : match.info.teams[1]
const teamKills = team.objectives.champion.kills const teamKills = team.objectives.champion.kills
const kp = let kp =
teamKills === 0 ? 0 : +(((player.kills + player.assists) * 100) / teamKills).toFixed(1) teamKills === 0 ? 0 : +(((player.kills + player.assists) * 100) / teamKills).toFixed(1)
const primaryStyle = player.perks.styles.find((s) => s.description === 'primaryStyle') const primaryStyle = player.perks.styles.find((s) => s.description === 'primaryStyle')
@ -149,14 +160,28 @@ class MatchParser {
await parsedMatch.load((loader) => { await parsedMatch.load((loader) => {
loader.load('teams').load('players') loader.load('teams').load('players')
}) })
if (!trx.isCompleted) {
await trx.commit()
}
} catch (error) {
console.log('Error in MatchParser transaction.')
if (trx && trx.isTransaction) {
await trx.rollback()
return null
}
}
return parsedMatch return parsedMatch
} }
public async parse(matches: MatchDto[]) { public async parse(matches: MatchDto[]) {
// Loop on all matches and call .parseOneMatch on it
const parsedMatches: Match[] = [] const parsedMatches: Match[] = []
for (const match of matches) { for (const match of matches) {
parsedMatches.push(await this.parseOneMatch(match)) const parsed = await this.parseOneMatch(match)
if (parsed) {
parsedMatches.push(parsed)
}
} }
return parsedMatches return parsedMatches
} }

View file

@ -77,16 +77,16 @@ class MatchRepository {
public async globalStats(filters: SelectFilters) { public async globalStats(filters: SelectFilters) {
const query = ` const query = `
SELECT SELECT
SUM(match_players.kills) as kills, COALESCE(SUM(match_players.kills), 0) as kills,
SUM(match_players.deaths) as deaths, COALESCE(SUM(match_players.deaths), 0) as deaths,
SUM(match_players.assists) as assists, COALESCE(SUM(match_players.assists), 0) as assists,
SUM(match_players.minions) as minions, COALESCE(SUM(match_players.minions), 0) as minions,
SUM(matches.game_duration) as time, COALESCE(SUM(matches.game_duration), 0) as time,
SUM(match_players.vision_score) as vision, COALESCE(SUM(match_players.vision_score), 0) as vision,
COUNT(match_players.id) as count, COUNT(match_players.id) as count,
AVG(match_players.kp) as kp, COALESCE(AVG(match_players.kp), 0) as kp,
SUM(match_players.win) as wins, COALESCE(SUM(match_players.win), 0) as wins,
SUM(match_players.loss) as losses COALESCE(SUM(match_players.loss), 0) as losses
FROM FROM
match_players match_players
${this.JOIN_MATCHES} ${this.JOIN_MATCHES}