export class CreateRoundDto extends PickType(Round, [
"content",
"datetime",
"showId",
]) {
@IsObject()
@ValidateNested()
seatPrices: Record<SeatClass, number>;
}
CreateRoundDto: 내용, 날짜와 시간, 공연 아이디, 좌석별 금액
@UseGuards(AuthGuard("admin"))
@Post(":showId")
async createRound(
@Body() createRoundDto: CreateRoundDto,
@Param("showId") showId: number,
) {
validate(createRoundDto);
return await this.roundService.createRound(createRoundDto, +showId);
}
Guard를 통해서 admin 권한을 가진 유저만 만들 수 있도록 해주었다.
async createRound(createRoundDto: CreateRoundDto, showId: number) {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
API 실행 중 실패하더라도 데이터베이스에 저장되지 않도록 트랜잭션을 이용하였다.
try {
const seats = await this.findSeatsId(showId);
async findSeatsId(showId: number) {
const show = await this.showRepository.findOneBy({ id: showId });
if (!show) {
throw new NotFoundException("해당 공연을 찾을 수 없습니다.");
}
const hall = await this.hallRepository.findOne({
where: { id: show.hallId },
relations: ["seats"],
});
return hall.seats.map((seat) => ({
id: seat.id,
seatClass: seat.seatClass,
}));
}
해당 공연의 공연장을 조회하여 좌석의 아이디와 좌석의 등급을 찾아주었다.
createRoundDto.showId = showId;
const round = await queryRunner.manager.save(Round, createRoundDto);
showId도 추가해준 후, 해당 회차정보를 저장해주었다.
const newRoundSeats = await this.createRoundSeat(
seats,
round.id,
createRoundDto.seatPrices,
);
await queryRunner.manager.save(RoundSeat, newRoundSeats);
공연장의 좌석들과 회차 아이디, 금액으로 회차별 좌석을 생성해주었다.
async createRoundSeat(
seats: { id: number; seatClass: SeatClass }[],
id: number,
seatPrices: Record<SeatClass, number>,
) {
const newRoundSeats = seats.map((seat) => {
const newRoundSeat = new CreateRoundSeatDto();
newRoundSeat.roundId = id;
newRoundSeat.seatId = seat.id;
newRoundSeat.price = seatPrices[seat.seatClass];
return newRoundSeat;
});
return newRoundSeats;
}
회차별 좌석을 위해서 새로운 회차별 좌석 배열을 만들어주었다.
await queryRunner.commitTransaction();
return round;
} catch (error) {
await queryRunner.rollbackTransaction();
return { message: `${error}` };
} finally {
await queryRunner.release();
}
}
성공 후 해당 회차를 return 해주었다!
간단하게 이렇게 설계를 한 이유를 말해보자면
먼저 같은 공연장이라고 하더라도 어떤 공연을 하는지에 따라 좌석의 등급별로 금액이 다를 수 있다는 생각이 들어 각각의 좌석 금액과, 상태를 넣어주기 위하여 RoundSeat를 만들었다.
회차를 생성해주는 것은 각각 해야하지만, 해당 회차별 좌석을 따로 생성하는 것은 비효율적이라는 생각이 들어서 회차 생성 시 좌석별 금액을 넣어서 Round - RoundSeat를 같이 생성했다.
티켓 예매 시에 RoundSeat를 통해 해당 공연, 회차 정보, 좌석별 금액, 좌석의 상태를 통해
간편하게 확인 할 수 있도록 설계하였다.