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]: 공연,날짜,회차에 대한 좌석 조회 API 추가 #42

Merged
merged 19 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a4b5c4a
[test]: ShowSeatsApiController test 추가
ssssujini99 Dec 27, 2023
3ca04db
[feat]: 공연 좌석 조회 controller 추가
ssssujini99 Dec 27, 2023
2d462d1
[feat]: 공연 좌석 조회 Application 추가
ssssujini99 Dec 27, 2023
d67ce94
[refactor]: 좌석 도메인 리팩토링
ssssujini99 Dec 27, 2023
5c71ae8
[test]: TestFixture 추가 및 기존 코드 리팩토링
ssssujini99 Dec 27, 2023
d00aa3b
[test]: 공연 좌석 조회 Application 테스트 추가
ssssujini99 Dec 27, 2023
d04118c
[feat]: 공연 좌석 조회 - SeatRepository, SeatRepositoryAdaptor 추가
ssssujini99 Dec 27, 2023
7aec39f
[test]: 공연 좌석 조회 - jpa query 테스트, adaptor 테스트 추가
ssssujini99 Dec 27, 2023
53d365b
[docs]: 인수테스트용 sql 더미데이터 파일 추가
ssssujini99 Dec 27, 2023
7906643
[refactor]: 코드 리팩토링
ssssujini99 Dec 27, 2023
a65dd13
[refactor]: 코드 라인 줄맞춤
ssssujini99 Dec 29, 2023
af5bbe9
[refactor]: EqualsAndHashCode 수정
ssssujini99 Dec 29, 2023
00ad503
[refactor]: 쿼리모델, 응답모델 분리
ssssujini99 Dec 29, 2023
b0172c6
[refactor]: 줄맞춤 리팩토링
ssssujini99 Dec 29, 2023
ab37917
[refactor]: sql 코드 라인 줄맞춤
ssssujini99 Dec 29, 2023
9fddc46
[refactor]: testFixture 클래스 위치 변경
ssssujini99 Dec 29, 2023
1715ae5
Merge branch 'dev' into feat/#36/show-seats-api
ssssujini99 Dec 29, 2023
c4164d4
[refactor]: 2차 리팩토링
ssssujini99 Dec 29, 2023
cd64c3e
Merge remote-tracking branch 'origin/feat/#36/show-seats-api' into fe…
ssssujini99 Dec 29, 2023
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
34 changes: 34 additions & 0 deletions api/src/main/java/dev/hooon/show/ShowSeatsApiController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.hooon.show;

