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

[BE] feat: AdminStageV1Controller에 공연 단건 조회 기능 추가 (#855) #856

Merged
merged 6 commits into from
Apr 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.festago.admin.dto.stage.AdminStageV1Response;
import com.festago.admin.repository.AdminStageV1QueryDslRepository;
import com.festago.common.exception.ErrorCode;
import com.festago.common.exception.NotFoundException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -17,4 +19,9 @@ public class AdminStageV1QueryService {
public List<AdminStageV1Response> findAllByFestivalId(Long festivalId) {
return adminStageV1QueryDslRepository.findAllByFestivalId(festivalId);
}

public AdminStageV1Response findById(Long stageId) {
return adminStageV1QueryDslRepository.findById(stageId)
.orElseThrow(() -> new NotFoundException(ErrorCode.STAGE_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.festago.admin.presentation.v1;

import com.festago.admin.application.AdminStageV1QueryService;
import com.festago.admin.dto.stage.AdminStageV1Response;
import com.festago.admin.dto.stage.StageV1CreateRequest;
import com.festago.admin.dto.stage.StageV1UpdateRequest;
import com.festago.stage.application.command.StageCommandFacadeService;
Expand All @@ -9,6 +11,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -23,6 +26,15 @@
public class AdminStageV1Controller {

private final StageCommandFacadeService stageCommandFacadeService;
private final AdminStageV1QueryService adminStageV1QueryService;

@GetMapping("/{stageId}")
public ResponseEntity<AdminStageV1Response> findById(
@PathVariable Long stageId
) {
return ResponseEntity.ok()
.body(adminStageV1QueryService.findById(stageId));
}

@PostMapping
public ResponseEntity<Void> createStage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.festago.common.querydsl.QueryDslRepositorySupport;
import com.festago.stage.domain.Stage;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;

@Repository
Expand Down Expand Up @@ -43,4 +44,30 @@ public List<AdminStageV1Response> findAllByFestivalId(Long festivalId) {
)
);
}

public Optional<AdminStageV1Response> findById(Long stageId) {
List<AdminStageV1Response> response = selectFrom(stage)
.leftJoin(stageArtist).on(stageArtist.stageId.eq(stageId))
.leftJoin(artist).on(artist.id.eq(stageArtist.artistId))
.where(stage.id.eq(stageId))
.transform(
groupBy(stage.id).list(
new QAdminStageV1Response(
stage.id,
stage.startTime,
stage.ticketOpenTime,
list(new QAdminStageArtistV1Response(
artist.id,
artist.name
)),
stage.createdAt,
stage.updatedAt
)
)
);
if (response.isEmpty()) {
return Optional.empty();
}
return Optional.of(response.get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import static java.util.stream.Collectors.toMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.SoftAssertions.assertSoftly;

import com.festago.admin.application.AdminStageV1QueryService;
import com.festago.admin.dto.stage.AdminStageArtistV1Response;
import com.festago.admin.dto.stage.AdminStageV1Response;
import com.festago.artist.domain.Artist;
import com.festago.artist.repository.ArtistRepository;
import com.festago.common.exception.ErrorCode;
import com.festago.common.exception.NotFoundException;
import com.festago.festival.domain.Festival;
import com.festago.festival.repository.FestivalRepository;
import com.festago.school.repository.SchoolRepository;
Expand Down Expand Up @@ -55,116 +59,187 @@ class AdminStageV1QueryServiceIntegrationTest extends ApplicationIntegrationTest
LocalDate _2077년_6월_16일 = LocalDate.parse("2077-06-16");
LocalDate _2077년_6월_17일 = LocalDate.parse("2077-07-17");

@Test
void 존재하지_않는_축제의_식별자로_조회하면_빈_리스트가_반환된다() {
// when
var actual = adminStageV1QueryService.findAllByFestivalId(4885L);

// then
assertThat(actual).isEmpty();
}

@Nested
class 축제에_공연이_없으면 {

Long 축제_식별자;

@BeforeEach
void setUp() {
var 학교 = schoolRepository.save(SchoolFixture.builder().build());
축제_식별자 = festivalRepository.save(FestivalFixture.builder()
.startDate(_2077년_6월_15일)
.endDate(_2077년_6월_15일)
.school(학교)
.build()).getId();
}
class findAllByFestivalId {

@Test
void 빈_리스트가_반환된다() {
void 존재하지_않는_축제의_식별자로_조회하면_빈_리스트가_반환된다() {
// when
var actual = adminStageV1QueryService.findAllByFestivalId(축제_식별자);
var actual = adminStageV1QueryService.findAllByFestivalId(4885L);

// then
assertThat(actual).isEmpty();
}
}

/**
* 6월 15일 ~ 6월 17일까지 진행되는 축제<p> 6월 15일 공연, 6월 16일 공연이 있다.<p>
* <p>
* 6월 15일 공연에는 아티스트A, 아티스트B가 참여한다.<p> 6월 16일 공연에는 아티스트C가 참여한다.
*/
@Nested
class 특정_축제의_공연_목록과_참여하는_아티스트를_조회할_수_있어야_한다 {

Long 아티스트A_식별자;
Long 아티스트B_식별자;
Long 아티스트C_식별자;
Festival 축제;
Long _6월_15일_공연_식별자;
Long _6월_16일_공연_식별자;

@BeforeEach
void setUp() {
아티스트A_식별자 = createArtist("아티스트A");
아티스트B_식별자 = createArtist("아티스트B");
아티스트C_식별자 = createArtist("아티스트C");
var 학교 = schoolRepository.save(SchoolFixture.builder().build());
축제 = festivalRepository.save(FestivalFixture.builder()
.startDate(_2077년_6월_15일)
.endDate(_2077년_6월_17일)
.school(학교)
.build());
_6월_15일_공연_식별자 = createStage(축제, _2077년_6월_15일, List.of(아티스트A_식별자, 아티스트B_식별자)).getId();
_6월_16일_공연_식별자 = createStage(축제, _2077년_6월_16일, List.of(아티스트C_식별자)).getId();
}
@Nested
class 축제에_공연이_없으면 {

Long 축제_식별자;

@BeforeEach
void setUp() {
var 학교 = schoolRepository.save(SchoolFixture.builder().build());
축제_식별자 = festivalRepository.save(FestivalFixture.builder()
.startDate(_2077년_6월_15일)
.endDate(_2077년_6월_15일)
.school(학교)
.build()).getId();
}

private Long createArtist(String artistName) {
return artistRepository.save(ArtistFixture.builder()
.name(artistName)
.build()
).getId();
@Test
void 빈_리스트가_반환된다() {
// when
var actual = adminStageV1QueryService.findAllByFestivalId(축제_식별자);

// then
assertThat(actual).isEmpty();
}
}

private Stage createStage(Festival festival, LocalDate localDate, List<Long> artistIds) {
var 공연 = stageRepository.save(StageFixture.builder()
.festival(festival)
.startTime(localDate.atTime(18, 0))
.build()
);
for (Long artistId : artistIds) {
stageArtistRepository.save(StageArtistFixture.builder(공연.getId(), artistId).build());
/**
* 6월 15일 ~ 6월 17일까지 진행되는 축제<p> 6월 15일 공연, 6월 16일 공연이 있다.<p>
* <p>
* 6월 15일 공연에는 아티스트A, 아티스트B가 참여한다.<p> 6월 16일 공연에는 아티스트C가 참여한다.
*/
@Nested
class 축제에_공연이_있으면 {

Long 아티스트A_식별자;
Long 아티스트B_식별자;
Long 아티스트C_식별자;
Festival 축제;
Long _6월_15일_공연_식별자;
Long _6월_16일_공연_식별자;

@BeforeEach
void setUp() {
아티스트A_식별자 = createArtist("아티스트A").getId();
아티스트B_식별자 = createArtist("아티스트B").getId();
아티스트C_식별자 = createArtist("아티스트C").getId();
var 학교 = schoolRepository.save(SchoolFixture.builder().build());
축제 = festivalRepository.save(FestivalFixture.builder()
.startDate(_2077년_6월_15일)
.endDate(_2077년_6월_17일)
.school(학교)
.build());
_6월_15일_공연_식별자 = createStage(축제, _2077년_6월_15일, List.of(아티스트A_식별자, 아티스트B_식별자)).getId();
_6월_16일_공연_식별자 = createStage(축제, _2077년_6월_16일, List.of(아티스트C_식별자)).getId();
}

@Test
void 공연의_시작_순서대로_정렬된다() {
// when
var actual = adminStageV1QueryService.findAllByFestivalId(축제.getId());

// then
assertThat(actual)
.map(AdminStageV1Response::id)
.containsExactly(_6월_15일_공연_식별자, _6월_16일_공연_식별자);
}

@Test
void 해당_일자의_공연에_참여하는_아티스트_목록을_조회할_수_있다() {
// when
var stageIdToArtists = adminStageV1QueryService.findAllByFestivalId(축제.getId()).stream()
.collect(toMap(AdminStageV1Response::id, AdminStageV1Response::artists));

// then
assertSoftly(softly -> {
softly.assertThat(stageIdToArtists.get(_6월_15일_공연_식별자))
.map(AdminStageArtistV1Response::id)
.containsExactlyInAnyOrder(아티스트A_식별자, 아티스트B_식별자);

softly.assertThat(stageIdToArtists.get(_6월_16일_공연_식별자))
.map(AdminStageArtistV1Response::id)
.containsExactlyInAnyOrder(아티스트C_식별자);
});
}
return 공연;
}
}

@Test
void 공연의_시작_순서대로_정렬된다() {
// when
var actual = adminStageV1QueryService.findAllByFestivalId(축제.getId());
private Artist createArtist(String artistName) {
return artistRepository.save(ArtistFixture.builder()
.name(artistName)
.build()
);
}

// then
assertThat(actual)
.map(AdminStageV1Response::id)
.containsExactly(_6월_15일_공연_식별자, _6월_16일_공연_식별자);
private Stage createStage(Festival festival, LocalDate localDate, List<Long> artistIds) {
var 공연 = stageRepository.save(StageFixture.builder()
.festival(festival)
.startTime(localDate.atTime(18, 0))
.build()
);
for (Long artistId : artistIds) {
stageArtistRepository.save(StageArtistFixture.builder(공연.getId(), artistId).build());
}
return 공연;
}

@Test
void 해당_일자의_공연에_참여하는_아티스트_목록을_조회할_수_있다() {
// when
var stageIdToArtists = adminStageV1QueryService.findAllByFestivalId(축제.getId()).stream()
.collect(toMap(AdminStageV1Response::id, AdminStageV1Response::artists));
@Nested
class findById {

// then
assertSoftly(softly -> {
softly.assertThat(stageIdToArtists.get(_6월_15일_공연_식별자))
.map(AdminStageArtistV1Response::id)
.containsExactlyInAnyOrder(아티스트A_식별자, 아티스트B_식별자);

softly.assertThat(stageIdToArtists.get(_6월_16일_공연_식별자))
.map(AdminStageArtistV1Response::id)
.containsExactlyInAnyOrder(아티스트C_식별자);
});
@Nested
class 식별자에_해당하는_공연이_없으면 {

@Test
void 예외가_발생한다() {
// when & then
assertThatThrownBy(() -> adminStageV1QueryService.findById(4885L))
.isInstanceOf(NotFoundException.class)
.hasMessage(ErrorCode.STAGE_NOT_FOUND.getMessage());
}
}

@Nested
class 식별자에_해당하는_공연이_있으면 {

Artist 아티스트A;
Artist 아티스트B;
Artist 아티스트C;
Stage 공연;

@BeforeEach
void setUp() {
var 학교 = schoolRepository.save(SchoolFixture.builder().build());
var 축제 = festivalRepository.save(FestivalFixture.builder()
.startDate(_2077년_6월_15일)
.endDate(_2077년_6월_15일)
.school(학교)
.build()
);
아티스트A = createArtist("아티스트A");
아티스트B = createArtist("아티스트B");
아티스트C = createArtist("아티스트C");
공연 = createStage(
축제,
_2077년_6월_15일,
List.of(아티스트A.getId(), 아티스트B.getId(), 아티스트C.getId())
);
}

@Test
void 공연의_정보가_정확하게_조회되어야_한다() {
// when
var actual = adminStageV1QueryService.findById(공연.getId());

assertSoftly(softly -> {
softly.assertThat(actual.id()).isEqualTo(공연.getId());
softly.assertThat(actual.startDateTime()).isEqualTo(공연.getStartTime());
softly.assertThat(actual.ticketOpenTime()).isEqualTo(공연.getTicketOpenTime());
});
}

@Test
void 공연의_아티스트_목록이_조회되어야_한다() {
// when
var actual = adminStageV1QueryService.findById(공연.getId());

// then
assertThat(actual.artists())
.map(AdminStageArtistV1Response::name)
.containsExactlyInAnyOrder(아티스트A.getName(), 아티스트B.getName(), 아티스트C.getName());
}
}
}
}
Loading
Loading