Skip to content

Commit

Permalink
feat: MainMatchにdepartmentTypematchTypeを追加 (#558)
Browse files Browse the repository at this point in the history
* chore: DBスキーマを更新
MainMatchにdepartmentTypeを追加

* chore: マイグレーションを生成

* feat: MainMatchモデルにdepartmentTypeを追加

* feat: GenerateMainMatchServiceにdepartmentTypeを追加

* feat: MainMatchのAPIにmatchTypeを追加

* chore: APIドキュメントを更新

* chore: フロントエンドの型定義を更新
  • Loading branch information
tufusa authored Oct 21, 2024
1 parent 9a4d0be commit e0f96f3
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 25 deletions.
2 changes: 2 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@
"id": "70983405",
// 試合コード `${コース番号}-${そのコースでの試合番号}` どちらも1始まり
"matchCode": "1-3",
// 試合種別 (matchType 設定依存)
"matchType": "main",
// チームのカテゴリ (departmentType 設定依存)
"departmentType": "elementary",
// チーム1 (空になる可能性あり 空の場合undefined)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Warnings:
- Added the required column `department_type` to the `main_match` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_main_match" (
"id" TEXT NOT NULL PRIMARY KEY,
"department_type" TEXT NOT NULL,
"course_index" INTEGER NOT NULL,
"match_index" INTEGER NOT NULL,
"left_team_id" TEXT,
"right_team_id" TEXT,
"winner_team_id" TEXT,
CONSTRAINT "main_match_left_team_id_fkey" FOREIGN KEY ("left_team_id") REFERENCES "team" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "main_match_right_team_id_fkey" FOREIGN KEY ("right_team_id") REFERENCES "team" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_main_match" ("course_index", "id", "left_team_id", "match_index", "right_team_id", "winner_team_id") SELECT "course_index", "id", "left_team_id", "match_index", "right_team_id", "winner_team_id" FROM "main_match";
DROP TABLE "main_match";
ALTER TABLE "new_main_match" RENAME TO "main_match";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
17 changes: 10 additions & 7 deletions packages/kcms/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ model Team {
}

model MainMatch {
id String @id
courseIndex Int @map("course_index")
matchIndex Int @map("match_index")
leftTeamId String? @map("left_team_id")
leftTeam Team? @relation("main_left_team", fields: [leftTeamId], references: [id])
rightTeamId String? @map("right_team_id")
rightTeam Team? @relation("main_right_team", fields: [rightTeamId], references: [id])
id String @id
departmentType String @map("department_type")
courseIndex Int @map("course_index")
matchIndex Int @map("match_index")
leftTeamId String? @map("left_team_id")
leftTeam Team? @relation("main_left_team", fields: [leftTeamId], references: [id])
rightTeamId String? @map("right_team_id")
rightTeam Team? @relation("main_right_team", fields: [rightTeamId], references: [id])
// NOTE: アプリケーション側を信用するのでここはリレーションを作らないことにした (PreMatchも同様)
winnerTeamId String? @map("winner_team_id")
Expand Down
11 changes: 9 additions & 2 deletions packages/kcms/src/match/adaptor/controller/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
PostMatchGenerateResponseSchema,
PreSchema,
RunResultSchema,
ShortMainSchema,
ShortPreSchema,
} from '../validator/match';

Expand Down Expand Up @@ -117,14 +118,19 @@ export class MatchController {
team1ID: string,
team2ID: string
): Promise<Result.Result<Error, z.infer<typeof PostMatchGenerateManualResponseSchema>>> {
const res = await this.generateMainMatchService.handle(team1ID as TeamID, team2ID as TeamID);
const res = await this.generateMainMatchService.handle(
departmentType,
team1ID as TeamID,
team2ID as TeamID
);
if (Result.isErr(res)) return res;

const match = Result.unwrap(res);
return Result.ok([
return Result.ok<z.infer<typeof ShortMainSchema>[]>([
{
id: match.getId(),
matchCode: `${match.getCourseIndex()}-${match.getMatchIndex()}`,
matchType: 'main',
departmentType,
team1ID: match.getTeamId1(),
team2ID: match.getTeamId2(),
Expand Down Expand Up @@ -250,6 +256,7 @@ export class MatchController {
return {
id: v.getId(),
matchCode: `${v.getCourseIndex()}-${v.getMatchIndex()}`,
matchType: 'main',
departmentType: teamsMap.get(v.getTeamId1() ?? ('' as TeamID))!.getDepartmentType(),
team1:
v.getTeamId1() == undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Option, Result } from '@mikuroxina/mini-fn';
import { config } from 'config';
import { beforeEach, describe, expect, it } from 'vitest';
import { TeamID } from '../../../team/models/team.js';
import { testRankingMainMatchData } from '../../../testData/match.js';
Expand All @@ -18,6 +19,7 @@ describe('DummyMainMatchRepository', () => {
id: '900' as MainMatchID,
courseIndex: 0,
matchIndex: 91,
departmentType: config.departmentTypes[0],
teamId1: '91' as TeamID,
teamId2: '92' as TeamID,
winnerId: '91' as TeamID,
Expand Down Expand Up @@ -53,6 +55,7 @@ describe('DummyMainMatchRepository', () => {
id: '100' as MainMatchID,
courseIndex: 0,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '1' as TeamID,
teamId2: '2' as TeamID,
winnerId: '1' as TeamID,
Expand Down
5 changes: 5 additions & 0 deletions packages/kcms/src/match/adaptor/prisma/mainMatchRepository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Option, Result } from '@mikuroxina/mini-fn';
import type { Prisma, PrismaClient } from '@prisma/client';
import { DepartmentType } from 'config';
import { TeamID } from '../../../team/models/team';
import { MainMatch, MainMatchID } from '../../model/main';
import { MainMatchRepository } from '../../model/repository';
Expand All @@ -25,6 +26,7 @@ export class PrismaMainMatchRepository implements MainMatchRepository {
id: data.id as MainMatchID,
courseIndex: data.courseIndex,
matchIndex: data.matchIndex,
departmentType: data.departmentType as DepartmentType,
teamId1: (data.leftTeamId as TeamID) ?? undefined,
teamId2: (data.rightTeamId as TeamID) ?? undefined,
winnerId: (data.winnerTeamId as TeamID) ?? undefined,
Expand All @@ -50,6 +52,7 @@ export class PrismaMainMatchRepository implements MainMatchRepository {
id: match.getId(),
courseIndex: match.getCourseIndex(),
matchIndex: match.getMatchIndex(),
departmentType: match.getDepartmentType(),
leftTeamId: match.getTeamId1(),
rightTeamId: match.getTeamId2(),
},
Expand All @@ -69,6 +72,7 @@ export class PrismaMainMatchRepository implements MainMatchRepository {
id: v.getId(),
courseIndex: v.getCourseIndex(),
matchIndex: v.getMatchIndex(),
departmentType: v.getDepartmentType(),
leftTeamId: v.getTeamId1(),
rightTeamId: v.getTeamId2(),
};
Expand Down Expand Up @@ -119,6 +123,7 @@ export class PrismaMainMatchRepository implements MainMatchRepository {
data: {
courseIndex: match.getCourseIndex(),
matchIndex: match.getMatchIndex(),
departmentType: match.getDepartmentType(),
leftTeamId: match.getTeamId1(),
rightTeamId: match.getTeamId2(),
winnerTeamId: match.getWinnerId(),
Expand Down
1 change: 1 addition & 0 deletions packages/kcms/src/match/adaptor/validator/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const PreSchema = z.object({
export const MainSchema = z.object({
id: z.string().openapi({ example: '70983405' }),
matchCode: z.string(),
matchType: z.literal('main').openapi({ example: 'main' }),
departmentType: z.enum(config.departmentTypes).openapi({ example: config.departments[0].type }),
team1: BriefTeamSchema,
team2: BriefTeamSchema,
Expand Down
21 changes: 14 additions & 7 deletions packages/kcms/src/match/model/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { config } from 'config';
import { describe, expect, it } from 'vitest';
import { TeamID } from '../../team/models/team.js';
import { MainMatch, MainMatchID } from './main.js';
import { CreateMainMatchArgs, MainMatch, MainMatchID } from './main.js';
import { RunResult, RunResultID } from './runResult.js';

describe('MainMatch', () => {
it('正しく初期化できる', () => {
const args = {
const args: CreateMainMatchArgs = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
winnerId: '2' as TeamID,
Expand All @@ -30,11 +32,12 @@ describe('MainMatch', () => {
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);
Expand Down Expand Up @@ -72,10 +75,11 @@ describe('MainMatch', () => {
});

it('勝者を指定できる', () => {
const args = {
const args: CreateMainMatchArgs = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
runResults: [...Array(4)].map((_, i) =>
Expand All @@ -97,10 +101,11 @@ describe('MainMatch', () => {
});

it('勝者が決まっているときは変更できない', () => {
const args = {
const args: CreateMainMatchArgs = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
winnerId: '2' as TeamID,
Expand All @@ -123,10 +128,11 @@ describe('MainMatch', () => {
});

it('試合が終わっていないときは設定できない', () => {
const args = {
const args: CreateMainMatchArgs = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
runResults: [...Array(2)].map((_, i) => {
Expand All @@ -148,10 +154,11 @@ describe('MainMatch', () => {
});

it('勝者はteamId1かteamId2でなければならない', () => {
const args = {
const args: CreateMainMatchArgs = {
id: '1' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '2' as TeamID,
teamId2: '3' as TeamID,
runResults: [...Array(4)].map((_, i) => {
Expand Down
8 changes: 8 additions & 0 deletions packages/kcms/src/match/model/main.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DepartmentType } from 'config';
import { SnowflakeID } from '../../id/main.js';
import { TeamID } from '../../team/models/team.js';
import { RunResult } from './runResult.js';
Expand All @@ -7,6 +8,7 @@ export interface CreateMainMatchArgs {
id: MainMatchID;
courseIndex: number;
matchIndex: number;
departmentType: DepartmentType;
teamId1?: TeamID;
teamId2?: TeamID;
winnerId?: TeamID;
Expand All @@ -20,6 +22,7 @@ export class MainMatch {
private readonly id: MainMatchID;
private readonly courseIndex: number;
private readonly matchIndex: number;
private readonly departmentType: DepartmentType;
private readonly teamId1?: TeamID;
private readonly teamId2?: TeamID;
private winnerId?: TeamID;
Expand All @@ -29,6 +32,7 @@ export class MainMatch {
this.id = args.id;
this.courseIndex = args.courseIndex;
this.matchIndex = args.matchIndex;
this.departmentType = args.departmentType;
this.teamId1 = args.teamId1;
this.teamId2 = args.teamId2;
this.winnerId = args.winnerId;
Expand All @@ -51,6 +55,10 @@ export class MainMatch {
return this.matchIndex;
}

getDepartmentType(): DepartmentType {
return this.departmentType;
}

getTeamId1(): TeamID | undefined {
return this.teamId1;
}
Expand Down
5 changes: 3 additions & 2 deletions packages/kcms/src/match/service/generateMain.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Result } from '@mikuroxina/mini-fn';
import { config } from 'config';
import { describe, expect, it } from 'vitest';
import { SnowflakeIDGenerator } from '../../id/main';
import { TeamID } from '../../team/models/team';
Expand All @@ -13,7 +14,7 @@ describe('GenerateMainMatchService', () => {
const service = new GenerateMainMatchService(mainMatchRepository, idGenerator);

it('本戦試合を生成できる', async () => {
const res = await service.handle('1' as TeamID, '2' as TeamID);
const res = await service.handle(config.departmentTypes[0], '1' as TeamID, '2' as TeamID);
expect(Result.isOk(res)).toBe(true);

const match = Result.unwrap(res);
Expand All @@ -22,7 +23,7 @@ describe('GenerateMainMatchService', () => {
});

it('(安来用) 本戦試合の試合番号は1-1になる', async () => {
const res = await service.handle('1' as TeamID, '2' as TeamID);
const res = await service.handle(config.departmentTypes[0], '1' as TeamID, '2' as TeamID);
expect(Result.isOk(res)).toBe(true);

const match = Result.unwrap(res);
Expand Down
8 changes: 7 additions & 1 deletion packages/kcms/src/match/service/generateMain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Result } from '@mikuroxina/mini-fn';
import { DepartmentType } from 'config';
import { SnowflakeIDGenerator } from '../../id/main';
import { TeamID } from '../../team/models/team';
import { MainMatch } from '../model/main';
Expand All @@ -10,7 +11,11 @@ export class GenerateMainMatchService {
private readonly idGenerator: SnowflakeIDGenerator
) {}

async handle(teamID1: TeamID, teamID2: TeamID): Promise<Result.Result<Error, MainMatch>> {
async handle(
departmentType: DepartmentType,
teamID1: TeamID,
teamID2: TeamID
): Promise<Result.Result<Error, MainMatch>> {
const newIDRes = this.idGenerator.generate<MainMatch>();
if (Result.isErr(newIDRes)) {
return newIDRes;
Expand All @@ -21,6 +26,7 @@ export class GenerateMainMatchService {
id: newID,
courseIndex: 1,
matchIndex: 1,
departmentType,
runResults: [],
teamId1: teamID1,
teamId2: teamID2,
Expand Down
2 changes: 2 additions & 0 deletions packages/kcms/src/testData/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const testCreateRunResultMainData = [
id: '900' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '91' as TeamID,
teamId2: '92' as TeamID,
winnerId: '91' as TeamID,
Expand Down Expand Up @@ -297,6 +298,7 @@ export const testRankingMainMatchData = [
id: '900' as MainMatchID,
courseIndex: 1,
matchIndex: 1,
departmentType: config.departmentTypes[0],
teamId1: '91' as TeamID,
teamId2: '92' as TeamID,
winnerId: '91' as TeamID,
Expand Down
12 changes: 6 additions & 6 deletions packages/kcmsf/src/types/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ export type PreMatch = MatchBase &
/**
* 本戦のマッチ
* @todo `winnerId`のプロパティ名が誤っている (`winnerID`)
* @todo MainMatchに`matchType`が存在しない
*/
export type MainMatch = MatchBase & {
team1: BriefTeam;
team2: BriefTeam;
winnerId: string; // TODO: スキーマの修正漏れ
};
export type MainMatch = MatchBase &
MatchTypeRecord<"main"> & {
team1: BriefTeam;
team2: BriefTeam;
winnerId: string; // TODO: スキーマの修正漏れ
};

/**
* マッチ
Expand Down

0 comments on commit e0f96f3

Please sign in to comment.