Skip to content

Commit

Permalink
Merge pull request #96 from KNU-HAEDAL/issue/#58
Browse files Browse the repository at this point in the history
[Feat]: 리뷰 조회 DB 쿼리로 변경 (#58)
  • Loading branch information
bayy1216 authored Sep 19, 2024
2 parents 9afc209 + 15f66e2 commit ba4e519
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
@Builder
@Table(
indexes = {
@Index(name = "idx_challenge_review_challenge_group_id", columnList = "challenge_group_id"),
@Index(
name = "idx_challenge_review_challenge_group_id_rating",
columnList = "challenge_group_id, rating"
),
}
)
public class ChallengeReview extends BaseTimeEntity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public static Score of(List<ChallengeReview> challengeReviews) {
.ratingCount(ratingCount)
.build();
}

public static Score from(Map<Integer, Integer> ratingCount) {
var averageRating = ratingCount.entrySet().stream()
.mapToDouble(entry -> entry.getKey() * entry.getValue())
.sum() / ratingCount.values().stream().mapToInt(Integer::intValue).sum();
return Score.builder()
.averageRating((float) averageRating)
.ratingCount(ratingCount)
.build();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ Page<ChallengeReview> getChallengeReviewPageByChallengeGroupId(Long challengeGro

List<ChallengeReview> findByChallengeGroupId(Long challengeGroupId);

ChallengeReviewModel.Score getScoreModelByChallengeGroupId(Long challengeGroupId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ public Page<ChallengeReviewModel.ChallengeReviewWithUserInfo> getChallengeReview
@Transactional(readOnly = true)
public ChallengeReviewModel.Score getChallengeGroupReviewScore(
Long challengeGroupId) {
List<ChallengeReview> challengeReviews = challengeReviewReader.findByChallengeGroupId(
challengeGroupId);
//TODO 모든 리뷰를 가져와서 계산 -> 성능 이슈 발생 가능
return ChallengeReviewModel.Score.of(challengeReviews);
return challengeReviewReader.getScoreModelByChallengeGroupId(challengeGroupId);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.haedal.zzansuni.challengereview.infrastructure;

import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.haedal.zzansuni.challengereview.domain.ChallengeReview;
import org.haedal.zzansuni.challengereview.domain.ChallengeReviewModel;
import org.haedal.zzansuni.challengereview.domain.ChallengeReviewReader;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
Expand Down Expand Up @@ -56,7 +58,7 @@ public Map<Long, Boolean> getReviewWrittenMapByUserChallengeId(List<Long> userCh
*/
@Override
public Page<ChallengeReview> getChallengeReviewPageByChallengeGroupId(Long challengeGroupId,
Pageable pageable) {
Pageable pageable) {
Long count = queryFactory
.select(challengeReview.count())
.from(challengeReview)
Expand Down Expand Up @@ -114,4 +116,26 @@ public List<ChallengeReview> findByChallengeGroupId(Long challengeGroupId) {
.where(challengeReview.challengeGroupId.eq(challengeGroupId))
.fetch();
}

@Override
public ChallengeReviewModel.Score getScoreModelByChallengeGroupId(Long challengeGroupId) {
List<Tuple> fetch = queryFactory
.select(challengeReview.rating, challengeReview.count())
.from(challengeReview)
.where(challengeReview.challengeGroupId.eq(challengeGroupId))
.groupBy(challengeReview.rating)
.fetch();
Map<Integer, Integer> ratingCount = fetch
.stream()
.collect(
HashMap::new,
(m, v) ->
m.put(v.get(challengeReview.rating), v.get(challengeReview.count()).intValue()),
HashMap::putAll
);
for(int i = 1; i <= 5; i++) {
ratingCount.putIfAbsent(i, 0);
}
return ChallengeReviewModel.Score.from(ratingCount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- 평점 1~5이므로 `TINYINT`로 변경
ALTER TABLE challenge_review MODIFY COLUMN rating TINYINT NOT NULL;

-- 기존 인덱스 삭제
DROP INDEX idx_challenge_review_challenge_group_id ON challenge_review;

-- 새로운 복합 인덱스 생성
CREATE INDEX idx_challenge_review_challenge_group_id_rating ON challenge_review (challenge_group_id, rating);
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package org.haedal.zzansuni.challengereview.infrastructure;

import org.haedal.zzansuni.challengegroup.domain.Challenge;
import org.haedal.zzansuni.challengegroup.domain.ChallengeCategory;
import org.haedal.zzansuni.challengegroup.domain.ChallengeGroup;
import org.haedal.zzansuni.challengegroup.infrastructure.ChallengeGroupRepository;
import org.haedal.zzansuni.challengegroup.infrastructure.ChallengeRepository;
import org.haedal.zzansuni.challengereview.domain.ChallengeReview;
import org.haedal.zzansuni.challengereview.domain.ChallengeReviewModel;
import org.haedal.zzansuni.global.security.Role;
import org.haedal.zzansuni.user.domain.User;
import org.haedal.zzansuni.user.infrastructure.UserRepository;
import org.haedal.zzansuni.userchallenge.domain.ChallengeStatus;
import org.haedal.zzansuni.userchallenge.domain.UserChallenge;
import org.haedal.zzansuni.userchallenge.infrastructure.UserChallengeRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class ChallengeReviewReaderImplTest {
@Autowired private ChallengeGroupRepository challengeGroupRepository;
@Autowired private UserRepository userRepository;
@Autowired private ChallengeRepository challengeRepository;
@Autowired private UserChallengeRepository userChallengeRepository;
@Autowired private ChallengeReviewRepository challengeReviewRepository;
@Autowired private ChallengeReviewReaderImpl challengeReviewReader;

@Test
@Transactional
@DisplayName("리뷰 평점 count 쿼리가 정상적으로 동작한다.")
void getScoreModelByChallengeGroupId() {
// given
ChallengeGroup challengeGroup = createChallengeGroup();
Challenge challenge = Challenge.builder()
.challengeGroup(challengeGroup)
.requiredCount(2)
.onceExp(100)
.successExp(100)
.difficulty(2)
.activePeriod(10)
.build();
User user = createUser();
UserChallenge userChallenge = createUserChallenge(challenge, user);

challengeGroupRepository.save(challengeGroup);
challengeRepository.save(challenge);
userRepository.save(user);
userChallengeRepository.save(userChallenge);

List<ChallengeReview> reviews = IntStream.range(0, 11)
.mapToObj(i -> ChallengeReview.builder()
.challengeGroupId(challenge.getChallengeGroupId())
.userChallenge(userChallenge)
.content("content")
.rating(i % 4 + 1)
.build())
.toList();
// -> 1:3 / 2:3 / 3:3 / 4:2 / 5:0
challengeReviewRepository.saveAll(reviews);

// when
ChallengeReviewModel.Score score = challengeReviewReader.getScoreModelByChallengeGroupId(1L);


// then
assertAll(
() -> assertEquals(3, score.ratingCount().get(1)),
() -> assertEquals(3, score.ratingCount().get(2)),
() -> assertEquals(3, score.ratingCount().get(3)),
() -> assertEquals(2, score.ratingCount().get(4)),
() -> assertEquals(0, score.ratingCount().get(5))
);
}

private User createUser() {
return User.builder()
.nickname("nickname")
.email(null)
.password(null)
.role(Role.USER)
.provider(null)
.authToken(null)
.exp(0)
.profileImageUrl(null)
.build();
}

private ChallengeGroup createChallengeGroup() {
return ChallengeGroup.builder()
.title("title")
.category(ChallengeCategory.VOLUNTEER)
.content("content")
.guide("guide")
.cumulativeCount(0)
.joinStartDate(LocalDate.of(2023, 8, 1))
.joinEndDate(LocalDate.of(2023, 8, 5))
.build();
}

private UserChallenge createUserChallenge(Challenge challenge, User user) {

return UserChallenge.builder()
.challenge(challenge)
.status(ChallengeStatus.PROCEEDING)
.activeStartDate(LocalDate.of(2023, 8, 1))
.activeEndDate(LocalDate.of(2023, 8, 5))
.user(user)
.challengeVerifications(new ArrayList<>())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,4 @@ void getChallengeReviews() {
verify(challengeReviewReader).getChallengeReviewPage(pageable);
}

@Test
void getChallengeGroupReviewScore() {
Long challengeGroupId = 1L;
List<ChallengeReview> challengeReviews = Collections.singletonList(challengeReview);
when(challengeReviewReader.findByChallengeGroupId(challengeGroupId)).thenReturn(
challengeReviews);

ChallengeReviewModel.Score result = challengeReviewService.getChallengeGroupReviewScore(
challengeGroupId);

assertNotNull(result);
verify(challengeReviewReader).findByChallengeGroupId(challengeGroupId);
}
}

0 comments on commit ba4e519

Please sign in to comment.