From 586fcbdc02db5fffe3a171d6780ad432b6741011 Mon Sep 17 00:00:00 2001 From: Minseong Park <52368015+pminsung12@users.noreply.github.com> Date: Mon, 9 Sep 2024 03:00:45 +0900 Subject: [PATCH] =?UTF-8?q?[BSVR-257]=20=EB=A6=AC=EB=B7=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20API=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20-=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20nullable=20=EC=B2=98=EB=A6=AC=20(#185)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: spring 디폴트 프로필 local로 변경 * feat: UpdateReviewRequest에 stadiumId, rowNumber, reviewType 추가 * feat: UpdateReviewCommand에 stadiumId, rowNumber, reviewType 추가 * refactor: findByBlockIdAndSeatNumber 메서드 이름 변경 * feat: block id와 number로 BlockRow 엔티티 조회해오는 repository 메서드 구현 * feat: 리팩토링 위한 ReviewLocationInfo 도메인 생성 * feat: ReviewDataProcessor에 업데이트 로직 이관 * feat: ReviewDataProcessor에 업데이트된 리뷰 생성 로직 이관 * feat: processReviewDetails 메서드 reviewCreationProcessor로 리팩토링 * feat: ReviewKeywordProcessor에 업데이트쪽 updateBlockTopKeywords 메서드 이동 * feat: Processor를 적용해 UpdatteReviewService 리팩토링 * refactor: 더이상 사용하지 않는 UpdateReviewService 필드 삭제 --- .../dto/request/UpdateReviewRequest.java | 11 +- .../src/main/resources/application.yaml | 2 +- .../domain/review/ReviewLocationInfo.java | 8 ++ .../repository/row/BlockRowJpaRepository.java | 4 +- .../row/BlockRowRepositoryImpl.java | 8 +- .../seat/repository/SeatRepositoryImpl.java | 4 +- .../port/in/review/UpdateReviewUsecase.java | 6 +- .../port/out/block/BlockRowRepository.java | 2 + .../usecase/port/out/seat/SeatRepository.java | 4 +- .../service/review/CreateReviewService.java | 25 +--- .../service/review/UpdateReviewService.java | 117 ++---------------- .../processor/ReviewCreationProcessor.java | 12 ++ .../ReviewCreationProcessorImpl.java | 60 +++++++++ .../review/processor/ReviewDataProcessor.java | 10 ++ .../processor/ReviewDataProcessorImpl.java | 75 ++++++++++- .../processor/ReviewKeywordProcessor.java | 28 +++++ .../service/fake/FakeSeatRepository.java | 4 +- 17 files changed, 240 insertions(+), 140 deletions(-) create mode 100644 domain/src/main/java/org/depromeet/spot/domain/review/ReviewLocationInfo.java diff --git a/application/src/main/java/org/depromeet/spot/application/review/dto/request/UpdateReviewRequest.java b/application/src/main/java/org/depromeet/spot/application/review/dto/request/UpdateReviewRequest.java index ec9cf91d..81f5c6f9 100644 --- a/application/src/main/java/org/depromeet/spot/application/review/dto/request/UpdateReviewRequest.java +++ b/application/src/main/java/org/depromeet/spot/application/review/dto/request/UpdateReviewRequest.java @@ -10,27 +10,34 @@ import org.depromeet.spot.common.exception.review.ReviewException.InvalidReviewDateTimeFormatException; import org.depromeet.spot.common.exception.review.ReviewException.InvalidReviewKeywordsException; +import org.depromeet.spot.domain.review.Review.ReviewType; import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand; public record UpdateReviewRequest( + @NotNull Long stadiumId, @NotNull Long blockId, - @NotNull Integer seatNumber, + Integer rowNumber, + Integer seatNumber, @Size(min = 1, max = 3) List images, List good, List bad, String content, - @NotNull String dateTime) { + @NotNull String dateTime, + ReviewType reviewType) { public UpdateReviewCommand toCommand() { validateGoodAndBad(); return UpdateReviewCommand.builder() + .stadiumId(stadiumId) .blockId(blockId) + .rowNumber(rowNumber) .seatNumber(seatNumber) .images(images) .good(good) .bad(bad) .content(content) .dateTime(toLocalDateTime(dateTime)) + .reviewType(reviewType) .build(); } diff --git a/application/src/main/resources/application.yaml b/application/src/main/resources/application.yaml index aa4a88d8..076af459 100644 --- a/application/src/main/resources/application.yaml +++ b/application/src/main/resources/application.yaml @@ -5,7 +5,7 @@ server: spring: # 서브모듈 profile profiles: - active: dev + active: local group: local: - jpa diff --git a/domain/src/main/java/org/depromeet/spot/domain/review/ReviewLocationInfo.java b/domain/src/main/java/org/depromeet/spot/domain/review/ReviewLocationInfo.java new file mode 100644 index 00000000..56566f4f --- /dev/null +++ b/domain/src/main/java/org/depromeet/spot/domain/review/ReviewLocationInfo.java @@ -0,0 +1,8 @@ +package org.depromeet.spot.domain.review; + +import org.depromeet.spot.domain.block.Block; +import org.depromeet.spot.domain.block.BlockRow; +import org.depromeet.spot.domain.seat.Seat; +import org.depromeet.spot.domain.section.Section; + +public record ReviewLocationInfo(Section section, Block block, BlockRow row, Seat seat) {} diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowJpaRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowJpaRepository.java index 28c870a3..90ecde01 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowJpaRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowJpaRepository.java @@ -15,7 +15,7 @@ public interface BlockRowJpaRepository extends JpaRepository findAllByStadiumAndBlock( @Param("stadiumId") Long stadiumId, @Param("code") String code); + + BlockRowEntity findByBlockIdAndNumber(Long blockId, Integer number); } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowRepositoryImpl.java index dba84130..fc281de1 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/block/repository/row/BlockRowRepositoryImpl.java @@ -31,7 +31,13 @@ public List findAllByBlock(Long blockId) { @Override public BlockRow findBy(long stadiumId, String blockCode, int rowNumber) { BlockRowEntity entity = - blockRowJpaRepository.findByBlockAndNumber(stadiumId, blockCode, rowNumber); + blockRowJpaRepository.findByCodeAndNumber(stadiumId, blockCode, rowNumber); + return entity.toDomain(); + } + + @Override + public BlockRow findBy(Long blockId, Integer rowNumber) { + BlockRowEntity entity = blockRowJpaRepository.findByBlockIdAndNumber(blockId, rowNumber); return entity.toDomain(); } } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/seat/repository/SeatRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/seat/repository/SeatRepositoryImpl.java index c40205b2..efea0716 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/seat/repository/SeatRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/seat/repository/SeatRepositoryImpl.java @@ -34,14 +34,14 @@ public Seat findById(Long seatId) { } @Override - public Seat findByIdWith(Long seatId) { + public Seat findByBlockIdAndSeatNumber(Long seatId) { SeatEntity entity = seatJpaRepository.findByIdWith(seatId).orElseThrow(SeatNotFoundException::new); return entity.toDomain(); } @Override - public Seat findByIdWith(Long blockId, Integer seatNumber) { + public Seat findByBlockIdAndSeatNumber(Long blockId, Integer seatNumber) { SeatEntity entity = seatJpaRepository .findByIdWith(blockId, seatNumber) diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/UpdateReviewUsecase.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/UpdateReviewUsecase.java index e0920f7e..91fdb8b6 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/UpdateReviewUsecase.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/review/UpdateReviewUsecase.java @@ -4,6 +4,7 @@ import java.util.List; import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.Review.ReviewType; import lombok.Builder; @@ -16,13 +17,16 @@ public interface UpdateReviewUsecase { @Builder record UpdateReviewCommand( + Long stadiumId, Long blockId, + Integer rowNumber, Integer seatNumber, List images, List good, List bad, String content, - LocalDateTime dateTime) {} + LocalDateTime dateTime, + ReviewType reviewType) {} record UpdateReviewResult(Review review) {} } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/block/BlockRowRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/block/BlockRowRepository.java index c07b6b4c..c43d1402 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/block/BlockRowRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/block/BlockRowRepository.java @@ -11,4 +11,6 @@ public interface BlockRowRepository { List findAllByBlock(Long blockId); BlockRow findBy(long stadiumId, String blockCode, int rowNumber); + + BlockRow findBy(Long blockId, Integer rowNumber); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/seat/SeatRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/seat/SeatRepository.java index 9611e73f..3e10c555 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/seat/SeatRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/seat/SeatRepository.java @@ -13,9 +13,9 @@ public interface SeatRepository { Seat findById(Long seatId); - Seat findByIdWith(Long seatId); + Seat findByBlockIdAndSeatNumber(Long seatId); - Seat findByIdWith(Long blockId, Integer seatNumber); + Seat findByBlockIdAndSeatNumber(Long blockId, Integer seatNumber); Map> findSeatsGroupByRowInBlock(Block block); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/CreateReviewService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/CreateReviewService.java index 38ea038a..e3a782c8 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/CreateReviewService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/CreateReviewService.java @@ -1,6 +1,5 @@ package org.depromeet.spot.usecase.service.review; -import java.util.List; import java.util.Map; import org.depromeet.spot.domain.member.Member; @@ -41,7 +40,8 @@ public CreateReviewResult create(Long blockId, Long memberId, CreateReviewComman Review review = reviewCreationProcessor.createReview(blockId, member, command); - Map keywordMap = processReviewDetails(review, command); + Map keywordMap = + reviewCreationProcessor.processReviewDetails(review, command); Review savedReview = reviewRepository.save(review); reviewKeywordProcessor.updateBlockTopKeywords(savedReview); @@ -69,7 +69,8 @@ public void createAdmin( reviewCreationProcessor.createAdminReview( stadiumId, blockCode, rowNumber, member, command); - Map keywordMap = processAdminReviewDetails(review, command); + Map keywordMap = + reviewCreationProcessor.processAdminReviewDetails(review, command); Review savedReview = reviewRepository.save(review); reviewKeywordProcessor.updateBlockTopKeywords(savedReview); @@ -77,22 +78,4 @@ public void createAdmin( memberLevelProcessor.calculateAndUpdateMemberLevel(member); } - - private Map processReviewDetails(Review review, CreateReviewCommand command) { - Map keywordMap = - reviewKeywordProcessor.processKeywords(review, command.good(), command.bad()); - review.setKeywordMap(keywordMap); - reviewImageProcessor.processImages(review, command.images()); - return keywordMap; - } - - private Map processAdminReviewDetails( - Review review, CreateAdminReviewCommand command) { - Map keywordMap = - reviewKeywordProcessor.processKeywords(review, command.good(), command.bad()); - review.setKeywordMap(keywordMap); - List imageUrls = reviewImageProcessor.getImageUrl(command.images()); - reviewImageProcessor.processImages(review, imageUrls); - return keywordMap; - } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/UpdateReviewService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/UpdateReviewService.java index 44c58844..7948040b 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/UpdateReviewService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/UpdateReviewService.java @@ -1,23 +1,15 @@ package org.depromeet.spot.usecase.service.review; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; import org.depromeet.spot.common.exception.review.ReviewException.UnauthorizedReviewModificationException; -import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.review.Review; -import org.depromeet.spot.domain.review.image.ReviewImage; import org.depromeet.spot.domain.review.keyword.Keyword; -import org.depromeet.spot.domain.review.keyword.ReviewKeyword; -import org.depromeet.spot.domain.seat.Seat; import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase; -import org.depromeet.spot.usecase.port.out.review.BlockTopKeywordRepository; -import org.depromeet.spot.usecase.port.out.review.KeywordRepository; import org.depromeet.spot.usecase.port.out.review.ReviewRepository; -import org.depromeet.spot.usecase.port.out.seat.SeatRepository; +import org.depromeet.spot.usecase.service.review.processor.ReviewCreationProcessor; +import org.depromeet.spot.usecase.service.review.processor.ReviewDataProcessor; +import org.depromeet.spot.usecase.service.review.processor.ReviewKeywordProcessor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -33,33 +25,28 @@ public class UpdateReviewService implements UpdateReviewUsecase { private final ReviewRepository reviewRepository; - private final SeatRepository seatRepository; - private final KeywordRepository keywordRepository; - private final BlockTopKeywordRepository blockTopKeywordRepository; + private final ReviewDataProcessor reviewDataProcessor; + private final ReviewKeywordProcessor reviewKeywordProcessor; + private final ReviewCreationProcessor reviewCreationProcessor; public UpdateReviewResult updateReview( Long memberId, Long reviewId, UpdateReviewCommand command) { + // 1. review id로 조회 Review existingReview = reviewRepository.findById(reviewId); - if (!existingReview.getMember().getId().equals(memberId)) { throw new UnauthorizedReviewModificationException(); } - Member member = existingReview.getMember(); - Seat seat = seatRepository.findByIdWith(command.blockId(), command.seatNumber()); - - // 새로운 Review 객체 생성 - Review updatedReview = createUpdatedReview(reviewId, member, seat, command, existingReview); + // 2. 새로운 Review 객체 생성 + Review updatedReview = reviewCreationProcessor.updateReviewData(existingReview, command); // keyword와 image 처리 Map keywordMap = - processKeywords(updatedReview, command.good(), command.bad()); - processImages(updatedReview, command.images()); + reviewCreationProcessor.processReviewDetails(updatedReview, command); // 저장 및 blockTopKeyword 업데이트 Review savedReview = reviewRepository.save(updatedReview); - updateBlockTopKeywords(existingReview, savedReview); - + reviewKeywordProcessor.updateBlockTopKeywords(existingReview, savedReview); savedReview.setKeywordMap(keywordMap); return new UpdateReviewResult(savedReview); @@ -74,86 +61,4 @@ public void updateLikesCount(Review review) { public void updateScrapsCount(Review review) { reviewRepository.updateScrapsCount(review.getId(), review.getScrapsCount()); } - - private Review createUpdatedReview( - Long reviewId, - Member member, - Seat seat, - UpdateReviewCommand command, - Review savedReview) { - return Review.builder() - .id(reviewId) - .member(member) - .stadium(seat.getStadium()) - .section(seat.getSection()) - .block(seat.getBlock()) - .row(seat.getRow()) - .seat(seat) - .dateTime(command.dateTime()) - .content(command.content()) - .likesCount(savedReview.getLikesCount()) - .build(); - } - - private Map processKeywords( - Review review, List goodKeywords, List badKeywords) { - Map keywordMap = new HashMap<>(); - processKeywordList(review, goodKeywords, true, keywordMap); - processKeywordList(review, badKeywords, false, keywordMap); - - return keywordMap; - } - - private void processKeywordList( - Review review, - List keywordContents, - boolean isPositive, - Map keywordMap) { - for (String content : keywordContents) { - Keyword keyword = - keywordRepository - .findByContent(content) - .orElseGet( - () -> - keywordRepository.save( - Keyword.create(null, content, isPositive))); - - ReviewKeyword reviewKeyword = ReviewKeyword.create(null, keyword.getId()); - review.addKeyword(reviewKeyword); - keywordMap.put(keyword.getId(), keyword); - } - } - - private void processImages(Review review, List imageUrls) { - for (String url : imageUrls) { - ReviewImage image = ReviewImage.create(null, review, url); - review.addImage(image); - } - } - - private void updateBlockTopKeywords(Review oldReview, Review newReview) { - Set oldKeywordIds = - oldReview.getKeywords().stream() - .map(ReviewKeyword::getKeywordId) - .collect(Collectors.toSet()); - Set newKeywordIds = - newReview.getKeywords().stream() - .map(ReviewKeyword::getKeywordId) - .collect(Collectors.toSet()); - - List decrementIds = - oldKeywordIds.stream() - .filter(id -> !newKeywordIds.contains(id)) - .collect(Collectors.toList()); - - List incrementIds = - newKeywordIds.stream() - .filter(id -> !oldKeywordIds.contains(id)) - .collect(Collectors.toList()); - - if (!decrementIds.isEmpty() || !incrementIds.isEmpty()) { - blockTopKeywordRepository.batchUpdateCounts( - newReview.getBlock().getId(), incrementIds, decrementIds); - } - } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessor.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessor.java index 996cdbf9..ca52e4c5 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessor.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessor.java @@ -1,9 +1,13 @@ package org.depromeet.spot.usecase.service.review.processor; +import java.util.Map; + import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.keyword.Keyword; import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateAdminReviewCommand; import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateReviewCommand; +import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand; public interface ReviewCreationProcessor { Review createReview(Long blockId, Member member, CreateReviewCommand command); @@ -14,4 +18,12 @@ Review createAdminReview( int rowNumber, Member member, CreateAdminReviewCommand command); + + Map processReviewDetails(Review review, CreateReviewCommand command); + + Map processReviewDetails(Review review, UpdateReviewCommand command); + + Map processAdminReviewDetails(Review review, CreateAdminReviewCommand command); + + Review updateReviewData(Review existingReview, UpdateReviewCommand command); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessorImpl.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessorImpl.java index e1ddb0a9..1738985c 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessorImpl.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewCreationProcessorImpl.java @@ -1,15 +1,21 @@ package org.depromeet.spot.usecase.service.review.processor; +import java.util.List; +import java.util.Map; + import org.depromeet.spot.domain.block.Block; import org.depromeet.spot.domain.block.BlockRow; import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.review.Review; import org.depromeet.spot.domain.review.Review.ReviewType; +import org.depromeet.spot.domain.review.ReviewLocationInfo; +import org.depromeet.spot.domain.review.keyword.Keyword; import org.depromeet.spot.domain.seat.Seat; import org.depromeet.spot.domain.section.Section; import org.depromeet.spot.domain.stadium.Stadium; import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateAdminReviewCommand; import org.depromeet.spot.usecase.port.in.review.CreateReviewUsecase.CreateReviewCommand; +import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand; import org.springframework.stereotype.Component; import lombok.RequiredArgsConstructor; @@ -18,6 +24,8 @@ @RequiredArgsConstructor public class ReviewCreationProcessorImpl implements ReviewCreationProcessor { private final ReviewDataProcessor reviewDataProcessor; + private final ReviewKeywordProcessor reviewKeywordProcessor; + private final ReviewImageProcessor reviewImageProcessor; @Override public Review createReview(Long blockId, Member member, CreateReviewCommand command) { @@ -87,4 +95,56 @@ public Review createAdminReview( .reviewType(ReviewType.VIEW) .build(); } + + @Override + public Map processReviewDetails(Review review, CreateReviewCommand command) { + Map keywordMap = + reviewKeywordProcessor.processKeywords(review, command.good(), command.bad()); + review.setKeywordMap(keywordMap); + reviewImageProcessor.processImages(review, command.images()); + return keywordMap; + } + + @Override + public Map processReviewDetails(Review review, UpdateReviewCommand command) { + Map keywordMap = + reviewKeywordProcessor.processKeywords(review, command.good(), command.bad()); + review.setKeywordMap(keywordMap); + reviewImageProcessor.processImages(review, command.images()); + return keywordMap; + } + + @Override + public Map processAdminReviewDetails( + Review review, CreateAdminReviewCommand command) { + Map keywordMap = + reviewKeywordProcessor.processKeywords(review, command.good(), command.bad()); + review.setKeywordMap(keywordMap); + List imageUrls = reviewImageProcessor.getImageUrl(command.images()); + reviewImageProcessor.processImages(review, imageUrls); + return keywordMap; + } + + @Override + public Review updateReviewData(Review existingReview, UpdateReviewCommand command) { + Stadium stadium = + reviewDataProcessor.getStadiumIfChanged(existingReview, command.stadiumId()); + ReviewLocationInfo locationInfo = + reviewDataProcessor.getUpdatedLocationInfo(existingReview, command); + + return Review.builder() + .id(existingReview.getId()) + .member(existingReview.getMember()) + .stadium(stadium) + .section(locationInfo.section()) + .block(locationInfo.block()) + .row(locationInfo.row()) + .seat(locationInfo.seat()) + .dateTime(command.dateTime()) + .content(command.content()) + .likesCount(existingReview.getLikesCount()) + .scrapsCount(existingReview.getScrapsCount()) + .reviewType(command.reviewType()) + .build(); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessor.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessor.java index b233441b..a8752848 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessor.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessor.java @@ -2,11 +2,17 @@ import org.depromeet.spot.domain.block.Block; import org.depromeet.spot.domain.block.BlockRow; +import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.ReviewLocationInfo; import org.depromeet.spot.domain.seat.Seat; import org.depromeet.spot.domain.section.Section; import org.depromeet.spot.domain.stadium.Stadium; +import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand; public interface ReviewDataProcessor { + + Stadium getStadiumIfChanged(Review existingReview, Long newStadiumId); + Seat getSeat(Long blockId, Integer seatNumber); Block getBlock(Long blockId); @@ -17,5 +23,9 @@ public interface ReviewDataProcessor { BlockRow getBlockRow(Long stadiumId, String blockCode, Integer rowNumber); + BlockRow getBlockRow(Long blockId, Integer rowNumber); + Seat getSeatWithDetails(Long blockId, Integer seatNumber); + + ReviewLocationInfo getUpdatedLocationInfo(Review existingReview, UpdateReviewCommand command); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessorImpl.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessorImpl.java index 2661a66e..161b1a3a 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessorImpl.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewDataProcessorImpl.java @@ -2,9 +2,12 @@ import org.depromeet.spot.domain.block.Block; import org.depromeet.spot.domain.block.BlockRow; +import org.depromeet.spot.domain.review.Review; +import org.depromeet.spot.domain.review.ReviewLocationInfo; import org.depromeet.spot.domain.seat.Seat; import org.depromeet.spot.domain.section.Section; import org.depromeet.spot.domain.stadium.Stadium; +import org.depromeet.spot.usecase.port.in.review.UpdateReviewUsecase.UpdateReviewCommand; import org.depromeet.spot.usecase.port.out.block.BlockRepository; import org.depromeet.spot.usecase.port.out.block.BlockRowRepository; import org.depromeet.spot.usecase.port.out.seat.SeatRepository; @@ -28,7 +31,7 @@ public Seat getSeat(Long blockId, Integer seatNumber) { if (seatNumber == null) { return null; } - return seatRepository.findByIdWith(blockId, seatNumber); + return seatRepository.findByBlockIdAndSeatNumber(blockId, seatNumber); } @Override @@ -66,6 +69,17 @@ public BlockRow getBlockRow(Long stadiumId, String blockCode, Integer rowNumber) // stadiumId: " + stadiumId + ", blockCode: " + blockCode + ", rowNumber: " + rowNumber)); } + @Override + public BlockRow getBlockRow(Long blockId, Integer rowNumber) { + if (rowNumber == null) { + return null; + } + return blockRowRepository.findBy(blockId, rowNumber); + // TODO: 예외처리 어떻게 할 건지 논의 + // .orElseThrow(() -> new IllegalArgumentException("BlockRow not found with + // stadiumId: " + stadiumId + ", blockCode: " + blockCode + ", rowNumber: " + rowNumber)); + } + @Override public Seat getSeatWithDetails(Long blockId, Integer seatNumber) { Seat seat = getSeat(blockId, seatNumber); @@ -87,4 +101,63 @@ public Seat getSeatWithDetails(Long blockId, Integer seatNumber) { .seatNumber(seat.getSeatNumber()) .build(); } + + @Override + public ReviewLocationInfo getUpdatedLocationInfo( + Review existingReview, UpdateReviewCommand command) { + Block block = existingReview.getBlock(); + Section section = existingReview.getSection(); + BlockRow row = existingReview.getRow(); + Seat seat = existingReview.getSeat(); + + boolean blockChanged = !existingReview.getBlock().getId().equals(command.blockId()); + boolean rowChanged = isRowChanged(existingReview.getRow(), command.rowNumber()); + boolean seatChanged = isSeatChanged(existingReview.getSeat(), command.seatNumber()); + + if (command.seatNumber() != null) { + if (seatChanged || blockChanged) { + seat = getSeatWithDetails(command.blockId(), command.seatNumber()); + block = seat.getBlock(); + section = seat.getSection(); + row = seat.getRow(); + } + } else { + if (rowChanged || blockChanged) { + if (command.rowNumber() != null) { + row = getBlockRow(command.blockId(), command.rowNumber()); + block = row.getBlock(); + } else { + row = null; + if (blockChanged) { + block = getBlock(command.blockId()); + } + } + section = getSection(block.getSectionId()); + } + seat = null; + } + + return new ReviewLocationInfo(section, block, row, seat); + } + + private boolean isRowChanged(BlockRow existingRow, Integer newRowNumber) { + return (newRowNumber != null + && (existingRow == null || !existingRow.getNumber().equals(newRowNumber))) + || (newRowNumber == null && existingRow != null); + } + + private boolean isSeatChanged(Seat existingSeat, Integer newSeatNumber) { + return (newSeatNumber != null + && (existingSeat == null + || !existingSeat.getSeatNumber().equals(newSeatNumber))) + || (newSeatNumber == null && existingSeat != null); + } + + @Override + public Stadium getStadiumIfChanged(Review existingReview, Long newStadiumId) { + if (!existingReview.getStadium().getId().equals(newStadiumId)) { + return stadiumRepository.findById(newStadiumId); + } + return existingReview.getStadium(); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewKeywordProcessor.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewKeywordProcessor.java index 88827f9d..0fa7d084 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewKeywordProcessor.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/review/processor/ReviewKeywordProcessor.java @@ -3,6 +3,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.depromeet.spot.domain.review.Review; import org.depromeet.spot.domain.review.keyword.Keyword; @@ -55,4 +57,30 @@ public void updateBlockTopKeywords(Review review) { review.getBlock().getId(), reviewKeyword.getKeywordId()); } } + + public void updateBlockTopKeywords(Review oldReview, Review newReview) { + Set oldKeywordIds = + oldReview.getKeywords().stream() + .map(ReviewKeyword::getKeywordId) + .collect(Collectors.toSet()); + Set newKeywordIds = + newReview.getKeywords().stream() + .map(ReviewKeyword::getKeywordId) + .collect(Collectors.toSet()); + + List decrementIds = + oldKeywordIds.stream() + .filter(id -> !newKeywordIds.contains(id)) + .collect(Collectors.toList()); + + List incrementIds = + newKeywordIds.stream() + .filter(id -> !oldKeywordIds.contains(id)) + .collect(Collectors.toList()); + + if (!decrementIds.isEmpty() || !incrementIds.isEmpty()) { + blockTopKeywordRepository.batchUpdateCounts( + newReview.getBlock().getId(), incrementIds, decrementIds); + } + } } diff --git a/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeSeatRepository.java b/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeSeatRepository.java index 80a03bde..8d795e43 100644 --- a/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeSeatRepository.java +++ b/usecase/src/test/java/org/depromeet/spot/usecase/service/fake/FakeSeatRepository.java @@ -69,12 +69,12 @@ private Seat save(Seat seat) { } @Override - public Seat findByIdWith(Long seatId) { + public Seat findByBlockIdAndSeatNumber(Long seatId) { return getById(seatId).orElseThrow(SeatNotFoundException::new); } @Override - public Seat findByIdWith(Long blockId, Integer seatNumber) { + public Seat findByBlockIdAndSeatNumber(Long blockId, Integer seatNumber) { return getByBlockAndSeatNum(seatNumber, blockId).orElseThrow(SeatNotFoundException::new); }