import java.time.LocalDate;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import dev.hooon.show.application.ShowSeatsService;
import dev.hooon.show.dto.response.seats.ShowSeatsResponse;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
public class ShowSeatsApiController {

private final ShowSeatsService showSeatsService;

@GetMapping("/api/shows/{showId}/seats")
public ResponseEntity<ShowSeatsResponse> getShowSeatsInfo(
@PathVariable("showId") Long showId,
@RequestParam("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@RequestParam("round") int round
Comment on lines +25 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런건 Request dto 를 만드는게 어떨까요??

) {
ShowSeatsResponse showSeatsResponse = showSeatsService.findShowSeatsByShowIdAndDateAndRound(
showId, date, round
);
return ResponseEntity.ok(showSeatsResponse);
}

}
74 changes: 74 additions & 0 deletions api/src/test/java/dev/hooon/show/ShowSeatsApiControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package dev.hooon.show;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import dev.hooon.common.support.ApiTestSupport;

@DisplayName("[ShowSeatsApiController API 테스트]")
@Sql("/sql/show_seats_dummy.sql")
class ShowSeatsApiControllerTest extends ApiTestSupport {

@Autowired
private MockMvc mockMvc;

@DisplayName("[공연 아이디, 날짜, 회차]를 통해 API 를 호출하면 해당 공연의 세부 정보를 조회할 수 있다")
@Test
void getShowSeatsInfoTest() throws Exception {

// when
ResultActions resultActions = mockMvc.perform(
MockMvcRequestBuilders
.get("/api/shows/1/seats?date=2024-01-01&round=2")
);

// then
resultActions.andExpectAll(
status().isOk(),

jsonPath("$.seatsInfo").isArray(),
jsonPath("$.seatsInfo[0].grade").isString(),
jsonPath("$.seatsInfo[0].leftSeats").isNumber(),
jsonPath("$.seatsInfo[0].price").isNumber(),
jsonPath("$.seatsInfo[0].seats[0].id").isNumber(),
jsonPath("$.seatsInfo[0].seats[0].date").isString(),
jsonPath("$.seatsInfo[0].seats[0].isBookingAvailable").isString(),
jsonPath("$.seatsInfo[0].seats[0].seat").isBoolean(),
jsonPath("$.seatsInfo[0].seats[0].positionInfo_sector").isString(),
jsonPath("$.seatsInfo[0].seats[0].positionInfo_row").isString(),
jsonPath("$.seatsInfo[0].seats[0].positionInfo_col").isNumber(),

jsonPath("$.seatsInfo").isArray(),
jsonPath("$.seatsInfo[1].grade").isString(),
jsonPath("$.seatsInfo[1].leftSeats").isNumber(),
jsonPath("$.seatsInfo[1].price").isNumber(),
jsonPath("$.seatsInfo[1].seats[0].id").isNumber(),
jsonPath("$.seatsInfo[1].seats[0].date").isString(),
jsonPath("$.seatsInfo[1].seats[0].isBookingAvailable").isString(),
jsonPath("$.seatsInfo[1].seats[0].seat").isBoolean(),
jsonPath("$.seatsInfo[1].seats[0].positionInfo_sector").isString(),
jsonPath("$.seatsInfo[1].seats[0].positionInfo_row").isString(),
jsonPath("$.seatsInfo[1].seats[0].positionInfo_col").isNumber(),

jsonPath("$.seatsInfo").isArray(),
jsonPath("$.seatsInfo[2].grade").isString(),
jsonPath("$.seatsInfo[2].leftSeats").isNumber(),
jsonPath("$.seatsInfo[2].price").isNumber(),
jsonPath("$.seatsInfo[2].seats[0].id").isNumber(),
jsonPath("$.seatsInfo[2].seats[0].date").isString(),
jsonPath("$.seatsInfo[2].seats[0].isBookingAvailable").isString(),
jsonPath("$.seatsInfo[2].seats[0].seat").isBoolean(),
jsonPath("$.seatsInfo[2].seats[0].positionInfo_sector").isString(),
jsonPath("$.seatsInfo[2].seats[0].positionInfo_row").isString(),
jsonPath("$.seatsInfo[2].seats[0].positionInfo_col").isNumber()
Comment on lines +36 to +70
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와우 꼼꼼하시네요 ㅋㅋㅋ 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니당 😆

);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package dev.hooon.show.application;

import java.time.LocalDate;
import java.util.List;

import org.springframework.stereotype.Service;

import dev.hooon.common.exception.NotFoundException;
import dev.hooon.show.domain.repository.SeatRepository;
import dev.hooon.show.domain.repository.ShowRepository;
import dev.hooon.show.dto.response.seats.SeatsDetailDto;
import dev.hooon.show.dto.response.seats.SeatsInfoDto;
import dev.hooon.show.dto.response.seats.ShowSeatsResponse;
import dev.hooon.show.exception.ShowErrorCode;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class ShowSeatsService {

private final ShowRepository showRepository;
private final SeatRepository seatRepository;

public ShowSeatsResponse findShowSeatsByShowIdAndDateAndRound(Long showId, LocalDate date, int round) {

throwIfShowDoesNotExist(showId);

List<SeatsInfoDto> seatsInfoDtoList = seatRepository.findSeatInfoByShowIdAndDateAndRound(showId,
date, round);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파라미터를 한줄에 나열하거나 너무길면 한라인씩 분리해서 표현하는게 보기 좋을거같습니다 ..! ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영완료했습니다!

seatsInfoDtoList
.forEach(it -> {
List<SeatsDetailDto> seatsDetailDtoList = seatRepository.findSeatsByShowIdAndDateAndRoundAndGrade(
showId, date, round, it.getGrade()
);
it.setSeats(seatsDetailDtoList);
});

return new ShowSeatsResponse(seatsInfoDtoList);
}

private void throwIfShowDoesNotExist(Long showId) {
showRepository.findById(showId).orElseThrow(
() -> new NotFoundException(ShowErrorCode.SHOW_NOT_FOUND)
);
}
Comment on lines +52 to +56
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seat 에 대한 조회인데 저는 이부분에서 Show 에대한 검증이 없어도 될거같아요 🤔
그리고 해야된다면 메소드 네이밍은 검증의 역할이 강한거같은데 validateShowExist 이렇게 가는게 어떨까요?

Copy link
Contributor Author

@ssssujini99 ssssujini99 Dec 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throwIfShowDoesNotExist 라고 했는데 (show가 존재하지 않으면 예외를 던진다) 라는 의미입니다!! 혹시 어떠신가요?


}
193 changes: 106 additions & 87 deletions core/src/main/java/dev/hooon/show/domain/entity/seat/Seat.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Objects;

import org.springframework.util.Assert;

Expand All @@ -33,91 +34,109 @@
@NoArgsConstructor(access = PROTECTED)
public class Seat extends TimeBaseEntity {

private static final String SEAT = "seat";

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "seat_id")
private Long id;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "seat_show_id", nullable = false, foreignKey = @ForeignKey(value = NO_CONSTRAINT))
private Show show;

@Enumerated(STRING)
@Column(name = "seat_grade", nullable = false)
private SeatGrade seatGrade;

@Column(name = "seat_is_seat", nullable = false)
private boolean isSeat;

@Embedded
private SeatPositionInfo positionInfo;

@Column(name = "seat_price", nullable = false)
private int price;

@Column(name = "seat_show_date", nullable = false)
private LocalDate showDate;

@Embedded
private ShowRound showRound;

@Enumerated(STRING)
@Column(name = "seat_status", nullable = false)
private SeatStatus seatStatus;

private Seat(
Show show,
SeatGrade seatGrade,
boolean isSeat,
String sector,
String row,
int col,
int price,
LocalDate showDate,
int round,
LocalTime startTime,
SeatStatus seatStatus
) {
Assert.notNull(show, getNotNullMessage(SEAT, "show"));
Assert.notNull(seatGrade, getNotNullMessage(SEAT, "seatGrade"));
Assert.hasText(sector, getNotEmptyPostfix(SEAT, "sector"));
Assert.hasText(row, getNotEmptyPostfix(SEAT, "row"));
Assert.notNull(showDate, getNotNullMessage(SEAT, "showDate"));
Assert.notNull(startTime, getNotNullMessage(SEAT, "startTime"));
Assert.notNull(seatStatus, getNotNullMessage(SEAT, "seatStatus"));
this.show = show;
this.seatGrade = seatGrade;
this.isSeat = isSeat;
this.positionInfo = new SeatPositionInfo(sector, row, col);
this.price = price;
this.showDate = showDate;
this.showRound = new ShowRound(round, startTime);
this.seatStatus = seatStatus;
}

public static Seat of(
Show show,
SeatGrade seatGrade,
boolean isSeat,
String sector,
String row,
int col,
int price,
LocalDate showDate,
int round,
LocalTime startTime,
SeatStatus seatStatus
) {
return new Seat(show, seatGrade, isSeat, sector, row, col, price, showDate, round, startTime, seatStatus);
}

public int getRound() {
return showRound.getRound();
}

public LocalTime getStartTime() {
return showRound.getStartTime();
}
private static final String SEAT = "seat";

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "seat_id")
private Long id;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "seat_show_id", nullable = false, foreignKey = @ForeignKey(value = NO_CONSTRAINT))
private Show show;

