diff --git a/backend/src/main/java/com/funeat/product/application/ProductService.java b/backend/src/main/java/com/funeat/product/application/ProductService.java index 921d07d7a..b094d49e8 100644 --- a/backend/src/main/java/com/funeat/product/application/ProductService.java +++ b/backend/src/main/java/com/funeat/product/application/ProductService.java @@ -32,6 +32,7 @@ import com.funeat.review.persistence.ReviewRepository; import com.funeat.review.persistence.ReviewTagRepository; import com.funeat.tag.domain.Tag; +import java.time.LocalDateTime; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -119,7 +120,9 @@ public ProductResponse findProductDetail(final Long productId) { } public RankingProductsResponse getTop3Products() { - final List productsAndReviewCounts = productRepository.findAllByAverageRatingGreaterThan3(); + final LocalDateTime endDateTime = LocalDateTime.now(); + final LocalDateTime startDateTime = endDateTime.minusWeeks(2L); + final List productsAndReviewCounts = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime); final Comparator rankingScoreComparator = Comparator.comparing( (ProductReviewCountDto it) -> it.getProduct().calculateRankingScore(it.getReviewCount()) ).reversed(); diff --git a/backend/src/main/java/com/funeat/product/persistence/ProductRepository.java b/backend/src/main/java/com/funeat/product/persistence/ProductRepository.java index 9b4036361..27208f254 100644 --- a/backend/src/main/java/com/funeat/product/persistence/ProductRepository.java +++ b/backend/src/main/java/com/funeat/product/persistence/ProductRepository.java @@ -3,6 +3,7 @@ import com.funeat.common.repository.BaseRepository; import com.funeat.product.domain.Product; import com.funeat.product.dto.ProductReviewCountDto; +import java.time.LocalDateTime; import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -15,8 +16,10 @@ public interface ProductRepository extends BaseRepository { + "FROM Product p " + "LEFT JOIN Review r ON r.product.id = p.id " + "WHERE p.averageRating > 3.0 " + + "AND r.createdAt BETWEEN :startDateTime AND :endDateTime " + "GROUP BY p.id") - List findAllByAverageRatingGreaterThan3(); + List findAllByAverageRatingGreaterThan3(final LocalDateTime startDateTime, + final LocalDateTime endDateTime); @Query("SELECT p FROM Product p " + "WHERE p.name LIKE CONCAT('%', :name, '%') " diff --git a/backend/src/test/java/com/funeat/product/application/ProductServiceTest.java b/backend/src/test/java/com/funeat/product/application/ProductServiceTest.java index 5aa812dc6..9f5b88c5b 100644 --- a/backend/src/test/java/com/funeat/product/application/ProductServiceTest.java +++ b/backend/src/test/java/com/funeat/product/application/ProductServiceTest.java @@ -109,16 +109,16 @@ class 상품_개수에_대한_테스트 { final var review1_4 = 리뷰_이미지test3_평점3점_재구매O_생성(member1, product1, 0L); final var review2_1 = 리뷰_이미지test4_평점4점_재구매O_생성(member1, product2, 0L); final var review2_2 = 리뷰_이미지test4_평점4점_재구매O_생성(member1, product2, 0L); - final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L); - final var review4_1 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product2, 0L); - final var review4_2 = 리뷰_이미지test3_평점3점_재구매X_생성(member1, product2, 0L); - final var review4_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L); + final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product3, 0L); + final var review4_1 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product4, 0L); + final var review4_2 = 리뷰_이미지test3_평점3점_재구매X_생성(member1, product4, 0L); + final var review4_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product4, 0L); 복수_리뷰_저장(review1_1, review1_2, review1_3, review1_4, review2_1, review2_2, review3_1, review4_1, review4_2, review4_3); - final var rankingProductDto1 = RankingProductDto.toDto(product2); - final var rankingProductDto2 = RankingProductDto.toDto(product3); - final var rankingProductDto3 = RankingProductDto.toDto(product4); + final var rankingProductDto1 = RankingProductDto.toDto(product3); + final var rankingProductDto2 = RankingProductDto.toDto(product4); + final var rankingProductDto3 = RankingProductDto.toDto(product2); final var rankingProductDtos = List.of(rankingProductDto1, rankingProductDto2, rankingProductDto3); final var expected = RankingProductsResponse.toResponse(rankingProductDtos); diff --git a/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java b/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java index e1eff6623..107585475 100644 --- a/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java +++ b/backend/src/test/java/com/funeat/product/persistence/ProductRepositoryTest.java @@ -4,40 +4,23 @@ import static com.funeat.fixture.MemberFixture.멤버_멤버1_생성; import static com.funeat.fixture.MemberFixture.멤버_멤버2_생성; import static com.funeat.fixture.MemberFixture.멤버_멤버3_생성; -import static com.funeat.fixture.PageFixture.가격_내림차순; -import static com.funeat.fixture.PageFixture.가격_오름차순; -import static com.funeat.fixture.PageFixture.리뷰수_내림차순; import static com.funeat.fixture.PageFixture.페이지요청_기본_생성; -import static com.funeat.fixture.PageFixture.페이지요청_생성; -import static com.funeat.fixture.PageFixture.평균_평점_내림차순; -import static com.funeat.fixture.PageFixture.평균_평점_오름차순; import static com.funeat.fixture.ProductFixture.상품_망고빙수_가격5000원_평점4점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_리뷰3개_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점1점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점2점_생성; import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점3점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점4점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점5점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_리뷰1개_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_평점1점_생성; import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_평점4점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_리뷰5개_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_평점1점_생성; import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_평점5점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격4000원_평점1점_생성; import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격4000원_평점2점_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격5000원_리뷰0개_생성; -import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격5000원_평점1점_생성; import static com.funeat.fixture.ProductFixture.상품_애플망고_가격3000원_평점5점_생성; import static com.funeat.fixture.ReviewFixture.리뷰_이미지test1_평점1점_재구매X_생성; import static com.funeat.fixture.ReviewFixture.리뷰_이미지test3_평점3점_재구매O_생성; -import static com.funeat.fixture.ReviewFixture.리뷰_이미지test4_평점4점_재구매X_생성; import static com.funeat.fixture.ReviewFixture.리뷰_이미지test5_평점5점_재구매O_생성; +import static com.funeat.fixture.ReviewFixture.리뷰_이미지test5_평점5점_재구매X_생성; import static org.assertj.core.api.Assertions.assertThat; import com.funeat.common.RepositoryTest; -import com.funeat.product.dto.ProductInCategoryDto; import com.funeat.product.dto.ProductReviewCountDto; +import java.time.LocalDateTime; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -65,12 +48,12 @@ class findAllByAverageRatingGreaterThan3_성공_테스트 { final var member3 = 멤버_멤버3_생성(); 복수_멤버_저장(member1, member2, member3); - final var review1_1 = 리뷰_이미지test1_평점1점_재구매X_생성(member1, product1, 0L); - final var review1_2 = 리뷰_이미지test5_평점5점_재구매O_생성(member2, product1, 0L); - final var review2_1 = 리뷰_이미지test3_평점3점_재구매O_생성(member3, product2, 0L); - final var review2_2 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product2, 0L); - final var review2_3 = 리뷰_이미지test5_평점5점_재구매O_생성(member2, product2, 0L); - final var review3_1 = 리뷰_이미지test5_평점5점_재구매O_생성(member1, product3, 0L); + final var review1_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product1, 0L, LocalDateTime.now().minusDays(2L)); + final var review1_2 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product1, 0L, LocalDateTime.now().minusDays(3L)); + final var review2_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member3, product2, 0L, LocalDateTime.now().minusDays(10L)); + final var review2_2 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L, LocalDateTime.now().minusDays(1L)); + final var review2_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product2, 0L, LocalDateTime.now().minusDays(9L)); + final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product3, 0L, LocalDateTime.now().minusDays(8L)); 복수_리뷰_저장(review1_1, review1_2, review2_1, review2_2, review2_3, review3_1); final var productReviewCountDto1 = new ProductReviewCountDto(product2, 3L); @@ -78,7 +61,39 @@ class findAllByAverageRatingGreaterThan3_성공_테스트 { final var expected = List.of(productReviewCountDto1, productReviewCountDto2); // when - final var actual = productRepository.findAllByAverageRatingGreaterThan3(); + final var startDateTime = LocalDateTime.now().minusWeeks(2L); + final var endDateTime = LocalDateTime.now(); + final var actual = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime); + + // then + assertThat(actual).usingRecursiveComparison() + .isEqualTo(expected); + } + + @Test + void 기간_안에_리뷰가_존재하는_상품이_없으면_빈_리스트를_반환한다() { + // given + final var category = 카테고리_간편식사_생성(); + 단일_카테고리_저장(category); + + final var product1 = 상품_삼각김밥_가격1000원_평점3점_생성(category); + final var product2 = 상품_삼각김밥_가격2000원_평점4점_생성(category); + 복수_상품_저장(product1, product2); + + final var member1 = 멤버_멤버1_생성(); + final var member2 = 멤버_멤버2_생성(); + 복수_멤버_저장(member1, member2); + + final var review1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product1, 0L, LocalDateTime.now().minusDays(15L)); + final var review2 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product2, 0L, LocalDateTime.now().minusWeeks(3L)); + 복수_리뷰_저장(review1, review2); + + final var expected = Collections.emptyList(); + + // when + final var startDateTime = LocalDateTime.now().minusWeeks(2L); + final var endDateTime = LocalDateTime.now(); + final var actual = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime); // then assertThat(actual).usingRecursiveComparison()