-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from claustra01/feat/add_result
結果入力コマンドを実装
- Loading branch information
Showing
19 changed files
with
603 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,164 @@ | ||
import { isValid } from 'date-fns'; | ||
import { parse } from 'date-fns/fp'; | ||
import { config } from '../../config/config'; | ||
import { addMedal } from '../../usecase/functions/addMedal'; | ||
import { calculateRate } from '../../usecase/functions/calculateRate'; | ||
import { makePlayerObject } from '../../usecase/functions/makeObject'; | ||
import { Calculate, NewCalculate } from '../../usecase/types/calculate'; | ||
import { Game, NewGame } from '../../usecase/types/game'; | ||
import { Player } from '../../usecase/types/player'; | ||
import { Reply, ReplyType } from '../../usecase/types/reply'; | ||
import { calculateController } from '../queries/calculate'; | ||
import { gameController } from '../queries/game'; | ||
import { playerController } from '../queries/player'; | ||
import { transactionController } from '../queries/transaction'; | ||
|
||
const parseDate = parse(new Date(), 'yyyy-MM-dd'); | ||
|
||
const insertGame = async (newData: NewGame): Promise<Game> => { | ||
return await gameController | ||
.create(newData) | ||
.then((game) => { | ||
return game; | ||
}) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
}; | ||
|
||
const insertCalc = async (newData: NewCalculate): Promise<Calculate> => { | ||
return await calculateController | ||
.create(newData) | ||
.then((game) => { | ||
return game; | ||
}) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
}; | ||
|
||
const isExcluded = (gameId: number, playerGameCount: number): boolean => { | ||
const calculatingGameCount = config.calculatingGameCount; | ||
if (gameId <= 5) return false; | ||
if (playerGameCount <= calculatingGameCount) return true; | ||
return false; | ||
}; | ||
|
||
export const commandResult = async (args: string[]): Promise<Reply> => { | ||
if (args.length < 8) { | ||
return { | ||
type: ReplyType.Error, | ||
errorText: | ||
'Invalid Arguments: Date, EntryCount, Stack, Players...(4 or more)', | ||
}; | ||
} | ||
|
||
const date = args[1]; | ||
const parsedDate = parseDate(date); | ||
const entryCount = parseInt(args[2]); | ||
const stack = parseInt(args[3]); | ||
const playerNameList = args.slice(4); | ||
const playerList: Player[] = []; | ||
const calcList: Calculate[] = []; | ||
let gameId = -1; | ||
|
||
// validation | ||
if ( | ||
!isValid(parsedDate) || | ||
date.length !== 10 || | ||
parsedDate.getFullYear() < 2000 | ||
) { | ||
return { | ||
type: ReplyType.Error, | ||
errorText: 'Error: Invalid date format: YYYY-MM-DD', | ||
}; | ||
} | ||
if (isNaN(entryCount) || isNaN(stack)) { | ||
return { | ||
type: ReplyType.Error, | ||
errorText: 'Error: entry count and stack must be numbers', | ||
}; | ||
} | ||
if (entryCount != playerNameList.length) { | ||
return { | ||
type: ReplyType.Error, | ||
errorText: 'Error: entry count and number of players do not match', | ||
}; | ||
} | ||
for (let i = 0; i < playerNameList.length; i++) { | ||
try { | ||
const player = await playerController.readByDiscordOrName( | ||
playerNameList[i] | ||
); | ||
playerList.push(player); | ||
} catch (error) { | ||
return { | ||
type: ReplyType.Error, | ||
errorText: `${error}`, | ||
}; | ||
} | ||
} | ||
|
||
// insert data | ||
try { | ||
await transactionController.begin(); | ||
const game = await insertGame({ | ||
date, | ||
entryCount, | ||
stack, | ||
}); | ||
gameId = game.gameId; | ||
for (let i = 0; i < playerList.length - 1; i++) { | ||
for (let j = 1; j < playerList.length; j++) { | ||
if (i < j) { | ||
const calc = await insertCalc({ | ||
gameId: game.gameId, | ||
stack: game.stack, | ||
winnerName: playerList[i].playerName, | ||
winnerRate: playerList[i].currentRate, | ||
winnerIsExcluded: isExcluded(game.gameId, playerList[i].gameCount), | ||
loserName: playerList[j].playerName, | ||
loserRate: playerList[j].currentRate, | ||
loserIsExcluded: isExcluded(game.gameId, playerList[j].gameCount), | ||
}); | ||
calcList.push(calc); | ||
} | ||
} | ||
} | ||
await transactionController.commit(); | ||
} catch (error) { | ||
await transactionController.rollback(); | ||
return { | ||
type: ReplyType.Error, | ||
errorText: `${error}`, | ||
}; | ||
} | ||
|
||
// calculate rate | ||
try { | ||
await transactionController.begin(); | ||
const playerObj = makePlayerObject(playerList); | ||
const rateUpdatedPlayerObj = calculateRate(playerObj, calcList); | ||
const medalUpdatedPlayerObj = addMedal( | ||
rateUpdatedPlayerObj, | ||
playerList[0].playerName, | ||
playerList[1].playerName, | ||
playerList[2].playerName | ||
); | ||
Object.values(medalUpdatedPlayerObj).forEach(async (player) => { | ||
await playerController.update(player); | ||
}); | ||
await transactionController.commit(); | ||
} catch (error) { | ||
await transactionController.rollback(); | ||
return { | ||
type: ReplyType.Error, | ||
errorText: 'Error: Calculation Failed: use `recalculate` command', | ||
}; | ||
} | ||
|
||
export const commandResult = (args: string[]): Reply => { | ||
console.log(args); | ||
return { | ||
type: ReplyType.Error, | ||
errorText: 'Error: Not Implemented', | ||
type: ReplyType.Text, | ||
contentText: `Result Saved: ${stack}/${entryCount}entry, Id: ${gameId}`, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { | ||
parseCalculate, | ||
parseCalculateList, | ||
} from '../../usecase/functions/parseJson'; | ||
import { IController } from '../../usecase/interfaces/controller'; | ||
import { IDatabase } from '../../usecase/interfaces/db'; | ||
import { Calculate, NewCalculate } from '../../usecase/types/calculate'; | ||
|
||
export class CalculateController | ||
implements IController<Calculate, NewCalculate> | ||
{ | ||
private pool!: IDatabase; | ||
|
||
setPool(pool: IDatabase): void { | ||
this.pool = pool; | ||
} | ||
|
||
async create(newData: NewCalculate): Promise<Calculate> { | ||
const result = await this.pool | ||
.query( | ||
`INSERT INTO calculates (game_id, stack, winner_name, winner_rate, winner_is_excluded, loser_name, loser_rate, loser_is_excluded) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`, | ||
[ | ||
newData.gameId.toString(), | ||
newData.stack.toString(), | ||
newData.winnerName, | ||
newData.winnerRate.toString(), | ||
newData.winnerIsExcluded.toString(), | ||
newData.loserName, | ||
newData.loserRate.toString(), | ||
newData.loserIsExcluded.toString(), | ||
] | ||
) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
return parseCalculate(result[0]); | ||
} | ||
|
||
async read(id: string): Promise<Calculate> { | ||
const result = await this.pool | ||
.query(`SELECT * FROM calculates WHERE calc_id = $1`, [id]) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
if (result.length === 0) { | ||
throw new Error(`Calculate Not Found: ${id}`); | ||
} | ||
return parseCalculate(result[0]); | ||
} | ||
|
||
async readAll(): Promise<Calculate[]> { | ||
const result = await this.pool | ||
.query(`SELECT * FROM calculates`) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
if (result.length === 0) { | ||
throw new Error(`Calculate Not Found`); | ||
} | ||
return parseCalculateList(result); | ||
} | ||
|
||
async update(replaceData: Calculate): Promise<Calculate> { | ||
const result = await this.pool | ||
.query( | ||
`UPDATE calculates SET game_id = $2, stack = $3, winner_name = $4, winner_rate = $5, winner_is_excluded = $6, loser_name = $7, loser_rate = $8, loser_is_excluded = $9 WHERE calc_id = $1 RETURNING *`, | ||
[ | ||
replaceData.calcId.toString(), | ||
replaceData.gameId.toString(), | ||
replaceData.stack.toString(), | ||
replaceData.winnerName, | ||
replaceData.winnerRate.toString(), | ||
replaceData.winnerIsExcluded.toString(), | ||
replaceData.loserName, | ||
replaceData.loserRate.toString(), | ||
replaceData.loserIsExcluded.toString(), | ||
] | ||
) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
return parseCalculate(result[0]); | ||
} | ||
|
||
async delete(id: string): Promise<Calculate> { | ||
const result = await this.pool | ||
.query(`DELETE FROM calculates WHERE calc_id = $1 RETURNING *`, [id]) | ||
.catch((error) => { | ||
throw error; | ||
}); | ||
return parseCalculate(result[0]); | ||
} | ||
} | ||
|
||
export const calculateController = new CalculateController(); |
Oops, something went wrong.