Skip to content

Commit

Permalink
Team のリポジトリのうち参照系をクエリサービスに分離
Browse files Browse the repository at this point in the history
  • Loading branch information
k-kbot committed Sep 3, 2023
1 parent 3d042c2 commit 6644693
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 123 deletions.
2 changes: 1 addition & 1 deletion backend/src/controller/team/response/get-teams-response.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TeamDto } from '../../../domain/repository-interface/team-repository';
import { TeamDto } from '../../../usecase/team/query-service-interface/team-query-service';

export class GetTeamsResponse {
teams: Team[];
Expand Down
8 changes: 5 additions & 3 deletions backend/src/controller/team/teams.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Get, Controller, Put, Body, Param } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { TeamQueryService } from '../../infra/db/query-service/team-query-service';
import { TeamRepository } from '../../infra/db/repository/team/team-repository';
import { GetTeamsUsecase } from '../../usecase/team/get-teams-usecase';
import { GetTeamsResponse } from './response/get-teams-response';
Expand All @@ -11,8 +12,8 @@ export class TeamsController {
@Get()
async getTeams(): Promise<GetTeamsResponse> {
const prisma = new PrismaClient();
const teamRepository = new TeamRepository(prisma);
const usecase = new GetTeamsUsecase(teamRepository);
const teamQueryService = new TeamQueryService(prisma);
const usecase = new GetTeamsUsecase(teamQueryService);
const result = await usecase.do();
return new GetTeamsResponse(result);
}
Expand All @@ -23,8 +24,9 @@ export class TeamsController {
@Body() updateTeamDto: UpdateTeamRequest,
): Promise<boolean> {
const prisma = new PrismaClient();
const teamQueryService = new TeamQueryService(prisma);
const teamRepository = new TeamRepository(prisma);
const usecase = new UpdateTeamUsecase(teamRepository);
const usecase = new UpdateTeamUsecase(teamQueryService, teamRepository);
return await usecase.do({ id, name: updateTeamDto.name });
}
}
3 changes: 0 additions & 3 deletions backend/src/domain/repository-interface/team-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,5 @@ export class TeamDto {
}

export interface ITeamRepository {
findAll(): Promise<TeamDto[]>;
findById(id: string): Promise<TeamDto | undefined>;
findByName(name: string): Promise<TeamDto | undefined>;
update(team: Team): Promise<boolean>;
}
6 changes: 3 additions & 3 deletions backend/src/domain/team/unique-team-name-validator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ITeamRepository } from '../repository-interface/team-repository';
import { ITeamQueryService } from '../../usecase/team/query-service-interface/team-query-service';