@Enumerated(STRING)
@Column(name = "seat_grade", nullable = false)
private SeatGrade seatGrade;

@Column(name = "seat_is_seat", nullable = false)
private boolean isSeat;

@Embedded
private SeatPositionInfo positionInfo;

@Column(name = "seat_price", nullable = false)
private int price;

@Column(name = "seat_show_date", nullable = false)
private LocalDate showDate;

@Embedded
private ShowRound showRound;

@Enumerated(STRING)
@Column(name = "seat_status", nullable = false)
private SeatStatus seatStatus;

private Seat(
Show show,
SeatGrade seatGrade,
boolean isSeat,
String sector,
String row,
int col,
int price,
LocalDate showDate,
int round,
LocalTime startTime,
SeatStatus seatStatus
) {
Assert.notNull(show, getNotNullMessage(SEAT, "show"));
Assert.notNull(seatGrade, getNotNullMessage(SEAT, "seatGrade"));
Assert.hasText(sector, getNotEmptyPostfix(SEAT, "sector"));
Assert.hasText(row, getNotEmptyPostfix(SEAT, "row"));
Assert.notNull(showDate, getNotNullMessage(SEAT, "showDate"));
Assert.notNull(startTime, getNotNullMessage(SEAT, "startTime"));
Assert.notNull(seatStatus, getNotNullMessage(SEAT, "seatStatus"));
this.show = show;
this.seatGrade = seatGrade;
this.isSeat = isSeat;
this.positionInfo = new SeatPositionInfo(sector, row, col);
this.price = price;
this.showDate = showDate;
this.showRound = new ShowRound(round, startTime);
this.seatStatus = seatStatus;
}

public static Seat of(
Show show,
SeatGrade seatGrade,
boolean isSeat,
String sector,
String row,
int col,
int price,
LocalDate showDate,
int round,
LocalTime startTime,
SeatStatus seatStatus
) {
return new Seat(show, seatGrade, isSeat, sector, row, col, price, showDate, round, startTime, seatStatus);
}

public int getRound() {
return showRound.getRound();
}

public LocalTime getStartTime() {
return showRound.getStartTime();
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Seat seat = (Seat)o;
return isSeat == seat.isSeat && price == seat.price && Objects.equals(show, seat.show)
&& seatGrade == seat.seatGrade && Objects.equals(positionInfo, seat.positionInfo)
&& Objects.equals(showDate, seat.showDate) && Objects.equals(showRound, seat.showRound)
&& seatStatus == seat.seatStatus;
}

@Override
public int hashCode() {
return Objects.hash(show, seatGrade, isSeat, positionInfo, price, showDate, showRound, seatStatus);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id 비교도 추가하는게 좋을거같네요!

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
@RequiredArgsConstructor
public enum SeatGrade {

VIP("VIP석"),
R("R석"),
S("S석"),
A("A석"),
B("B석");
VIP("VIP석"),
R("R석"),
S("S석"),
A("A석"),
B("B석");

private final String description;
private final String description;

public String getDescription() {
return description;
}
}
Loading