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 : 예매대기 처리 스케줄러 구현 #43

Merged
merged 14 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public enum SeatStatus {

AVAILABLE("예매 가능"),
BOOKED("예매 완료"),
CANCELED("예매 취소");
CANCELED("예매 취소"),
// 취소된 좌석이 예매대기로 인해 6시간동안 예매대기를 한 사용자에 한해 예약이 가능한 상태
WAITING("예매 대기");
Copy link
Contributor

Choose a reason for hiding this comment

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

👍🏻👍🏻


private final String description;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package dev.hooon.show.domain.repository;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

import dev.hooon.show.domain.entity.seat.Seat;
import dev.hooon.show.domain.entity.seat.SeatStatus;
import dev.hooon.show.dto.query.SeatDateRoundDto;

public interface SeatRepository {

void saveAll(Iterable<Seat> seats);

Optional<Seat> findById(Long id);

List<SeatDateRoundDto> findSeatDateRoundInfoByShowId(Long showId);

List<Seat> findByStatusIsCanceled();

void updateStatusByIdIn(Collection<Long> ids, SeatStatus status);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package dev.hooon.show.infrastructure.adaptor;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Repository;

import dev.hooon.show.domain.entity.seat.Seat;
import dev.hooon.show.domain.entity.seat.SeatStatus;
import dev.hooon.show.domain.repository.SeatRepository;
import dev.hooon.show.dto.query.SeatDateRoundDto;
import dev.hooon.show.infrastructure.repository.SeatJpaRepository;
Expand All @@ -21,8 +24,23 @@ public void saveAll(Iterable<Seat> seats) {
seatJpaRepository.saveAll(seats);
}

@Override
public Optional<Seat> findById(Long id) {
return seatJpaRepository.findById(id);
}

@Override
public List<SeatDateRoundDto> findSeatDateRoundInfoByShowId(Long showId) {
return seatJpaRepository.findSeatDateRoundInfoByShowId(showId);
}

@Override
public List<Seat> findByStatusIsCanceled() {
return seatJpaRepository.findBySeatStatus(SeatStatus.CANCELED);
}

@Override
public void updateStatusByIdIn(Collection<Long> ids, SeatStatus status) {
seatJpaRepository.updateStatusByIdIn(ids, status);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package dev.hooon.show.infrastructure.repository;

import java.util.Collection;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import dev.hooon.show.domain.entity.seat.Seat;
import dev.hooon.show.domain.entity.seat.SeatStatus;
import dev.hooon.show.dto.query.SeatDateRoundDto;

public interface SeatJpaRepository extends JpaRepository<Seat, Long> {
Expand All @@ -18,4 +22,10 @@ public interface SeatJpaRepository extends JpaRepository<Seat, Long> {
order by s.showDate, s.showRound.round
""")
List<SeatDateRoundDto> findSeatDateRoundInfoByShowId(Long showId);

List<Seat> findBySeatStatus(SeatStatus status);

@Modifying
@Query("update Seat s SET s.seatStatus = :status where s.id in :ids")
void updateStatusByIdIn(@Param("ids") Collection<Long> ids, @Param("status") SeatStatus status);
}
29 changes: 18 additions & 11 deletions core/src/main/java/dev/hooon/user/domain/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,25 @@
@NoArgsConstructor
public class User extends TimeBaseEntity {

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

@Column(name = "user_email", nullable = false, unique = true)
private String email;
@Column(name = "user_email", nullable = false, unique = true)
private String email;

@Column(name = "user_name", nullable = false)
private String name;
@Column(name = "user_name", nullable = false)
private String name;

@Enumerated(STRING)
@Column(name = "user_role", nullable = false)
private UserRole userRole;
@Enumerated(STRING)
@Column(name = "user_role", nullable = false)
private UserRole userRole;

// 테스트용 AllArgsConstructor
public User(String email, String name, UserRole userRole) {
this.email = email;
this.name = name;
this.userRole = userRole;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@

public interface UserRepository {

User save(User user);

Optional<User> findById(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public class UserRepositoryAdaptor implements UserRepository {

private final UserJpaRepository userJpaRepository;

@Override
public User save(User user) {
return userJpaRepository.save(user);
}

@Override
public Optional<User> findById(Long id) {
return userJpaRepository.findById(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static jakarta.persistence.FetchType.*;
import static jakarta.persistence.GenerationType.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -52,6 +53,8 @@ public class WaitingBooking extends TimeBaseEntity {

private int seatCount;

private LocalDateTime expireAt;
Copy link
Contributor

Choose a reason for hiding this comment

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

expiredAt 은 어떤가요?! (근데 사실 너무 사소함 ㅎㅎ)

Copy link
Member Author

Choose a reason for hiding this comment

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

의미적으로 그게 더 맞는거같네요! 수정하겠습니다 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

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

b84ab45
수정 했습니다~


@OneToMany(mappedBy = "waitingBooking", cascade = {REMOVE, PERSIST})
List<WaitingBookingSeat> waitingBookingSeats = new ArrayList<>();

Expand Down Expand Up @@ -108,4 +111,10 @@ public static WaitingBooking of(
) {
return new WaitingBooking(user, seatCount, seatIds);
}

public List<Long> getSelectedSeatIds() {
Copy link
Contributor

Choose a reason for hiding this comment

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

예약 대기 좌석에 해당하는 좌석 id값을 list로 반환하는 함수가 맞을까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

네 맞습니다~ 👍

return waitingBookingSeats.stream()
.map(WaitingBookingSeat::getSeatId)
.toList();
}
}
Copy link
Contributor

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
Expand Up @@ -10,17 +10,23 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.util.ReflectionTestUtils;

import dev.hooon.common.fixture.SeatFixture;
import dev.hooon.common.support.DataJpaTestSupport;
import dev.hooon.show.domain.entity.seat.Seat;
import dev.hooon.show.domain.entity.seat.SeatStatus;
import dev.hooon.show.dto.query.SeatDateRoundDto;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;

@DisplayName("[SeatJpaRepository 테스트]")
class SeatRepositoryTest extends DataJpaTestSupport {

@Autowired
private SeatRepository seatRepository;
@PersistenceContext
private EntityManager entityManager;

private void assertSeatDateRoundDto(SeatDateRoundDto dto, Seat expected) {
assertAll(
Expand Down Expand Up @@ -52,4 +58,54 @@ void findSeatDateRoundInfoByShowIdTest() {
assertSeatDateRoundDto(result.get(1), seats.get(2));
assertSeatDateRoundDto(result.get(2), seats.get(3));
}

@Test
@DisplayName("[상태가 CANCELED 상태인 좌석을 조회한다]")
void findByStatusIsCanceledTest() {
//given
List<Seat> seats = List.of(
SeatFixture.getSeat(),
SeatFixture.getSeat(),
SeatFixture.getSeat()
);
// 0번 Seat 만 Canceled 상태로 변경(취소 기능이 아직 구현되지 않아서 리플렉션 사용)
ReflectionTestUtils.setField(seats.get(0), "seatStatus", SeatStatus.CANCELED);
Copy link
Contributor

Choose a reason for hiding this comment

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

👍🏻👍🏻
저도 배워갑니다

Copy link
Member Author

Choose a reason for hiding this comment

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

리플랙션이 정말 사기적인 기술이긴한데.. 안좋은 측면도 있어서 남발하지만 않으면 좋은거같아요!


seatRepository.saveAll(seats);

//when
List<Seat> result = seatRepository.findByStatusIsCanceled();

//then
assertThat(result)
.hasSize(1)
.contains(seats.get(0));
}

@Test
@DisplayName("[id 와 status 를 입력하면 id 에 해당하는 좌석의 상태를 입력한 status 로 변경한다]")
void updateStatusByIdInTest() {
//given
List<Seat> seats = List.of(
SeatFixture.getSeat(),
SeatFixture.getSeat(),
SeatFixture.getSeat()
);
seatRepository.saveAll(seats);

List<Long> seatIds = seats.stream().map(Seat::getId).toList();

//when
seatRepository.updateStatusByIdIn(seatIds, SeatStatus.CANCELED);
entityManager.flush();
entityManager.clear();

//then
List<Seat> actual = seatRepository.findByStatusIsCanceled();
List<Long> actualIds = actual.stream().map(Seat::getId).toList();

assertThat(actualIds)
.hasSameSizeAs(seatIds)
.containsAll(seatIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,24 @@ void ofTest_4() {
.isInstanceOf(ValidationException.class)
.hasMessageContaining(WaitingBookingErrorCode.INVALID_SELECTED_SEAT_COUNT.getMessage());
}

@Test
@DisplayName("[선택한 좌석의 ID List 를 응답한다]")
void getSelectedSeatIdsTest() {
//given
List<Long> selectedSeatIds = List.of(1L, 2L, 3L, 4L, 5L);
WaitingBooking waitingBooking = WaitingBooking.of(
new User(),
3,
selectedSeatIds
);

//when
List<Long> result = waitingBooking.getSelectedSeatIds();

//then
assertThat(result)
.hasSameSizeAs(selectedSeatIds)
.containsAll(selectedSeatIds);
}
}
4 changes: 4 additions & 0 deletions scheduler/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
implementation project(':core')
testImplementation(testFixtures(project(':core')))
}
12 changes: 12 additions & 0 deletions scheduler/src/main/java/dev/hooon/SchedulerApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.hooon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SchedulerApplication {

public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
13 changes: 13 additions & 0 deletions scheduler/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: create
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true

logging:
level:
org.hibernate.sql: info
2 changes: 2 additions & 0 deletions settings.gradle
Copy link
Contributor

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
Expand Up @@ -2,3 +2,5 @@ rootProject.name = 'interpark'

include 'api'
include 'core'
include 'scheduler'