export class UniqueTeamNameValidator {
constructor(private teamRepository: ITeamRepository) {}
constructor(private teamQueryService: ITeamQueryService) {}

async exists(teamName: string): Promise<boolean> {
const teamDto = await this.teamRepository.findByName(teamName);
const teamDto = await this.teamQueryService.findByName(teamName);
return !!teamDto;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { TeamRepository } from './team-repository';
import { Team } from '../../../../domain/team/team';
import { TeamId } from '../../../../domain/team/team-id';
import { TeamName } from '../../../../domain/team/team-name';
import { prisma } from '../../../../../testUtils/prisma';
import { TeamDto } from '../../../../domain/repository-interface/team-repository';
import { TeamQueryService } from './team-query-service';
import { prisma } from '../../../../testUtils/prisma';
import { TeamDto } from '../../../usecase/team/query-service-interface/team-query-service';

describe('TeamRepository', () => {
const teamRepository = new TeamRepository(prisma);
describe('TeamQueryService', () => {
const teamQueryService = new TeamQueryService(prisma);

afterEach(async () => {
await prisma.team.deleteMany({});
Expand All @@ -33,7 +30,7 @@ describe('TeamRepository', () => {
});

// Act
const actual = await teamRepository.findAll();
const actual = await teamQueryService.findAll();

// Assert
expect(actual).toStrictEqual([
Expand Down Expand Up @@ -68,7 +65,7 @@ describe('TeamRepository', () => {
});

// Act
const actual = await teamRepository.findById(id);
const actual = await teamQueryService.findById(id);

// Assert
expect(actual).toStrictEqual(
Expand All @@ -93,7 +90,7 @@ describe('TeamRepository', () => {
});

// Act
const actual = await teamRepository.findById('2');
const actual = await teamQueryService.findById('2');

// Assert
expect(actual).toBeUndefined();
Expand All @@ -115,7 +112,7 @@ describe('TeamRepository', () => {
});

// Act
const actual = await teamRepository.findByName(name);
const actual = await teamQueryService.findByName(name);

// Assert
expect(actual).toStrictEqual(
Expand All @@ -140,38 +137,10 @@ describe('TeamRepository', () => {
});

// Act
const actual = await teamRepository.findByName('002');
const actual = await teamQueryService.findByName('002');

// Assert
expect(actual).toBeUndefined();
});
});
describe('update', () => {
it('正常系 チームの名前を更新できること', async () => {
// Arrange
const id = '1';

await prisma.team.create({
data: {
id,
name: '001',
createdAt: '2023-01-01T09:00:00Z',
updatedAt: '2023-01-01T09:00:00Z',
},
});

const team = Team.rebuild({
id: TeamId.rebuild(id),
name: TeamName.rebuild('002'),
createdAt: new Date('2023-01-01T09:00:00Z'),
updatedAt: new Date('2023-01-01T09:00:00Z'),
});

// Act
const actual = await teamRepository.update(team);

// Assert
expect(actual).toBe(true);
});
});
});
56 changes: 56 additions & 0 deletions backend/src/infra/db/query-service/team-query-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { PrismaClient } from '@prisma/client';
import {
ITeamQueryService,
TeamDto,
} from '../../../usecase/team/query-service-interface/team-query-service';

export class TeamQueryService implements ITeamQueryService {
constructor(private prismaClient: PrismaClient) {}

async findAll(): Promise<TeamDto[]> {
const teams = await this.prismaClient.team.findMany();
return teams.map(
(team) =>
new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
}),
);
}

async findById(id: string): Promise<TeamDto | undefined> {
const team = await this.prismaClient.team.findUnique({
where: {
id,
},
});

if (!team) return undefined;

return new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
});
}

async findByName(name: string): Promise<TeamDto | undefined> {
const team = await this.prismaClient.team.findFirst({
where: {
name,
},
});

if (!team) return undefined;

return new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { TeamRepository } from './team-repository';
import { Team } from '../../../../domain/team/team';
import { TeamId } from '../../../../domain/team/team-id';
import { TeamName } from '../../../../domain/team/team-name';
import { prisma } from '../../../../../testUtils/prisma';

describe('TeamRepository', () => {
const teamRepository = new TeamRepository(prisma);

afterEach(async () => {
await prisma.team.deleteMany({});
});

describe('update', () => {
it('正常系 チームの名前を更新できること', async () => {
// Arrange
const id = '1';

await prisma.team.create({
data: {
id,
name: '001',
createdAt: '2023-01-01T09:00:00Z',
updatedAt: '2023-01-01T09:00:00Z',
},
});

const team = Team.rebuild({
id: TeamId.rebuild(id),
name: TeamName.rebuild('002'),
createdAt: new Date('2023-01-01T09:00:00Z'),
updatedAt: new Date('2023-01-01T09:00:00Z'),
});

// Act
const actual = await teamRepository.update(team);

// Assert
expect(actual).toBe(true);
});
});
});
52 changes: 1 addition & 51 deletions backend/src/infra/db/repository/team/team-repository.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,10 @@
import { PrismaClient } from '@prisma/client';
import {
ITeamRepository,
TeamDto,
} from '../../../../domain/repository-interface/team-repository';
import { ITeamRepository } from '../../../../domain/repository-interface/team-repository';
import { Team } from '../../../../domain/team/team';

export class TeamRepository implements ITeamRepository {
constructor(private prismaClient: PrismaClient) {}

async findAll(): Promise<TeamDto[]> {
const teams = await this.prismaClient.team.findMany();
return teams.map(
(team) =>
new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
}),
);
}

async findById(id: string): Promise<TeamDto | undefined> {
const team = await this.prismaClient.team.findUnique({
where: {
id,
},
});

if (!team) return undefined;

return new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
});
}

async findByName(name: string): Promise<TeamDto | undefined> {
const team = await this.prismaClient.team.findFirst({
where: {
name,
},
});

if (!team) return undefined;

return new TeamDto({
id: team.id,
name: team.name,
createdAt: team.createdAt,
updatedAt: team.updatedAt,
});
}

async update(team: Team): Promise<boolean> {
const { id, name } = team.getAllProperties();
await this.prismaClient.team.update({
Expand Down
14 changes: 7 additions & 7 deletions backend/src/usecase/team/get-teams-usecase.spec.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import { GetTeamsUsecase } from './get-teams-usecase';
import { TeamRepository } from '../../infra/db/repository/team/team-repository';
import { TeamQueryService } from '../../infra/db/query-service/team-query-service';
import { PrismaClient } from '@prisma/client';

jest.mock('@prisma/client');
jest.mock('../../infra/db/repository/team/team-repository');
jest.mock('../../infra/db/query-service/team-query-service');

describe('GetTeamsUsecase', () => {
let mockRepository: jest.MockedObjectDeep<TeamRepository>;
let mockQueryService: jest.MockedObjectDeep<TeamQueryService>;

beforeAll(() => {
const prisma = new PrismaClient();
mockRepository = jest.mocked(new TeamRepository(prisma));
mockQueryService = jest.mocked(new TeamQueryService(prisma));
});

describe('do', () => {
it('正常系 TeamRepository.findAllを1回コールすること', async () => {
it('正常系 TeamQueryService.findAllを1回コールすること', async () => {
// Act
const usecase = new GetTeamsUsecase(mockRepository);
const usecase = new GetTeamsUsecase(mockQueryService);
await usecase.do();

// Assert
expect(mockRepository.findAll).toHaveBeenCalledTimes(1);
expect(mockQueryService.findAll).toHaveBeenCalledTimes(1);
});
});
});
8 changes: 4 additions & 4 deletions backend/src/usecase/team/get-teams-usecase.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
ITeamRepository,
ITeamQueryService,
TeamDto,
} from '../../domain/repository-interface/team-repository';
} from './query-service-interface/team-query-service';

export class GetTeamsUsecase {
constructor(private teamRepository: ITeamRepository) {}
constructor(private teamQueryService: ITeamQueryService) {}

async do(): Promise<TeamDto[]> {
return await this.teamRepository.findAll();
return await this.teamQueryService.findAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export class TeamDto {
public readonly id: string;
public readonly name: string;
public readonly createdAt: Date;
public readonly updatedAt: Date;

constructor(props: {
id: string;
name: string;
createdAt: Date;
updatedAt: Date;
}) {
const { id, name, createdAt, updatedAt } = props;
this.id = id;
this.name = name;
this.createdAt = createdAt;
this.updatedAt = updatedAt;
}
}

export interface ITeamQueryService {
findAll(): Promise<TeamDto[]>;
findById(id: string): Promise<TeamDto | undefined>;
findByName(name: string): Promise<TeamDto | undefined>;
}
Loading

0 comments on commit 6644693

Please sign in to comment.