Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/poporonnet/kcmsx
Browse files Browse the repository at this point in the history
  • Loading branch information
kiharu3112 committed Oct 27, 2024
2 parents afbdbaf + 2fe3977 commit 7681883
Show file tree
Hide file tree
Showing 31 changed files with 1,200 additions and 752 deletions.
2 changes: 2 additions & 0 deletions packages/kcms/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ MIT License.
*/
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { trimTrailingSlash } from 'hono/trailing-slash';
import { matchHandler } from './match/main';
import { teamHandler } from './team/main.js';

const app = new Hono();

app.use('*', cors());
app.use(trimTrailingSlash());
app.route('/', teamHandler);
app.route('/', matchHandler);

Expand Down
10 changes: 5 additions & 5 deletions packages/kcms/src/match/adaptor/controller/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,11 @@ export class MatchController {
matchType: MatchType,
departmentType: DepartmentType
): Promise<Result.Result<Error, z.infer<typeof GetRankingResponseSchema>>> {
if (matchType !== 'pre') {
return Result.err(new Error('Not implemented'));
}

const rankingRes = await this.generateRankingService.generatePreMatchRanking(departmentType);
const generateRanking = {
pre: () => this.generateRankingService.generatePreMatchRanking(departmentType),
main: () => this.generateRankingService.generateMainMatchRanking(departmentType),
}[matchType];
const rankingRes = await generateRanking();
if (Result.isErr(rankingRes)) return rankingRes;
const ranking = Result.unwrap(rankingRes);

Expand Down
65 changes: 47 additions & 18 deletions packages/kcms/src/match/adaptor/prisma/mainMatchRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,37 @@ export class PrismaMainMatchRepository implements MainMatchRepository {

async update(match: MainMatch): Promise<Result.Result<Error, void>> {
try {
const currentRunResults = await this.client.runResult.findMany({
where: { mainMatchId: match.getId() },
});
const currentRunResultIDs = new Set<string>(currentRunResults.map((v) => v.id));

// 複数更新と複数作成が同時にできないため、クエリを分ける
const { updatable: updatableRunResults, new: newRunResults } = match
.getRunResults()
.reduce<{ updatable: RunResult[]; new: RunResult[] }>(
(results, runResult) => {
const updateType = currentRunResultIDs.has(runResult.getId()) ? 'updatable' : 'new';
results[updateType].push(runResult);
return results;
},
{ updatable: [], new: [] }
);

await this.client.runResult.createMany({
data: newRunResults.map((v) => ({
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
mainMatchId: match.getId(),
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
})),
});
await this.client.mainMatch.update({
where: {
id: match.getId(),
Expand All @@ -128,24 +159,22 @@ export class PrismaMainMatchRepository implements MainMatchRepository {
rightTeamId: match.getTeamId2(),
winnerTeamId: match.getWinnerId(),
runResult: {
updateMany: match.getRunResults().map((v) => {
return {
where: {
id: v.getId(),
},
data: {
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
},
};
}),
updateMany: updatableRunResults.map((v) => ({
where: {
id: v.getId(),
},
data: {
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
},
})),
},
},
});
Expand Down
117 changes: 57 additions & 60 deletions packages/kcms/src/match/adaptor/prisma/preMatchRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,72 +115,69 @@ export class PrismaPreMatchRepository implements PreMatchRepository {

async update(match: PreMatch): Promise<Result.Result<Error, void>> {
try {
const runResults = await this.client.runResult.findMany({
const currentRunResults = await this.client.runResult.findMany({
where: {
preMatchId: match.getId(),
},
});
if (runResults.length === 0) {
await this.client.runResult.createMany({
data: match.getRunResults().map((v) => {
return {
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
preMatchId: match.getId(),
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
};
}),
});
await this.client.preMatch.update({
where: {
id: match.getId(),
},
data: {
courseIndex: match.getCourseIndex(),
matchIndex: match.getMatchIndex(),
leftTeamID: match.getTeamId1(),
rightTeamID: match.getTeamId2(),
},
});
} else {
await this.client.preMatch.update({
where: {
id: match.getId(),
const currentRunResultIDs = new Set<string>(currentRunResults.map((v) => v.id));

// 複数更新と複数作成が同時にできないため、クエリを分ける
const { updatable: updatableRunResults, new: newRunResults } = match
.getRunResults()
.reduce<{ updatable: RunResult[]; new: RunResult[] }>(
(results, runResult) => {
const updateType = currentRunResultIDs.has(runResult.getId()) ? 'updatable' : 'new';
results[updateType].push(runResult);
return results;
},
data: {
courseIndex: match.getCourseIndex(),
matchIndex: match.getMatchIndex(),
leftTeamID: match.getTeamId1(),
rightTeamID: match.getTeamId2(),
runResult: {
updateMany: match.getRunResults().map((v) => {
return {
where: {
id: v.getId(),
},
data: {
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
},
};
}),
},
{ updatable: [], new: [] }
);

await this.client.runResult.createMany({
data: newRunResults.map((v) => ({
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
preMatchId: match.getId(),
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
})),
});
await this.client.preMatch.update({
where: {
id: match.getId(),
},
data: {
courseIndex: match.getCourseIndex(),
matchIndex: match.getMatchIndex(),
departmentType: match.getDepartmentType(),
leftTeamID: match.getTeamId1(),
rightTeamID: match.getTeamId2(),
runResult: {
updateMany: updatableRunResults.map((v) => ({
where: {
id: v.getId(),
},
data: {
id: v.getId(),
teamID: v.getTeamId(),
points: v.getPoints(),
// NOTE: Infinity: 2147483647
goalTimeSeconds: isFinite(v.getGoalTimeSeconds())
? v.getGoalTimeSeconds()
: this.INT32MAX,
// NOTE: GOAL: 0 , FINISHED: 1
finishState: v.isGoal() ? 0 : 1,
},
})),
},
});
}
},
});
return Result.ok(undefined);
} catch (e) {
return Result.err(e as Error);
Expand Down
2 changes: 1 addition & 1 deletion packages/kcms/src/match/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const generatePreMatchService = new GeneratePreMatchService(
idGenerator,
preMatchRepository
);
const generateRankingService = new GenerateRankingService(preMatchRepository);
const generateRankingService = new GenerateRankingService(preMatchRepository, mainMatchRepository);
const fetchRunResultService = new FetchRunResultService(mainMatchRepository, preMatchRepository);
const generateMainMatchService = new GenerateMainMatchService(mainMatchRepository, idGenerator);
const matchController = new MatchController(
Expand Down
76 changes: 61 additions & 15 deletions packages/kcms/src/match/model/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,33 @@ describe('MainMatch', () => {
});

it('走行結果は0 or 2 or 4になる', () => {
const args = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
winnerId: '2' as TeamID,
runResults: [],
} satisfies CreateMainMatchArgs;

for (let j = 1; j < 100; j++) {
const mainMatch = MainMatch.new(args);
const mainMatch = MainMatch.new({
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
winnerId: '2' as TeamID,
runResults: [],
});
// 2か4以外は足せない
if (j == 2 || j == 4) {
if (j == 1 || j == 2 || j == 4) {
expect(() => {
mainMatch.appendRunResults(
[...Array(j)].map((_, i) => {
return RunResult.new({
id: String(i) as RunResultID,
goalTimeSeconds: i * 10,
points: 10 + i,
teamID: i % 2 == 0 ? args.teamId1 : args.teamId2,
teamID: i % 2 == 0 ? ('2' as TeamID) : ('3' as TeamID),
finishState: 'FINISHED',
});
})
);
}).not.toThrow(new Error('RunResult length must be 2 or 4'));
expect(mainMatch.getRunResults().length).toBe(j);
continue;
}
expect(() => {
Expand All @@ -65,12 +64,59 @@ describe('MainMatch', () => {
id: String(i) as RunResultID,
goalTimeSeconds: i * 10,
points: 10 + i,
teamID: i % 2 == 0 ? args.teamId1 : args.teamId2,
teamID: i % 2 == 0 ? ('2' as TeamID) : ('3' as TeamID),
finishState: 'FINISHED',
});
})
);
}).toThrow(new Error('RunResult length must be 2 or 4'));
expect(mainMatch.getRunResults().length).toBe(0);
}
});

it('走行結果を追加できる', () => {
for (let i = 1; i <= 2; i++) {
const mainMatch = MainMatch.new({
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
winnerId: '2' as TeamID,
runResults: [],
});
for (let j = 1; j < 8; j++) {
if (j === 1 || j == 2) {
expect(() => {
mainMatch.appendRunResults(
[...Array(i)].map((_, i) => {
return RunResult.new({
id: String(i) as RunResultID,
goalTimeSeconds: i * 10,
points: 10 + i,
teamID: i % 2 == 0 ? ('2' as TeamID) : ('3' as TeamID),
finishState: 'FINISHED',
});
})
);
}).not.toThrow(new Error('RunResult length must be 2 or 4'));
} else {
expect(() => {
mainMatch.appendRunResults(
[...Array(i)].map((_, i) => {
return RunResult.new({
id: String(i) as RunResultID,
goalTimeSeconds: i * 10,
points: 10 + i,
teamID: i % 2 == 0 ? ('2' as TeamID) : ('3' as TeamID),
finishState: 'FINISHED',
});
})
);
}).toThrow(new Error('RunResult length must be 2 or 4'));
}
}
}
});

Expand Down
4 changes: 2 additions & 2 deletions packages/kcms/src/match/model/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ export class MainMatch {
appendRunResults(results: RunResult[]) {
// 1チームが2つずつ結果を持つので、2 または 4個
const appendedLength = this.runResults.length + results.length;
if (appendedLength !== 4 && appendedLength !== 2) {
if (appendedLength !== 4 && appendedLength !== 2 && appendedLength !== 1) {
throw new Error('RunResult length must be 2 or 4');
}
this.runResults.concat(results);
this.runResults.push(...results);
}
}
Loading

0 comments on commit 7681883

Please sign in to comment.