Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: MainMatchにdepartmentTypematchTypeを追加 #558

Merged
merged 7 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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