diff --git a/src/main/java/com/jisungin/api/talkroom/TalkRoomController.java b/src/main/java/com/jisungin/api/talkroom/TalkRoomController.java index 02a3aea..dd47ba0 100644 --- a/src/main/java/com/jisungin/api/talkroom/TalkRoomController.java +++ b/src/main/java/com/jisungin/api/talkroom/TalkRoomController.java @@ -6,7 +6,7 @@ import com.jisungin.api.talkroom.request.TalkRoomCreateRequest; import com.jisungin.api.talkroom.request.TalkRoomEditRequest; import com.jisungin.api.talkroom.request.TalkRoomSearchRequest; -import com.jisungin.application.response.PageResponse; +import com.jisungin.application.PageResponse; import com.jisungin.application.talkroom.TalkRoomService; import com.jisungin.application.talkroom.response.TalkRoomFindAllResponse; import com.jisungin.application.talkroom.response.TalkRoomFindOneResponse; @@ -31,7 +31,6 @@ public class TalkRoomController { private final TalkRoomService talkRoomService; - // TODO. 회원 도메인이 개발되면 변경 예정 @PostMapping("/talk-rooms") public ApiResponse createTalkRoom(@Valid @RequestBody TalkRoomCreateRequest request, @Auth AuthContext authContext) { diff --git a/src/main/java/com/jisungin/api/talkroom/request/TalkRoomSearchRequest.java b/src/main/java/com/jisungin/api/talkroom/request/TalkRoomSearchRequest.java index 7b2590f..52b4fc2 100644 --- a/src/main/java/com/jisungin/api/talkroom/request/TalkRoomSearchRequest.java +++ b/src/main/java/com/jisungin/api/talkroom/request/TalkRoomSearchRequest.java @@ -1,5 +1,6 @@ package com.jisungin.api.talkroom.request; +import com.jisungin.application.OrderType; import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; import lombok.Builder; import lombok.Getter; @@ -17,18 +18,22 @@ public class TalkRoomSearchRequest { private String order; + private String search; + @Builder - private TalkRoomSearchRequest(Integer page, Integer size, String order) { + private TalkRoomSearchRequest(Integer page, Integer size, String order, String search) { this.page = page != null ? page : 1; this.size = size != null ? size : 1; this.order = order != null ? order : "recent"; + this.search = search; } public TalkRoomSearchServiceRequest toService() { return TalkRoomSearchServiceRequest.builder() .page(page) .size(size) - .order(order) + .search(search) + .orderType(OrderType.convertToOrderType(order)) .build(); } diff --git a/src/main/java/com/jisungin/api/talkroomlike/TalkRoomLikeController.java b/src/main/java/com/jisungin/api/talkroomlike/TalkRoomLikeController.java new file mode 100644 index 0000000..ad81678 --- /dev/null +++ b/src/main/java/com/jisungin/api/talkroomlike/TalkRoomLikeController.java @@ -0,0 +1,44 @@ +package com.jisungin.api.talkroomlike; + +import com.jisungin.api.ApiResponse; +import com.jisungin.api.oauth.Auth; +import com.jisungin.api.oauth.AuthContext; +import com.jisungin.application.talkroomlike.TalkRoomLikeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/v1") +@RestController +public class TalkRoomLikeController { + + private final TalkRoomLikeService talkRoomLikeService; + + @PostMapping("/talk-rooms/{talkRoomId}/likes") + public ApiResponse likeTalkRoom(@PathVariable Long talkRoomId, + @Auth AuthContext authContext) { + talkRoomLikeService.likeTalkRoom(talkRoomId, authContext.getUserId()); + + return ApiResponse.builder() + .message("좋아요 성공") + .status(HttpStatus.OK) + .build(); + } + + @DeleteMapping("/talk-rooms/{talkRoomId}/likes") + public ApiResponse nuLikeTalkRoom(@PathVariable Long talkRoomId, + @Auth AuthContext authContext) { + talkRoomLikeService.unLikeTalkRoom(talkRoomId, authContext.getUserId()); + + return ApiResponse.builder() + .message("좋아요 취소") + .status(HttpStatus.OK) + .build(); + } + +} diff --git a/src/main/java/com/jisungin/application/OrderType.java b/src/main/java/com/jisungin/application/OrderType.java new file mode 100644 index 0000000..013dca5 --- /dev/null +++ b/src/main/java/com/jisungin/application/OrderType.java @@ -0,0 +1,21 @@ +package com.jisungin.application; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum OrderType { + + RECENT("최신순"), + RECOMMEND("좋아요순"); + + private final String text; + + public static OrderType convertToOrderType(String order) { + return switch (order) { + case "recent" -> RECENT; + case "recommend" -> RECOMMEND; + default -> RECENT; + }; + } + +} diff --git a/src/main/java/com/jisungin/application/response/PageResponse.java b/src/main/java/com/jisungin/application/PageResponse.java similarity index 92% rename from src/main/java/com/jisungin/application/response/PageResponse.java rename to src/main/java/com/jisungin/application/PageResponse.java index b51b5cc..f46e52b 100644 --- a/src/main/java/com/jisungin/application/response/PageResponse.java +++ b/src/main/java/com/jisungin/application/PageResponse.java @@ -1,4 +1,4 @@ -package com.jisungin.application.response; +package com.jisungin.application; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/jisungin/application/talkroom/TalkRoomService.java b/src/main/java/com/jisungin/application/talkroom/TalkRoomService.java index 1d2780c..7e8a7d9 100644 --- a/src/main/java/com/jisungin/application/talkroom/TalkRoomService.java +++ b/src/main/java/com/jisungin/application/talkroom/TalkRoomService.java @@ -1,6 +1,6 @@ package com.jisungin.application.talkroom; -import com.jisungin.application.response.PageResponse; +import com.jisungin.application.PageResponse; import com.jisungin.application.talkroom.request.TalkRoomCreateServiceRequest; import com.jisungin.application.talkroom.request.TalkRoomEditServiceRequest; import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; diff --git a/src/main/java/com/jisungin/application/talkroom/request/TalkRoomSearchServiceRequest.java b/src/main/java/com/jisungin/application/talkroom/request/TalkRoomSearchServiceRequest.java index 821e2dd..02c9fc4 100644 --- a/src/main/java/com/jisungin/application/talkroom/request/TalkRoomSearchServiceRequest.java +++ b/src/main/java/com/jisungin/application/talkroom/request/TalkRoomSearchServiceRequest.java @@ -3,6 +3,7 @@ import static java.lang.Math.max; import static java.lang.Math.min; +import com.jisungin.application.OrderType; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -17,13 +18,16 @@ public class TalkRoomSearchServiceRequest { private Integer size; - private String order; + private OrderType orderType; + + private String search; @Builder - private TalkRoomSearchServiceRequest(Integer page, Integer size, String order) { + private TalkRoomSearchServiceRequest(Integer page, Integer size, OrderType orderType, String search) { this.page = page; this.size = size; - this.order = order; + this.orderType = orderType; + this.search = search; } public long getOffset() { diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindAllResponse.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindAllResponse.java index 3601052..8c928db 100644 --- a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindAllResponse.java +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindAllResponse.java @@ -17,22 +17,29 @@ public class TalkRoomFindAllResponse { private String content; private String bookName; private String bookImage; - private List readingStatuses = new ArrayList<>(); + private List readingStatuses = new ArrayList<>(); + private List userIds = new ArrayList<>(); + private Long likeCount; @Builder @QueryProjection public TalkRoomFindAllResponse(Long talkRoomId, String userName, String title, String content, String bookName, - String bookImage) { + String bookImage, Long likeCount) { this.talkRoomId = talkRoomId; this.userName = userName; this.title = title; this.content = content; this.bookName = bookName; this.bookImage = bookImage; + this.likeCount = likeCount; } - public void addTalkRoomStatus(List readingStatuses) { + public void addTalkRoomStatus(List readingStatuses) { this.readingStatuses = readingStatuses; } + public void addTalkRoomLikeUserIds(List userIds) { + this.userIds = userIds; + } + } diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java index a9c3a55..315860c 100644 --- a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java @@ -17,27 +17,40 @@ public class TalkRoomFindOneResponse { private String content; private String bookName; private String bookImage; - private List readingStatuses = new ArrayList<>(); - private List comments = new ArrayList<>(); + private List readingStatuses = new ArrayList<>(); + private List comments = new ArrayList<>(); + private Long likeCount; + private Long commentCount; + private List userIds = new ArrayList<>(); @Builder @QueryProjection public TalkRoomFindOneResponse(Long talkRoomId, String userName, String title, String content, String bookName, - String bookImage) { + String bookImage, Long likeCount, Long commentCount) { this.talkRoomId = talkRoomId; this.userName = userName; this.title = title; this.content = content; this.bookName = bookName; this.bookImage = bookImage; + this.likeCount = likeCount; + this.commentCount = commentCount; } - public void addTalkRoomStatus(List readingStatuses) { + public void addTalkRoomStatus(List readingStatuses) { this.readingStatuses = readingStatuses; } - public void addTalkRoomComments(List comments) { + public void addTalkRoomComments(List comments) { this.comments = comments; } + public void addCommentCount(Long commentCount) { + this.commentCount = commentCount; + } + + public void addUserIds(List userIds) { + this.userIds = userIds; + } + } diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomLikeUserIdResponse.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomLikeUserIdResponse.java new file mode 100644 index 0000000..8748b91 --- /dev/null +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomLikeUserIdResponse.java @@ -0,0 +1,22 @@ +package com.jisungin.application.talkroom.response; + +import com.querydsl.core.annotations.QueryProjection; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class TalkRoomLikeUserIdResponse { + + private Long talkRoomId; + private Long userId; + + @Builder + @QueryProjection + public TalkRoomLikeUserIdResponse(Long talkRoomId, Long userId) { + this.talkRoomId = talkRoomId; + this.userId = userId; + } + +} diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryComments.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryCommentsResponse.java similarity index 76% rename from src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryComments.java rename to src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryCommentsResponse.java index d9d5489..34e549e 100644 --- a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryComments.java +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryCommentsResponse.java @@ -7,7 +7,7 @@ @Getter @NoArgsConstructor -public class TalkRoomQueryComments { +public class TalkRoomQueryCommentsResponse { private Long commentId; private String userName; @@ -15,7 +15,7 @@ public class TalkRoomQueryComments { @Builder @QueryProjection - public TalkRoomQueryComments(Long commentId, String userName, String content) { + public TalkRoomQueryCommentsResponse(Long commentId, String userName, String content) { this.commentId = commentId; this.userName = userName; this.content = content; diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatus.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatusResponse.java similarity index 75% rename from src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatus.java rename to src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatusResponse.java index 8399f40..7a4a393 100644 --- a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatus.java +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomQueryReadingStatusResponse.java @@ -8,7 +8,7 @@ @Getter @NoArgsConstructor -public class TalkRoomQueryReadingStatus { +public class TalkRoomQueryReadingStatusResponse { private Long talkRoomId; @@ -16,7 +16,7 @@ public class TalkRoomQueryReadingStatus { @Builder @QueryProjection - public TalkRoomQueryReadingStatus(Long talkRoomId, ReadingStatus readingStatus) { + public TalkRoomQueryReadingStatusResponse(Long talkRoomId, ReadingStatus readingStatus) { this.talkRoomId = talkRoomId; this.readingStatus = readingStatus; } diff --git a/src/main/java/com/jisungin/application/talkroomlike/TalkRoomLikeService.java b/src/main/java/com/jisungin/application/talkroomlike/TalkRoomLikeService.java new file mode 100644 index 0000000..2a9bc29 --- /dev/null +++ b/src/main/java/com/jisungin/application/talkroomlike/TalkRoomLikeService.java @@ -0,0 +1,55 @@ +package com.jisungin.application.talkroomlike; + +import com.jisungin.domain.talkroom.TalkRoom; +import com.jisungin.domain.talkroom.repository.TalkRoomRepository; +import com.jisungin.domain.talkroomlike.TalkRoomLike; +import com.jisungin.domain.talkroomlike.repository.TalkRoomLikeRepository; +import com.jisungin.domain.user.User; +import com.jisungin.domain.user.repository.UserRepository; +import com.jisungin.exception.BusinessException; +import com.jisungin.exception.ErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Transactional(readOnly = true) +@RequiredArgsConstructor +@Service +public class TalkRoomLikeService { + + private final TalkRoomLikeRepository talkRoomLikeRepository; + private final TalkRoomRepository talkRoomRepository; + private final UserRepository userRepository; + + @Transactional + public void likeTalkRoom(Long talkRoomId, Long userId) { + TalkRoom talkRoom = talkRoomRepository.findById(talkRoomId) + .orElseThrow(() -> new BusinessException(ErrorCode.TALK_ROOM_NOT_FOUND)); + + User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + + if (talkRoomLikeRepository.findByTalkRoomIdAndUserId(talkRoomId, userId).isPresent()) { + throw new BusinessException(ErrorCode.LIKE_EXIST); + } + + TalkRoomLike talkRoomLike = TalkRoomLike.likeTalkRoom(user, talkRoom); + + talkRoomLikeRepository.save(talkRoomLike); + } + + + @Transactional + public void unLikeTalkRoom(Long talkRoomId, Long userId) { + TalkRoom talkRoom = talkRoomRepository.findById(talkRoomId) + .orElseThrow(() -> new BusinessException(ErrorCode.TALK_ROOM_NOT_FOUND)); + + User user = userRepository.findById(userId) + .orElseThrow(() -> new BusinessException(ErrorCode.TALK_ROOM_NOT_FOUND)); + + TalkRoomLike talkRoomLike = talkRoomLikeRepository.findByTalkRoomIdAndUserId(talkRoom.getId(), user.getId()) + .orElseThrow(() -> new BusinessException(ErrorCode.TALK_ROOM_LIKE_NOT_FOUND)); + + talkRoomLikeRepository.delete(talkRoomLike); + } + +} diff --git a/src/main/java/com/jisungin/domain/talkroom/repository/OrderByNull.java b/src/main/java/com/jisungin/domain/talkroom/repository/OrderByNull.java new file mode 100644 index 0000000..0b35d80 --- /dev/null +++ b/src/main/java/com/jisungin/domain/talkroom/repository/OrderByNull.java @@ -0,0 +1,14 @@ +package com.jisungin.domain.talkroom.repository; + +import com.querydsl.core.types.NullExpression; +import com.querydsl.core.types.Order; +import com.querydsl.core.types.OrderSpecifier; + +public class OrderByNull extends OrderSpecifier { + public static final OrderByNull DEFAULT = new OrderByNull(); + + private OrderByNull() { + super(Order.ASC, NullExpression.DEFAULT, NullHandling.Default); + } + +} \ No newline at end of file diff --git a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryCustom.java b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryCustom.java index 86dbcf9..f11163e 100644 --- a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryCustom.java +++ b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryCustom.java @@ -1,6 +1,6 @@ package com.jisungin.domain.talkroom.repository; -import com.jisungin.application.response.PageResponse; +import com.jisungin.application.PageResponse; import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; import com.jisungin.application.talkroom.response.TalkRoomFindAllResponse; import com.jisungin.application.talkroom.response.TalkRoomFindOneResponse; diff --git a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java index 0175155..d279af2 100644 --- a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java +++ b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java @@ -1,22 +1,29 @@ package com.jisungin.domain.talkroom.repository; +import static com.jisungin.application.OrderType.RECENT; +import static com.jisungin.application.OrderType.RECOMMEND; import static com.jisungin.domain.book.QBook.book; import static com.jisungin.domain.comment.QComment.comment; import static com.jisungin.domain.talkroom.QTalkRoom.talkRoom; import static com.jisungin.domain.talkroom.QTalkRoomRole.talkRoomRole; +import static com.jisungin.domain.talkroomlike.QTalkRoomLike.talkRoomLike; import static com.jisungin.domain.user.QUser.user; -import com.jisungin.application.response.PageResponse; +import com.jisungin.application.OrderType; +import com.jisungin.application.PageResponse; import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; import com.jisungin.application.talkroom.response.QTalkRoomFindAllResponse; import com.jisungin.application.talkroom.response.QTalkRoomFindOneResponse; -import com.jisungin.application.talkroom.response.QTalkRoomQueryComments; -import com.jisungin.application.talkroom.response.QTalkRoomQueryReadingStatus; +import com.jisungin.application.talkroom.response.QTalkRoomLikeUserIdResponse; +import com.jisungin.application.talkroom.response.QTalkRoomQueryCommentsResponse; +import com.jisungin.application.talkroom.response.QTalkRoomQueryReadingStatusResponse; import com.jisungin.application.talkroom.response.TalkRoomFindAllResponse; import com.jisungin.application.talkroom.response.TalkRoomFindOneResponse; -import com.jisungin.application.talkroom.response.TalkRoomQueryComments; -import com.jisungin.application.talkroom.response.TalkRoomQueryReadingStatus; +import com.jisungin.application.talkroom.response.TalkRoomLikeUserIdResponse; +import com.jisungin.application.talkroom.response.TalkRoomQueryCommentsResponse; +import com.jisungin.application.talkroom.response.TalkRoomQueryReadingStatusResponse; import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import java.util.Map; @@ -28,18 +35,26 @@ public class TalkRoomRepositoryImpl implements TalkRoomRepositoryCustom { private final JPAQueryFactory queryFactory; + // 토크룸 페이징 조회 @Override public PageResponse findAllTalkRoom(TalkRoomSearchServiceRequest search) { - //루트 조회(toOne 코드를 모두 한번에 조회) + //루트 조회(toOne 코드를 모두 한번에 조회) -> Query 1번 발생 List findTalkRoom = findTalkRoomBySearch(search); - //TalkRoomRole 컬렉션을 MAP 한방에 조회 - Map> talkRoomRoleMap = findTalkRoomRoleMap(toTalkRoomIds(findTalkRoom)); + //TalkRoomRole 컬렉션을 MAP 한방에 조회 -> Query 1번 발생 + Map> talkRoomRoleMap = findTalkRoomRoleMap( + toTalkRoomIds(findTalkRoom)); //루프를 돌면서 컬렉션 추가(추가 쿼리 실행X) findTalkRoom.forEach(t -> t.addTalkRoomStatus(talkRoomRoleMap.get(t.getTalkRoomId()))); + // 좋아요한 유저 ID 정보들 추가 -> Query 1번 발생 + Map> talkRoomLikeUserMap = findTalkRoomLikeUserId( + toTalkRoomIds(findTalkRoom)); + findTalkRoom.forEach(t -> t.addTalkRoomLikeUserIds(talkRoomLikeUserMap.get(t.getTalkRoomId()))); + + // query 1번 발생 long totalCount = getTotalTalkRoomCount(); return PageResponse.builder() @@ -49,90 +64,139 @@ public PageResponse findAllTalkRoom(TalkRoomSearchServi .build(); } + // 토크룸 단건 조회 @Override public TalkRoomFindOneResponse findOneTalkRoom(Long talkRoomId) { TalkRoomFindOneResponse findOneTalkRoom = findTalkRoomByTalkRoomId(talkRoomId); - List talkRoomRoles = findTalkRoomRoleByTalkRoomId(talkRoomId); + List talkRoomRoles = findTalkRoomRoleByTalkRoomId(talkRoomId); findOneTalkRoom.addTalkRoomStatus(talkRoomRoles); - List talkRoomComments = findCommentsByTalkRoomId(talkRoomId); + List talkRoomComments = findCommentsByTalkRoomId(talkRoomId); findOneTalkRoom.addTalkRoomComments(talkRoomComments); + List userIds = findOneTalkRoomLikeUserId(talkRoomId); + findOneTalkRoom.addUserIds(userIds); + return findOneTalkRoom; } - private List findCommentsByTalkRoomId(Long talkRoomId) { - return queryFactory.select(new QTalkRoomQueryComments( - comment.id.as("commentId"), + // 토크룸 페이징 조회 쿼리 + private List findTalkRoomBySearch(TalkRoomSearchServiceRequest search) { + return queryFactory.select(new QTalkRoomFindAllResponse( + talkRoom.id.as("talkRoomId"), user.name.as("userName"), - comment.content + talkRoom.title, + talkRoom.content, + book.title, + book.imageUrl.as("bookImage"), + talkRoomLike.count().as("likeCount") )) - .from(comment) - .join(comment.talkRoom, talkRoom) - .join(comment.user, user) - .where(comment.talkRoom.id.eq(talkRoomId)) + .from(talkRoom) + .join(talkRoom.user, user) + .join(talkRoom.book, book) + .leftJoin(talkRoomLike).on(talkRoom.eq(talkRoomLike.talkRoom)) + .groupBy(talkRoom.id) + .where(searchQuery(search.getSearch())) + .offset(search.getOffset()) + .limit(search.getSize()) + .orderBy(condition(search.getOrderType())) .fetch(); } - private List findTalkRoomRoleByTalkRoomId(Long talkRoomId) { - return queryFactory.select(new QTalkRoomQueryReadingStatus( - talkRoom.id, - talkRoomRole.readingStatus - )) - .from(talkRoomRole) - .join(talkRoomRole.talkRoom, talkRoom) - .where(talkRoomRole.talkRoom.id.eq(talkRoomId)) - .fetch(); + private BooleanExpression searchQuery(String search) { + return search != null ? talkRoom.title.contains(search) : null; } + // 쿼리에서 가져온 토크룸 ID를 List 객체에 넣어주는 로직 private List toTalkRoomIds(List findTalkRoom) { return findTalkRoom.stream() .map(t -> t.getTalkRoomId()) .collect(Collectors.toList()); } - private Map> findTalkRoomRoleMap(List talkRoomIds) { - List talkRoomRoles = queryFactory.select(new QTalkRoomQueryReadingStatus( - talkRoom.id, - talkRoomRole.readingStatus - )) + // 토크룸 상태 가져온 후 Map<>에 넣어주는 로직 + private Map> findTalkRoomRoleMap(List talkRoomIds) { + List talkRoomRoles = queryFactory.select( + new QTalkRoomQueryReadingStatusResponse( + talkRoom.id, + talkRoomRole.readingStatus + )) .from(talkRoomRole) .join(talkRoomRole.talkRoom, talkRoom) .where(talkRoomRole.talkRoom.id.in(talkRoomIds)) .fetch(); return talkRoomRoles.stream() - .collect(Collectors.groupingBy(TalkRoomQueryReadingStatus::getTalkRoomId)); + .collect(Collectors.groupingBy(TalkRoomQueryReadingStatusResponse::getTalkRoomId)); } - private long getTotalTalkRoomCount() { - return queryFactory - .select(talkRoom.count()) - .from(talkRoom) - .join(talkRoom.user, user) - .join(talkRoom.book, book) - .fetchOne(); + // 페이징 조회 -> 토크룸 좋아요 누른 사용자 ID 가져온 후 Map<>에 넣어주는 로직 + private Map> findTalkRoomLikeUserId(List talkRoomIds) { + List talkRoomLikeUserIds = queryFactory.select(new QTalkRoomLikeUserIdResponse( + talkRoom.id.as("talkRoomId"), + user.id.as("userId") + )) + .from(talkRoomLike) + .join(talkRoomLike.talkRoom, talkRoom) + .join(talkRoomLike.user, user) + .where(talkRoomLike.talkRoom.id.in(talkRoomIds)) + .fetch(); + + return talkRoomLikeUserIds.stream() + .collect(Collectors.groupingBy(TalkRoomLikeUserIdResponse::getTalkRoomId)); } - private List findTalkRoomBySearch(TalkRoomSearchServiceRequest search) { - return queryFactory.select(new QTalkRoomFindAllResponse( + // 단건 조회 -> 토크룸 좋아요 누른 사용자 ID 가져온 후 Map<>에 넣어주는 로직 + private List findOneTalkRoomLikeUserId(Long talkRoomId) { + return queryFactory.select(new QTalkRoomLikeUserIdResponse( talkRoom.id.as("talkRoomId"), + user.id.as("userId") + )) + .from(talkRoomLike) + .join(talkRoomLike.talkRoom, talkRoom) + .join(talkRoomLike.user, user) + .where(talkRoomLike.talkRoom.id.eq(talkRoomId)) + .fetch(); + } + + // 토크룸 단건 조회 시 토크룸 상태 가져오는 쿼리 + private List findTalkRoomRoleByTalkRoomId(Long talkRoomId) { + return queryFactory.select(new QTalkRoomQueryReadingStatusResponse( + talkRoom.id, + talkRoomRole.readingStatus + )) + .from(talkRoomRole) + .join(talkRoomRole.talkRoom, talkRoom) + .where(talkRoomRole.talkRoom.id.eq(talkRoomId)) + .fetch(); + } + + // 토크룸에 저장된 의견들 가져오는 쿼리 + private List findCommentsByTalkRoomId(Long talkRoomId) { + return queryFactory.select(new QTalkRoomQueryCommentsResponse( + comment.id.as("commentId"), user.name.as("userName"), - talkRoom.title, - talkRoom.content, - book.title, - book.imageUrl.as("bookImage") + comment.content )) + .from(comment) + .join(comment.talkRoom, talkRoom) + .join(comment.user, user) + .where(comment.talkRoom.id.eq(talkRoomId)) + .fetch(); + } + + // 토크룸 전체 개수 가져오는 쿼리 + private long getTotalTalkRoomCount() { + return queryFactory + .select(talkRoom.count()) .from(talkRoom) .join(talkRoom.user, user) .join(talkRoom.book, book) - .offset(search.getOffset()) - .limit(search.getSize()) - .orderBy(condition(search.getOrder())) - .fetch(); + .fetchOne(); } + // 토크룸 단건 조회 쿼리 private TalkRoomFindOneResponse findTalkRoomByTalkRoomId(Long talkRoomId) { return queryFactory.select(new QTalkRoomFindOneResponse( talkRoom.id.as("talkRoomId"), @@ -140,21 +204,27 @@ private TalkRoomFindOneResponse findTalkRoomByTalkRoomId(Long talkRoomId) { talkRoom.title, talkRoom.content, book.title, - book.imageUrl.as("bookImage") + book.imageUrl.as("bookImage"), + talkRoomLike.count().as("likeCount"), + comment.count().as("commentCount") )) .from(talkRoom) .join(talkRoom.user, user) .join(talkRoom.book, book) + .leftJoin(talkRoomLike).on(talkRoom.eq(talkRoomLike.talkRoom)) + .leftJoin(comment).on(talkRoom.eq(comment.talkRoom)) + .groupBy(talkRoom.id) .where(talkRoom.id.eq(talkRoomId)) .fetchOne(); } - /** - * 아직 좋아요 기능이 구현 되지 않아 최신순으로만 정렬 - */ - private OrderSpecifier condition(String order) { -// if (order.equals("recent")) - return talkRoom.id.desc(); + private OrderSpecifier condition(OrderType orderType) { + if (RECENT.equals(orderType)) { + return talkRoom.id.desc(); + } else if (RECOMMEND.equals(orderType)) { + return talkRoomLike.count().desc(); + } + return OrderByNull.DEFAULT; } } diff --git a/src/main/java/com/jisungin/domain/talkroomlike/TalkRoomLike.java b/src/main/java/com/jisungin/domain/talkroomlike/TalkRoomLike.java index 9c55e0d..6e09bd0 100644 --- a/src/main/java/com/jisungin/domain/talkroomlike/TalkRoomLike.java +++ b/src/main/java/com/jisungin/domain/talkroomlike/TalkRoomLike.java @@ -3,7 +3,14 @@ import com.jisungin.domain.BaseEntity; import com.jisungin.domain.talkroom.TalkRoom; import com.jisungin.domain.user.User; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -33,4 +40,11 @@ private TalkRoomLike(User user, TalkRoom talkRoom) { this.talkRoom = talkRoom; } + public static TalkRoomLike likeTalkRoom(User user, TalkRoom talkRoom) { + return TalkRoomLike.builder() + .user(user) + .talkRoom(talkRoom) + .build(); + } + } diff --git a/src/main/java/com/jisungin/domain/talkroomlike/repository/TalkRoomLikeRepository.java b/src/main/java/com/jisungin/domain/talkroomlike/repository/TalkRoomLikeRepository.java new file mode 100644 index 0000000..fb33c44 --- /dev/null +++ b/src/main/java/com/jisungin/domain/talkroomlike/repository/TalkRoomLikeRepository.java @@ -0,0 +1,12 @@ +package com.jisungin.domain.talkroomlike.repository; + +import com.jisungin.domain.talkroomlike.TalkRoomLike; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TalkRoomLikeRepository extends JpaRepository { + + Optional findByTalkRoomIdAndUserId(Long talkRoomId, Long userId); +} diff --git a/src/main/java/com/jisungin/exception/ErrorCode.java b/src/main/java/com/jisungin/exception/ErrorCode.java index e6a3e33..dc31295 100644 --- a/src/main/java/com/jisungin/exception/ErrorCode.java +++ b/src/main/java/com/jisungin/exception/ErrorCode.java @@ -17,6 +17,8 @@ public enum ErrorCode { UNAUTHORIZED_REQUEST(400, "권한이 없는 사용자입니다."), COMMENT_NOT_FOUND(404, "의견을 찾을 수 없습니다."), REVIEW_NOT_FOUND(404, "리뷰를 찾을 수 없습니다."), + TALK_ROOM_LIKE_NOT_FOUND(404, "토크방 좋아요를 찾을 수 없습니다."), + LIKE_EXIST(400, "이미 좋아요를 눌렀습니다."), REQUEST_TIME_OUT(408, "요청 시간이 만료 되었습니다."); diff --git a/src/test/java/com/jisungin/ControllerTestSupport.java b/src/test/java/com/jisungin/ControllerTestSupport.java index 5928924..9f12774 100644 --- a/src/test/java/com/jisungin/ControllerTestSupport.java +++ b/src/test/java/com/jisungin/ControllerTestSupport.java @@ -5,9 +5,11 @@ import com.jisungin.api.oauth.AuthContext; import com.jisungin.api.review.ReviewController; import com.jisungin.api.talkroom.TalkRoomController; +import com.jisungin.api.talkroomlike.TalkRoomLikeController; import com.jisungin.application.comment.CommentService; import com.jisungin.application.review.ReviewService; import com.jisungin.application.talkroom.TalkRoomService; +import com.jisungin.application.talkroomlike.TalkRoomLikeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -16,7 +18,8 @@ @WebMvcTest(controllers = { TalkRoomController.class, CommentController.class, - ReviewController.class + ReviewController.class, + TalkRoomLikeController.class }) public abstract class ControllerTestSupport { @@ -38,4 +41,7 @@ public abstract class ControllerTestSupport { @MockBean protected ReviewService reviewService; + @MockBean + protected TalkRoomLikeService talkRoomLikeService; + } diff --git a/src/test/java/com/jisungin/api/talkroomlike/TalkRoomLikeControllerTest.java b/src/test/java/com/jisungin/api/talkroomlike/TalkRoomLikeControllerTest.java new file mode 100644 index 0000000..c0c8872 --- /dev/null +++ b/src/test/java/com/jisungin/api/talkroomlike/TalkRoomLikeControllerTest.java @@ -0,0 +1,44 @@ +package com.jisungin.api.talkroomlike; + +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.jisungin.ControllerTestSupport; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class TalkRoomLikeControllerTest extends ControllerTestSupport { + + @Test + @DisplayName("유저가 토크방에 좋아요를 누를 수 있다.") + void likeTalkRoom() throws Exception { + // when // then + mockMvc.perform(post("/v1/talk-rooms/1/likes") + .contentType(APPLICATION_JSON) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.status").value("OK")) + .andExpect(jsonPath("$.message").value("좋아요 성공")); + } + + @Test + @DisplayName("유저가 토크방 좋아요를 취소 할 수 있다.") + void unLikeTalkRoom() throws Exception { + // when // then + mockMvc.perform(delete("/v1/talk-rooms/1/likes") + .contentType(APPLICATION_JSON) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.status").value("OK")) + .andExpect(jsonPath("$.message").value("좋아요 취소")); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jisungin/application/service/talkroom/TalkRoomServiceTest.java b/src/test/java/com/jisungin/application/service/talkroom/TalkRoomServiceTest.java index 383e5f7..79513b8 100644 --- a/src/test/java/com/jisungin/application/service/talkroom/TalkRoomServiceTest.java +++ b/src/test/java/com/jisungin/application/service/talkroom/TalkRoomServiceTest.java @@ -4,7 +4,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.jisungin.ServiceTestSupport; -import com.jisungin.application.response.PageResponse; +import com.jisungin.application.OrderType; +import com.jisungin.application.PageResponse; import com.jisungin.application.talkroom.TalkRoomService; import com.jisungin.application.talkroom.request.TalkRoomCreateServiceRequest; import com.jisungin.application.talkroom.request.TalkRoomEditServiceRequest; @@ -23,12 +24,15 @@ import com.jisungin.domain.talkroom.TalkRoomRole; import com.jisungin.domain.talkroom.repository.TalkRoomRepository; import com.jisungin.domain.talkroom.repository.TalkRoomRoleRepository; +import com.jisungin.domain.talkroomlike.TalkRoomLike; +import com.jisungin.domain.talkroomlike.repository.TalkRoomLikeRepository; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; import com.jisungin.exception.BusinessException; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; @@ -55,8 +59,12 @@ class TalkRoomServiceTest extends ServiceTestSupport { @Autowired CommentRepository commentRepository; + @Autowired + TalkRoomLikeRepository talkRoomLikeRepository; + @AfterEach void tearDown() { + talkRoomLikeRepository.deleteAllInBatch(); commentRepository.deleteAllInBatch(); talkRoomRoleRepository.deleteAllInBatch(); talkRoomRepository.deleteAllInBatch(); @@ -295,14 +303,7 @@ void getTalkRooms() { Book book = createBook(); bookRepository.save(book); - List talkRoom = IntStream.range(0, 20) - .mapToObj(i -> TalkRoom.builder() - .user(user) - .book(book) - .title("토론방 " + i) - .content("내용 " + i) - .build()) - .toList(); + List talkRoom = listTalkRooms(20, user, book); talkRoomRepository.saveAll(talkRoom); @@ -313,6 +314,7 @@ void getTalkRooms() { TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() .page(1) .size(10) + .orderType(OrderType.RECENT) .build(); // when @@ -334,14 +336,7 @@ void getTalkRoomsPageTotalCount() { Book book = createBook(); bookRepository.save(book); - List talkRoom = IntStream.range(0, 103) - .mapToObj(i -> TalkRoom.builder() - .user(user) - .book(book) - .title("토론방 " + i) - .content("내용 " + i) - .build()) - .toList(); + List talkRoom = listTalkRooms(103, user, book); talkRoomRepository.saveAll(talkRoom); @@ -371,14 +366,7 @@ void getTalkRoomsMiddle() { Book book = createBook(); bookRepository.save(book); - List talkRoom = IntStream.range(0, 103) - .mapToObj(i -> TalkRoom.builder() - .user(user) - .book(book) - .title("토론방 " + i) - .content("내용 " + i) - .build()) - .toList(); + List talkRoom = listTalkRooms(103, user, book); talkRoomRepository.saveAll(talkRoom); @@ -389,6 +377,7 @@ void getTalkRoomsMiddle() { TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() .page(5) .size(10) + .orderType(OrderType.RECENT) .build(); // when @@ -410,14 +399,7 @@ void getTalkRoomsLast() { Book book = createBook(); bookRepository.save(book); - List talkRoom = IntStream.range(0, 103) - .mapToObj(i -> TalkRoom.builder() - .user(user) - .book(book) - .title("토론방 " + i) - .content("내용 " + i) - .build()) - .toList(); + List talkRoom = listTalkRooms(103, user, book); talkRoomRepository.saveAll(talkRoom); @@ -428,6 +410,7 @@ void getTalkRoomsLast() { TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() .page(11) .size(10) + .orderType(OrderType.RECENT) .build(); // when @@ -610,6 +593,360 @@ void deleteTalkRoomWithComment() { assertThat(0).isEqualTo(talkRoomRepository.findAll().size()); } + @Test + @DisplayName("토크방을 페이징 조회 시 토크방에는 좋아요 총 개수가 표시되어야 한다.") + void findAllTalkRoomWithLikeCount() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(2) + .size(10) + .orderType(OrderType.RECENT) + .build(); + + // when + PageResponse response = talkRoomService.findAllTalkRoom(search); + + // then + assertThat(5L).isEqualTo(response.getQueryResponse().get(9).getLikeCount()); + } + + @Test + @DisplayName("토크방 페이지 조회 시 토크방에 좋아요 누른 사용자 ID들이 프론트에 전송되어야 한다.") + void findAllTalkRoomWithLikeUserId() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(5, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(i)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(2) + .size(10) + .orderType(OrderType.RECENT) + .build(); + + // when + PageResponse response = talkRoomService.findAllTalkRoom(search); + + // then + assertThat(users.get(0).getId()).isEqualTo(response.getQueryResponse().get(9).getUserIds().get(0).getUserId()); + assertThat(users.get(1).getId()).isEqualTo(response.getQueryResponse().get(9).getUserIds().get(1).getUserId()); + assertThat(users.get(2).getId()).isEqualTo(response.getQueryResponse().get(9).getUserIds().get(2).getUserId()); + assertThat(users.get(3).getId()).isEqualTo(response.getQueryResponse().get(9).getUserIds().get(3).getUserId()); + assertThat(users.get(4).getId()).isEqualTo(response.getQueryResponse().get(9).getUserIds().get(4).getUserId()); + } + + @Test + @DisplayName("토크방 단건 조회 시 좋아요 개수가 표시 된다.") + void findOneTalkRoomWithLikeCount() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + talkRoomLikeRepository.saveAll(likes); + + // when + TalkRoomFindOneResponse response = talkRoomService.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(5L).isEqualTo(response.getLikeCount()); + } + + @Test + @DisplayName("토크방 단건 조회 시 좋아요한 유저의 ID가 보내진다.") + void findOneTalkRoomWithLikeUserId() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + talkRoomLikeRepository.saveAll(likes); + + // when + TalkRoomFindOneResponse response = talkRoomService.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(users.get(0).getId()).isEqualTo(response.getUserIds().get(0).getUserId()); + assertThat(users.get(1).getId()).isEqualTo(response.getUserIds().get(1).getUserId()); + assertThat(users.get(2).getId()).isEqualTo(response.getUserIds().get(2).getUserId()); + assertThat(users.get(3).getId()).isEqualTo(response.getUserIds().get(3).getUserId()); + assertThat(users.get(4).getId()).isEqualTo(response.getUserIds().get(4).getUserId()); + } + + @Test + @DisplayName("토크방 단건 조회 시 의견 개수가 표시 된다.") + void findOneTalkRoomWithCommentCount() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List comments = IntStream.range(0, 5) + .mapToObj(i -> Comment.builder() + .talkRoom(talkRoom.get(0)) + .user(users.get(0)) + .content("의견 " + i) + .build()) + .collect(Collectors.toList()); + + commentRepository.saveAll(comments); + + // when + TalkRoomFindOneResponse response = talkRoomService.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(5L).isEqualTo(response.getCommentCount()); + } + + @Test + @DisplayName("토크방을 좋아요 순으로 정렬을 한다.") + void findAllTalkRoomWithOrderLike() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(0, 9).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(1)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(1) + .size(10) + .orderType(OrderType.RECOMMEND) + .build(); + + // when + PageResponse response = talkRoomService.findAllTalkRoom(search); + + // then + assertThat(10L).isEqualTo(response.getQueryResponse().get(0).getLikeCount()); + } + + @Test + @DisplayName("토크방 제목을 입력해서 조회한다.") + void findAllTalkRoomWithSearch() { + // given + List users = listUsers(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = listTalkRooms(20, users.get(0), book); + + TalkRoom talkRoom1 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("검색어") + .content("내용") + .build(); + + TalkRoom talkRoom2 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("아무내용 검색어 아무내용") + .content("내용") + .build(); + + TalkRoom talkRoom3 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("아무내용 아무내용 검색어") + .content("내용") + .build(); + + talkRoomRepository.save(talkRoom1); + talkRoomRepository.save(talkRoom2); + talkRoomRepository.save(talkRoom3); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(0, 9).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(1)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(1) + .size(10) + .search("검색어") + .build(); + + // when + PageResponse response = talkRoomService.findAllTalkRoom(search); + + // then + assertThat(talkRoom1.getTitle()).isEqualTo(response.getQueryResponse().get(0).getTitle()); + assertThat(talkRoom2.getTitle()).isEqualTo(response.getQueryResponse().get(1).getTitle()); + assertThat(talkRoom3.getTitle()).isEqualTo(response.getQueryResponse().get(2).getTitle()); + } + + private static List listUsers() { + return IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + } + + private static List listTalkRooms(int endExclusive, User users, Book book) { + return IntStream.range(0, endExclusive) + .mapToObj(i -> TalkRoom.builder() + .user(users) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + } + private static Comment createComment(TalkRoom talkRoom, User user) { return Comment.builder() .talkRoom(talkRoom) diff --git a/src/test/java/com/jisungin/application/talkroomlike/TalkRoomLikeServiceTest.java b/src/test/java/com/jisungin/application/talkroomlike/TalkRoomLikeServiceTest.java new file mode 100644 index 0000000..6a7bd8c --- /dev/null +++ b/src/test/java/com/jisungin/application/talkroomlike/TalkRoomLikeServiceTest.java @@ -0,0 +1,232 @@ +package com.jisungin.application.talkroomlike; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.jisungin.ServiceTestSupport; +import com.jisungin.application.talkroom.TalkRoomService; +import com.jisungin.domain.ReadingStatus; +import com.jisungin.domain.book.Book; +import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.domain.oauth.OauthId; +import com.jisungin.domain.oauth.OauthType; +import com.jisungin.domain.talkroom.TalkRoom; +import com.jisungin.domain.talkroom.TalkRoomRole; +import com.jisungin.domain.talkroom.repository.TalkRoomRepository; +import com.jisungin.domain.talkroom.repository.TalkRoomRoleRepository; +import com.jisungin.domain.talkroomlike.TalkRoomLike; +import com.jisungin.domain.talkroomlike.repository.TalkRoomLikeRepository; +import com.jisungin.domain.user.User; +import com.jisungin.domain.user.repository.UserRepository; +import com.jisungin.exception.BusinessException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class TalkRoomLikeServiceTest extends ServiceTestSupport { + + @Autowired + TalkRoomRepository talkRoomRepository; + + @Autowired + TalkRoomRoleRepository talkRoomRoleRepository; + + @Autowired + TalkRoomService talkRoomService; + + @Autowired + BookRepository bookRepository; + + @Autowired + UserRepository userRepository; + + @Autowired + TalkRoomLikeService talkRoomLikeService; + + @Autowired + TalkRoomLikeRepository talkRoomLikeRepository; + + @AfterEach + void tearDown() { + talkRoomLikeRepository.deleteAllInBatch(); + talkRoomRoleRepository.deleteAllInBatch(); + talkRoomRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + bookRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("유저가 토크방을 좋아요 한다.") + void likeTalkRoom() { + // given + User user = createUser(); + userRepository.save(user); + + Book book = createBook(); + bookRepository.save(book); + + TalkRoom talkRoom = createTalkRoom(book, user); + talkRoomRepository.save(talkRoom); + + createTalkRoomRole(talkRoom); + + // when + talkRoomLikeService.likeTalkRoom(talkRoom.getId(), user.getId()); + + // then + List talkRoomLikes = talkRoomLikeRepository.findAll(); + assertThat(1).isEqualTo(talkRoomLikes.size()); + } + + @Test + @DisplayName("토크방이 없는 상태에선 좋아요 할 수 없다.") + void likeTalkRoomWithTalkRoomEmpty() { + // given + User user = createUser(); + userRepository.save(user); + + // when // then + assertThatThrownBy(() -> talkRoomLikeService.likeTalkRoom(1L, user.getId())) + .isInstanceOf(BusinessException.class) + .hasMessage("토크방을 찾을 수 없습니다."); + } + + @Test + @DisplayName("로그인을 하지 않는 상태에선 좋아요를 누를 수 없다.") + void likeTalkRoomWithUserEmpty() { + // given + User user = createUser(); + userRepository.save(user); + + Book book = createBook(); + bookRepository.save(book); + + TalkRoom talkRoom = createTalkRoom(book, user); + talkRoomRepository.save(talkRoom); + + createTalkRoomRole(talkRoom); + // when // then + assertThatThrownBy(() -> talkRoomLikeService.likeTalkRoom(talkRoom.getId(), 100L)) + .isInstanceOf(BusinessException.class) + .hasMessage("사용자를 찾을 수 없습니다."); + } + + @Test + @DisplayName("유저가 좋아요를 취소한다.") + void unLikeTalkRoom() { + // given + User user = createUser(); + userRepository.save(user); + + Book book = createBook(); + bookRepository.save(book); + + TalkRoom talkRoom = createTalkRoom(book, user); + talkRoomRepository.save(talkRoom); + + createTalkRoomRole(talkRoom); + + TalkRoomLike talkRoomLike = createTalkRoomLike(talkRoom, user); + talkRoomLikeRepository.save(talkRoomLike); + + // when + talkRoomLikeService.unLikeTalkRoom(talkRoom.getId(), user.getId()); + + // then + List talkRoomLikes = talkRoomLikeRepository.findAll(); + assertThat(0).isEqualTo(talkRoomLikes.size()); + } + + @Test + @DisplayName("유저A의 좋아요를 유저B가 취소할 순 없다.") + void unLikeTalkRoomWithUserB() { + // given + User user = createUser(); + userRepository.save(user); + + User userB = User.builder() + .name("userB@gmail.com") + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId2") + .oauthType(OauthType.KAKAO) + .build() + ) + .build(); + userRepository.save(userB); + + Book book = createBook(); + bookRepository.save(book); + + TalkRoom talkRoom = createTalkRoom(book, user); + talkRoomRepository.save(talkRoom); + + createTalkRoomRole(talkRoom); + + TalkRoomLike talkRoomLike = createTalkRoomLike(talkRoom, user); + talkRoomLikeRepository.save(talkRoomLike); + + // when // then + assertThatThrownBy(() -> talkRoomLikeService.unLikeTalkRoom(talkRoom.getId(), userB.getId())) + .isInstanceOf(BusinessException.class) + .hasMessage("토크방 좋아요를 찾을 수 없습니다."); + } + + private static TalkRoomLike createTalkRoomLike(TalkRoom talkRoom, User user) { + return TalkRoomLike.builder() + .talkRoom(talkRoom) + .user(user) + .build(); + } + + private void createTalkRoomRole(TalkRoom talkRoom) { + List request = new ArrayList<>(); + request.add("읽는 중"); + request.add("읽음"); + + List readingStatus = ReadingStatus.createReadingStatus(request); + + readingStatus.stream().map(status -> TalkRoomRole.roleCreate(talkRoom, status)) + .forEach(talkRoomRoleRepository::save); + } + + private static TalkRoom createTalkRoom(Book book, User user) { + return TalkRoom.builder() + .book(book) + .title("토크방") + .content("내용") + .user(user) + .build(); + } + + private static User createUser() { + return User.builder() + .name("user@gmail.com") + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId") + .oauthType(OauthType.KAKAO) + .build() + ) + .build(); + } + + private static Book createBook() { + return Book.builder() + .title("제목") + .content("내용") + .authors("작가") + .isbn("11111") + .publisher("publisher") + .dateTime(LocalDateTime.now()) + .imageUrl("www") + .build(); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImplTest.java b/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImplTest.java deleted file mode 100644 index 050d3aa..0000000 --- a/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImplTest.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.jisungin.domain.talkroom.repository; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.jisungin.RepositoryTestSupport; -import com.jisungin.application.response.PageResponse; -import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; -import com.jisungin.application.talkroom.response.TalkRoomFindAllResponse; -import com.jisungin.application.talkroom.response.TalkRoomFindOneResponse; -import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.book.Book; -import com.jisungin.domain.book.repository.BookRepository; -import com.jisungin.domain.comment.Comment; -import com.jisungin.domain.comment.repository.CommentRepository; -import com.jisungin.domain.oauth.OauthId; -import com.jisungin.domain.oauth.OauthType; -import com.jisungin.domain.talkroom.TalkRoom; -import com.jisungin.domain.talkroom.TalkRoomRole; -import com.jisungin.domain.user.User; -import com.jisungin.domain.user.repository.UserRepository; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.IntStream; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -class TalkRoomRepositoryImplTest extends RepositoryTestSupport { - - @Autowired - TalkRoomRepository talkRoomRepository; - - @Autowired - TalkRoomRoleRepository talkRoomRoleRepository; - - @Autowired - BookRepository bookRepository; - - @Autowired - UserRepository userRepository; - - @Autowired - CommentRepository commentRepository; - - @AfterEach - void tearDown() { - commentRepository.deleteAllInBatch(); - talkRoomRoleRepository.deleteAllInBatch(); - talkRoomRepository.deleteAllInBatch(); - userRepository.deleteAllInBatch(); - bookRepository.deleteAllInBatch(); - } - - @Test - @DisplayName("querydsl 페이징 조회 테스트") - void pageTest() { - // given - User user = createUser(); - userRepository.save(user); - - Book book = createBook(); - bookRepository.save(book); - - List talkRoom = IntStream.range(0, 20) - .mapToObj(i -> TalkRoom.builder() - .user(user) - .book(book) - .title("토론방 " + i) - .content("내용 " + i) - .build()) - .toList(); - - talkRoomRepository.saveAll(talkRoom); - - for (TalkRoom t : talkRoom) { - createTalkRoomRole(t); - } - - TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() - .page(1) - .size(10) - .order(null) - .build(); - - // when - PageResponse talkRooms = talkRoomRepository.findAllTalkRoom(search); - - // then - assertThat(10L).isEqualTo(talkRooms.getQueryResponse().size()); - assertThat("토론방 19").isEqualTo(talkRooms.getQueryResponse().get(0).getTitle()); - assertThat("내용 19").isEqualTo(talkRooms.getQueryResponse().get(0).getContent()); - assertThat(2).isEqualTo(talkRooms.getQueryResponse().get(0).getReadingStatuses().size()); - assertThat(20).isEqualTo(talkRooms.getTotalCount()); - } - - @Test - @DisplayName("querydsl 단건 조회 토크방 의견 조회 테스트") - void talkRoomFindOneComment() { - // given - User user = createUser(); - userRepository.save(user); - - Book book = createBook(); - bookRepository.save(book); - - TalkRoom talkRoom = createTalkRoom(book, user); - talkRoomRepository.save(talkRoom); - - createTalkRoomRole(talkRoom); - - Comment comment = createComment(talkRoom, user); - - commentRepository.save(comment); - // when - TalkRoomFindOneResponse findOneTalkRoom = talkRoomRepository.findOneTalkRoom(talkRoom.getId()); - - // then - assertThat("토론방").isEqualTo(findOneTalkRoom.getTitle()); - assertThat(2).isEqualTo(findOneTalkRoom.getReadingStatuses().size()); - assertThat("의견 남기기").isEqualTo(findOneTalkRoom.getComments().get(0).getContent()); - assertThat("user@gmail.com").isEqualTo(findOneTalkRoom.getComments().get(0).getUserName()); - } - - private static Comment createComment(TalkRoom talkRoom, User user) { - return Comment.builder() - .talkRoom(talkRoom) - .user(user) - .content("의견 남기기") - .build(); - } - - private void createTalkRoomRole(TalkRoom talkRoom) { - List request = new ArrayList<>(); - request.add("읽는 중"); - request.add("읽음"); - - List readingStatus = ReadingStatus.createReadingStatus(request); - - readingStatus.stream().map(status -> TalkRoomRole.roleCreate(talkRoom, status)) - .forEach(talkRoomRoleRepository::save); - } - - private static TalkRoom createTalkRoom(Book book, User user) { - return TalkRoom.builder() - .book(book) - .title("토론방") - .content("내용") - .user(user) - .build(); - } - - private static User createUser() { - return User.builder() - .name("user@gmail.com") - .profileImage("image") - .oauthId( - OauthId.builder() - .oauthId("oauthId") - .oauthType(OauthType.KAKAO) - .build() - ) - .build(); - } - - private static Book createBook() { - return Book.builder() - .title("제목") - .content("내용") - .authors("작가") - .isbn("11111") - .publisher("publisher") - .dateTime(LocalDateTime.now()) - .imageUrl("www") - .build(); - } - -} \ No newline at end of file diff --git a/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryTest.java b/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryTest.java new file mode 100644 index 0000000..a6a5163 --- /dev/null +++ b/src/test/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryTest.java @@ -0,0 +1,582 @@ +package com.jisungin.domain.talkroom.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.jisungin.RepositoryTestSupport; +import com.jisungin.application.OrderType; +import com.jisungin.application.PageResponse; +import com.jisungin.application.talkroom.request.TalkRoomSearchServiceRequest; +import com.jisungin.application.talkroom.response.TalkRoomFindAllResponse; +import com.jisungin.application.talkroom.response.TalkRoomFindOneResponse; +import com.jisungin.domain.ReadingStatus; +import com.jisungin.domain.book.Book; +import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.domain.comment.Comment; +import com.jisungin.domain.comment.repository.CommentRepository; +import com.jisungin.domain.oauth.OauthId; +import com.jisungin.domain.oauth.OauthType; +import com.jisungin.domain.talkroom.TalkRoom; +import com.jisungin.domain.talkroom.TalkRoomRole; +import com.jisungin.domain.talkroomlike.TalkRoomLike; +import com.jisungin.domain.talkroomlike.repository.TalkRoomLikeRepository; +import com.jisungin.domain.user.User; +import com.jisungin.domain.user.repository.UserRepository; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class TalkRoomRepositoryTest extends RepositoryTestSupport { + + @Autowired + TalkRoomRepository talkRoomRepository; + + @Autowired + TalkRoomRoleRepository talkRoomRoleRepository; + + @Autowired + BookRepository bookRepository; + + @Autowired + UserRepository userRepository; + + @Autowired + CommentRepository commentRepository; + + @Autowired + TalkRoomLikeRepository talkRoomLikeRepository; + + @AfterEach + void tearDown() { + talkRoomLikeRepository.deleteAllInBatch(); + commentRepository.deleteAllInBatch(); + talkRoomRoleRepository.deleteAllInBatch(); + talkRoomRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + bookRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("querydsl 페이징 조회 테스트") + void pageTest() { + // given + User user = createUser(); + userRepository.save(user); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(user) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(1) + .size(10) + .orderType(OrderType.RECENT) + .build(); + + // when + PageResponse talkRooms = talkRoomRepository.findAllTalkRoom(search); + + // then + assertThat(10L).isEqualTo(talkRooms.getQueryResponse().size()); + assertThat("토론방 19").isEqualTo(talkRooms.getQueryResponse().get(0).getTitle()); + assertThat("내용 19").isEqualTo(talkRooms.getQueryResponse().get(0).getContent()); + assertThat(2).isEqualTo(talkRooms.getQueryResponse().get(0).getReadingStatuses().size()); + assertThat(20).isEqualTo(talkRooms.getTotalCount()); + } + + @Test + @DisplayName("querydsl 단건 조회 토크방 의견 조회 테스트") + void talkRoomFindOneComment() { + // given + User user = createUser(); + userRepository.save(user); + + Book book = createBook(); + bookRepository.save(book); + + TalkRoom talkRoom = createTalkRoom(book, user); + talkRoomRepository.save(talkRoom); + + createTalkRoomRole(talkRoom); + + Comment comment = createComment(talkRoom, user); + + commentRepository.save(comment); + // when + TalkRoomFindOneResponse findOneTalkRoom = talkRoomRepository.findOneTalkRoom(talkRoom.getId()); + + // then + assertThat("토론방").isEqualTo(findOneTalkRoom.getTitle()); + assertThat(2).isEqualTo(findOneTalkRoom.getReadingStatuses().size()); + assertThat("의견 남기기").isEqualTo(findOneTalkRoom.getComments().get(0).getContent()); + assertThat("user@gmail.com").isEqualTo(findOneTalkRoom.getComments().get(0).getUserName()); + } + + @Test + @DisplayName("querydsl 좋아요 총 개수 조회") + void likeTalkRoomFindCount() { + // given + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(5, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(i)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(2) + .size(10) + .orderType(OrderType.RECENT) + .build(); + + // when + PageResponse response = talkRoomRepository.findAllTalkRoom(search); + + // then + assertThat(5L).isEqualTo(response.getQueryResponse().get(9).getLikeCount()); + } + + @Test + @DisplayName("querydsl 토크방 단건 조회 시 좋아요 개수 표시 테스트") + void findOneTalkRoomWithLikeCount() { + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(5, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(i)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + // when + TalkRoomFindOneResponse response = talkRoomRepository.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(5L).isEqualTo(response.getLikeCount()); + } + + @Test + @DisplayName("querydsl 토크방 단건 조회 시 의견 개수 표시 테스트") + void findOneTalkRoomWithCommentCount() { + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List comments = IntStream.range(0, 5) + .mapToObj(i -> Comment.builder() + .talkRoom(talkRoom.get(0)) + .user(users.get(0)) + .content("의견 " + i) + .build()) + .collect(Collectors.toList()); + + commentRepository.saveAll(comments); + + // when + TalkRoomFindOneResponse response = talkRoomRepository.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(5L).isEqualTo(response.getCommentCount()); + } + + @Test + @DisplayName("querydsl 토크방 단건 조회 시 좋아요 누른 userId 반환") + void findOneTalkRoomWithUserId() { + // given + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes = IntStream.range(0, 5).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + talkRoomLikeRepository.saveAll(likes); + + // when + TalkRoomFindOneResponse response = talkRoomRepository.findOneTalkRoom(talkRoom.get(0).getId()); + + // then + assertThat(users.get(0).getId()).isEqualTo(response.getUserIds().get(0).getUserId()); + assertThat(users.get(1).getId()).isEqualTo(response.getUserIds().get(1).getUserId()); + assertThat(users.get(2).getId()).isEqualTo(response.getUserIds().get(2).getUserId()); + assertThat(users.get(3).getId()).isEqualTo(response.getUserIds().get(3).getUserId()); + assertThat(users.get(4).getId()).isEqualTo(response.getUserIds().get(4).getUserId()); + } + + @Test + @DisplayName("querydsl 좋아요순 정렬 조회") + void findAllTalkRoomWithOrderLike() { + // given + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(0, 9).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(1)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(1) + .size(10) + .orderType(OrderType.RECOMMEND) + .build(); + + // when + PageResponse response = talkRoomRepository.findAllTalkRoom(search); + + // then + assertThat(10L).isEqualTo(response.getQueryResponse().get(0).getLikeCount()); + } + + @Test + @DisplayName("querydsl 토크방 제목 검색") + void findAllTalkRoomWithSearch() { + // given + List users = IntStream.range(0, 10) + .mapToObj(i -> User.builder() + .name("user@gmail.com " + i) + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId " + i) + .oauthType(OauthType.KAKAO) + .build() + ) + .build()).toList(); + + userRepository.saveAll(users); + + Book book = createBook(); + bookRepository.save(book); + + List talkRoom = IntStream.range(0, 20) + .mapToObj(i -> TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("토론방 " + i) + .content("내용 " + i) + .build()) + .toList(); + + TalkRoom talkRoom1 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("검색어") + .content("내용") + .build(); + + TalkRoom talkRoom2 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("아무내용 검색어 아무내용") + .content("내용") + .build(); + + TalkRoom talkRoom3 = TalkRoom.builder() + .user(users.get(0)) + .book(book) + .title("아무내용 아무내용 검색어") + .content("내용") + .build(); + + talkRoomRepository.save(talkRoom1); + talkRoomRepository.save(talkRoom2); + talkRoomRepository.save(talkRoom3); + + talkRoomRepository.saveAll(talkRoom); + + for (TalkRoom t : talkRoom) { + createTalkRoomRole(t); + } + + List likes1 = IntStream.range(0, 10).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(0)) + .build()) + .toList(); + + List likes2 = IntStream.range(0, 9).mapToObj(i -> TalkRoomLike.builder() + .user(users.get(i)) + .talkRoom(talkRoom.get(1)) + .build()) + .toList(); + + List likes = new ArrayList<>(); + likes.addAll(likes1); + likes.addAll(likes2); + + talkRoomLikeRepository.saveAll(likes); + + TalkRoomSearchServiceRequest search = TalkRoomSearchServiceRequest.builder() + .page(1) + .size(10) + .search("검색어") + .build(); + + // when + PageResponse response = talkRoomRepository.findAllTalkRoom(search); + + // then + assertThat(talkRoom1.getTitle()).isEqualTo(response.getQueryResponse().get(0).getTitle()); + assertThat(talkRoom2.getTitle()).isEqualTo(response.getQueryResponse().get(1).getTitle()); + assertThat(talkRoom3.getTitle()).isEqualTo(response.getQueryResponse().get(2).getTitle()); + } + + private static Comment createComment(TalkRoom talkRoom, User user) { + return Comment.builder() + .talkRoom(talkRoom) + .user(user) + .content("의견 남기기") + .build(); + } + + private void createTalkRoomRole(TalkRoom talkRoom) { + List request = new ArrayList<>(); + request.add("읽는 중"); + request.add("읽음"); + + List readingStatus = ReadingStatus.createReadingStatus(request); + + readingStatus.stream().map(status -> TalkRoomRole.roleCreate(talkRoom, status)) + .forEach(talkRoomRoleRepository::save); + } + + private static TalkRoom createTalkRoom(Book book, User user) { + return TalkRoom.builder() + .book(book) + .title("토론방") + .content("내용") + .user(user) + .build(); + } + + private static User createUser() { + return User.builder() + .name("user@gmail.com") + .profileImage("image") + .oauthId( + OauthId.builder() + .oauthId("oauthId") + .oauthType(OauthType.KAKAO) + .build() + ) + .build(); + } + + private static Book createBook() { + return Book.builder() + .title("제목") + .content("내용") + .authors("작가") + .isbn("11111") + .publisher("publisher") + .dateTime(LocalDateTime.now()) + .imageUrl("www") + .build(); + } + +} \ No newline at end of file