Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
package com.example.log4u.domain.comment.dto.response;

import java.time.LocalDateTime;

import com.example.log4u.domain.comment.entity.Comment;
import com.example.log4u.domain.user.entity.User;

public record CommentResponseDto(
Long commentId,
String content
Long userId,
String userName,
String userProfileImage,
String content,
LocalDateTime createdAt
) {
public static CommentResponseDto of(Comment comment) {
public static CommentResponseDto of(Comment comment, User user) {
return new CommentResponseDto(
comment.getCommentId(),
comment.getContent()
user.getUserId(),
user.getName(),
user.getProfileImage(),
comment.getContent(),
comment.getCreatedAt()
);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

import com.example.log4u.domain.comment.dto.response.CommentResponseDto;
import com.example.log4u.domain.comment.entity.Comment;

public interface CommentRepositoryCustom {

Slice<Comment> findByDiaryIdWithCursor(Long diaryId, Long cursorCommentId, Pageable pageable);
Slice<CommentResponseDto> findWithUserByDiaryId(Long diaryId, Long cursorCommentId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import org.springframework.data.domain.SliceImpl;
import org.springframework.stereotype.Repository;

import com.example.log4u.domain.comment.dto.response.CommentResponseDto;
import com.example.log4u.domain.comment.entity.Comment;
import com.example.log4u.domain.comment.entity.QComment;
import com.example.log4u.domain.user.entity.QUser;
import com.example.log4u.domain.user.entity.User;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;
Expand All @@ -21,19 +26,31 @@ public class CommentRepositoryImpl implements CommentRepositoryCustom {
private final JPAQueryFactory queryFactory;

@Override
public Slice<Comment> findByDiaryIdWithCursor(Long diaryId, Long cursorCommentId, Pageable pageable) {
List<Comment> result = queryFactory
.selectFrom(comment)
public Slice<CommentResponseDto> findWithUserByDiaryId(Long diaryId, Long cursorCommentId, Pageable pageable) {
QComment comment = QComment.comment;
QUser user = QUser.user;

List<Tuple> tuples = queryFactory
.select(comment, user)
.from(comment)
.join(user).on(comment.userId.eq(user.userId))
.where(
comment.diaryId.eq(diaryId),
cursorCommentId != null ? comment.commentId.lt(cursorCommentId) : null
)
.orderBy(comment.commentId.desc())
.limit(pageable.getPageSize() + 1) // 커서 기반 페이징
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();
List<Comment> content = hasNext ? result.subList(0, pageable.getPageSize()) : result;
boolean hasNext = tuples.size() > pageable.getPageSize();
List<CommentResponseDto> content = tuples.stream()
.limit(pageable.getPageSize())
.map(tuple -> {
Comment c = tuple.get(comment);
User u = tuple.get(user);
return CommentResponseDto.of(c, u);
})
.toList();

return new SliceImpl<>(content, pageable, hasNext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,10 @@ private Comment getComment(Long commentId) {
public PageResponse<CommentResponseDto> getCommentListByDiary(Long diaryId, Long cursorCommentId, int size) {
checkDiaryExists(diaryId);
Pageable pageable = PageRequest.of(0, size);
Slice<Comment> slice = commentRepository.findByDiaryIdWithCursor(diaryId, cursorCommentId, pageable);
Slice<CommentResponseDto> slice = commentRepository.findWithUserByDiaryId(diaryId, cursorCommentId, pageable);

List<CommentResponseDto> dtoList = slice.getContent().stream()
.map(CommentResponseDto::of)
.toList();

Long nextCursor = slice.hasNext() ? dtoList.getLast().commentId() : null;
return PageResponse.of(new SliceImpl<>(dtoList, pageable, slice.hasNext()), nextCursor);
Long nextCursor = slice.hasNext() ? slice.getContent().getLast().commentId() : null;
return PageResponse.of(slice, nextCursor);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -149,26 +150,26 @@ void getCommentsList_In_DiaryDetail_Success() {
int size = 5;
Long cursorCommentId = null;

List<Comment> commentList = CommentFixture.createCommentsListFixture(size + 1); // hasNext 판별 위해 +1
List<CommentResponseDto> dtoList = CommentFixture.createCommentDtos(size + 1);

Pageable pageable = PageRequest.of(0, size);
boolean hasNext = commentList.size() > size;
boolean hasNext = dtoList.size() > size;
List<CommentResponseDto> sliced = hasNext ? dtoList.subList(0, size) : dtoList;

List<Comment> sliced = hasNext ? commentList.subList(0, size) : commentList;
Slice<CommentResponseDto> slice = new SliceImpl<>(sliced, pageable, hasNext);

Slice<Comment> slice = new SliceImpl<>(sliced, pageable, hasNext);
given(commentRepository.findByDiaryIdWithCursor(diaryId, cursorCommentId, pageable))
given(commentRepository.findWithUserByDiaryId(diaryId, cursorCommentId, pageable))
.willReturn(slice);

// when
PageResponse<CommentResponseDto> response = commentService.getCommentListByDiary(diaryId, cursorCommentId,
size);
PageResponse<CommentResponseDto> response = commentService.getCommentListByDiary(diaryId, cursorCommentId, size);

// then
assertThat(response.list()).hasSize(sliced.size());
assertThat(response.pageInfo().hasNext()).isEqualTo(hasNext);
assertThat(response.pageInfo().nextCursor()).isEqualTo(hasNext ? sliced.getLast().getCommentId() : null);
assertThat(response.pageInfo().nextCursor()).isEqualTo(hasNext ? sliced.getLast().commentId() : null);

verify(commentRepository).findByDiaryIdWithCursor(diaryId, cursorCommentId, pageable);
verify(commentRepository).findWithUserByDiaryId(diaryId, cursorCommentId, pageable);
}

}
15 changes: 15 additions & 0 deletions src/test/java/com/example/log4u/fixture/CommentFixture.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.example.log4u.fixture;

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

import com.example.log4u.domain.comment.dto.response.CommentResponseDto;
import com.example.log4u.domain.comment.entity.Comment;

public class CommentFixture {
Expand Down Expand Up @@ -34,4 +37,16 @@ public static List<Comment> createCommentsListFixture(int count) {
}
return comments;
}

public static List<CommentResponseDto> createCommentDtos(int size) {
return IntStream.rangeClosed(1, size)
.mapToObj(i -> new CommentResponseDto(
(long) i,
(long) i,
"사용자" + i,
"https://cdn.example.com/user" + i + ".png",
"댓글 " + i,
LocalDateTime.now().minusMinutes(i) // createdAt
)).toList();
}
}