Skip to content

Commit 27fd21b

Browse files
authored
fix: PostRepository & CommentRepository의 일부 메서드의 정렬 순서 오류 해결 (#522)
* fix: 보드와 카테고리에 따른 포스트 조회 메서드 정렬 문제 해결 * test: 보드와 카테고리에 따른 포스트 조회 메서드 정렬 문제 해결 - 테스트 코드 수정 * fix: 코멘트 트리 조회 메서드 정렬 문제 해결 * test: 코멘트 트리 조회 메서드 정렬 문제 해결 - 테스트 코드 수정 * style: PostRepository 메서드명 변경 findByBoardCodeExcludingBlockedUsers -> findByBoardCodeExcludingBlockedUsersOrderByCreatedAtDesc * chore: todo 메세지 제거 * chore: 디버그 코드 제거 * test: 내림차순 정렬 검증이 비결정적일 수 있는 문제 수정 * Revert "chore : debug code delete" This reverts commit 5540b44. * refactor: 테스트 코드가 프로덕션 코드에게 영향 미치지 않게 reflaction 방식으로 createdAt 설정 메서드 구현 * refactor: 테스트 코드가 프로덕션 코드에게 영향 미치지 않게 TestTimeHelper 코드를 적용한 방식으로 Fixture 변경 * test: Comment 조회 메서드에 대한 순서 정렬 테스트 코드 추가 변경된 메서드: - 게시글의_모든_댓글과_대댓글을_생성시간_기준으로_정렬해_조회한다 * test: 게시판 조회 메서드에 대한 순서 정렬 테스트 코드 추가 변경된 메서드: - 게시판_코드와_카테고리로_게시글_목록을_최신순으로_조회한다 * test: 차단한 사용자 제외 댓글들 조회 메서드에 대한 순서 정렬 테스트 코드 추가 변경된 메서드: - 차단한_사용자의_댓글은_제외된다 * fix: rebase로 인한 테스트 코드 오류 수정 변경된 메서드: - 게시판_코드와_카테고리로_게시글_목록을_최신순으로_조회한다 * test: import 구문 정리 & 디버깅 코드 제거 * refactor: 중복 동작 로직 제거 제거된 메서드: - setPostAndSiteUserId * test: 중복 검증 로직 제거 제거된 검증: - filteredOn에 의해 검증된 comment.Id 값을 다시 한 번 검증하는 isEqualTo(comment.getId())로직 * test: 컨벤션에 맞춘 와일드 카드 정리 * test: 차단된 경우에서 순서 유지 검증하는 테스트 추가 추가된 메서드: - 차단한_사용자의_게시글은_제외하고_게시글_목록을_최신순으로_조회한다 * chore: code reformatting 적용
1 parent 17aa696 commit 27fd21b

File tree

11 files changed

+231
-74
lines changed

11 files changed

+231
-74
lines changed

src/main/java/com/example/solidconnection/community/board/controller/BoardController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public ResponseEntity<?> findPostsByCodeAndCategory(
3737
@PathVariable(value = "code") String code,
3838
@RequestParam(value = "category", defaultValue = "전체") String category) {
3939
List<PostListResponse> postsByCodeAndPostCategory = postQueryService
40-
.findPostsByCodeAndPostCategory(code, category, siteUserId);
40+
.findPostsByCodeAndPostCategoryOrderByCreatedAtDesc(code, category, siteUserId);
4141
return ResponseEntity.ok().body(postsByCodeAndPostCategory);
4242
}
4343
}

src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@
1212
public interface CommentRepository extends JpaRepository<Comment, Long> {
1313

1414
@Query(value = """
15-
WITH RECURSIVE CommentTree AS (
16-
SELECT
17-
id, parent_id, post_id, site_user_id, content,
18-
created_at, updated_at, is_deleted,
19-
0 AS level, CAST(id AS CHAR(255)) AS path
20-
FROM comment
21-
WHERE post_id = :postId AND parent_id IS NULL
22-
AND site_user_id NOT IN (
23-
SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId
24-
)
25-
UNION ALL
26-
SELECT
27-
c.id, c.parent_id, c.post_id, c.site_user_id, c.content,
28-
c.created_at, c.updated_at, c.is_deleted,
29-
ct.level + 1, CONCAT(ct.path, '->', c.id)
30-
FROM comment c
31-
INNER JOIN CommentTree ct ON c.parent_id = ct.id
32-
WHERE c.site_user_id NOT IN (
33-
SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId
34-
)
35-
)
36-
SELECT * FROM CommentTree
37-
ORDER BY path
38-
""", nativeQuery = true)
15+
WITH RECURSIVE CommentTree AS (
16+
SELECT
17+
id, parent_id, post_id, site_user_id, content,
18+
created_at, updated_at, is_deleted,
19+
0 AS level, CAST(id AS CHAR(255)) AS path
20+
FROM comment
21+
WHERE post_id = :postId AND parent_id IS NULL
22+
AND site_user_id NOT IN (
23+
SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId
24+
)
25+
UNION ALL
26+
SELECT
27+
c.id, c.parent_id, c.post_id, c.site_user_id, c.content,
28+
c.created_at, c.updated_at, c.is_deleted,
29+
ct.level + 1, CONCAT(ct.path, '->', c.id)
30+
FROM comment c
31+
INNER JOIN CommentTree ct ON c.parent_id = ct.id
32+
WHERE c.site_user_id NOT IN (
33+
SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId
34+
)
35+
)
36+
SELECT * FROM CommentTree
37+
ORDER BY path, created_at
38+
""", nativeQuery = true)
3939
List<Comment> findCommentTreeByPostIdExcludingBlockedUsers(@Param("postId") Long postId, @Param("siteUserId") Long siteUserId);
4040

4141
default Comment getById(Long id) {

src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@
1414

1515
public interface PostRepository extends JpaRepository<Post, Long> {
1616

17-
List<Post> findByBoardCode(String boardCode);
17+
List<Post> findByBoardCodeOrderByCreatedAtDesc(String boardCode);
1818

1919
@Query("""
20-
SELECT p FROM Post p
21-
WHERE p.boardCode = :boardCode
22-
AND p.siteUserId NOT IN (
23-
SELECT ub.blockedId FROM UserBlock ub WHERE ub.blockerId = :siteUserId
24-
)
25-
""")
26-
List<Post> findByBoardCodeExcludingBlockedUsers(@Param("boardCode") String boardCode, @Param("siteUserId") Long siteUserId);
20+
SELECT p FROM Post p
21+
WHERE p.boardCode = :boardCode
22+
AND p.siteUserId NOT IN (
23+
SELECT ub.blockedId FROM UserBlock ub WHERE ub.blockerId = :siteUserId
24+
)
25+
ORDER BY p.createdAt DESC
26+
""")
27+
List<Post> findByBoardCodeExcludingBlockedUsersOrderByCreatedAtDesc(@Param("boardCode") String boardCode, @Param("siteUserId") Long siteUserId);
2728

2829
@EntityGraph(attributePaths = {"postImageList"})
2930
Optional<Post> findPostById(Long id);

src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,17 @@ public class PostQueryService {
4646
private final RedisUtils redisUtils;
4747

4848
@Transactional(readOnly = true)
49-
public List<PostListResponse> findPostsByCodeAndPostCategory(String code, String category, Long siteUserId) {
49+
public List<PostListResponse> findPostsByCodeAndPostCategoryOrderByCreatedAtDesc(String code, String category, Long siteUserId) {
5050

5151
String boardCode = validateCode(code);
5252
PostCategory postCategory = validatePostCategory(category);
5353
boardRepository.getByCode(boardCode);
5454

55-
List<Post> postList; // todo : 추후 개선 필요(현재 최신순으로 응답나가지 않고 있음)
55+
List<Post> postList;
5656
if (siteUserId != null) {
57-
postList = postRepository.findByBoardCodeExcludingBlockedUsers(boardCode, siteUserId);
57+
postList = postRepository.findByBoardCodeExcludingBlockedUsersOrderByCreatedAtDesc(boardCode, siteUserId);
5858
} else {
59-
postList = postRepository.findByBoardCode(boardCode);
59+
postList = postRepository.findByBoardCodeOrderByCreatedAtDesc(boardCode);
6060
}
6161
return PostListResponse.from(getPostListByPostCategory(postList, postCategory));
6262
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.example.solidconnection.common.helper;
2+
3+
import com.example.solidconnection.common.BaseEntity;
4+
import java.lang.reflect.Field;
5+
import java.time.ZonedDateTime;
6+
import java.time.temporal.ChronoUnit;
7+
8+
public class TestTimeHelper {
9+
10+
public static void setCreatedAt(BaseEntity entity, ZonedDateTime time) {
11+
try {
12+
Field field = BaseEntity.class.getDeclaredField("createdAt");
13+
field.setAccessible(true);
14+
field.set(entity, time.truncatedTo(ChronoUnit.MICROS));
15+
} catch (Exception e) {
16+
throw new RuntimeException(e);
17+
}
18+
}
19+
}

src/test/java/com/example/solidconnection/community/comment/fixture/CommentFixture.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,19 @@ public class CommentFixture {
3232
.parentComment(parentComment)
3333
.createChild();
3434
}
35+
36+
public Comment 자식_댓글_지연저장(
37+
String content,
38+
Post post,
39+
SiteUser siteUser,
40+
Comment parentComment,
41+
long secondsDelay
42+
) {
43+
return commentFixtureBuilder
44+
.content(content)
45+
.post(post)
46+
.siteUser(siteUser)
47+
.parentComment(parentComment)
48+
.createChildWithDelaySeconds(secondsDelay);
49+
}
3550
}

src/test/java/com/example/solidconnection/community/comment/fixture/CommentFixtureBuilder.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.example.solidconnection.community.comment.fixture;
22

3+
import com.example.solidconnection.common.helper.TestTimeHelper;
34
import com.example.solidconnection.community.comment.domain.Comment;
45
import com.example.solidconnection.community.comment.repository.CommentRepository;
56
import com.example.solidconnection.community.post.domain.Post;
@@ -46,8 +47,18 @@ public Comment createParent() {
4647

4748
public Comment createChild() {
4849
Comment comment = new Comment(content);
49-
comment.setPostAndSiteUserId(post, siteUser.getId());
5050
comment.setParentCommentAndPostAndSiteUserId(parentComment, post, siteUser.getId());
5151
return commentRepository.save(comment);
5252
}
53+
54+
public Comment createChildWithDelaySeconds(long seconds) {
55+
Comment comment = new Comment(content);
56+
comment.setParentCommentAndPostAndSiteUserId(parentComment, post, siteUser.getId());
57+
58+
Comment saved = commentRepository.save(comment);
59+
60+
TestTimeHelper.setCreatedAt(saved, saved.getCreatedAt().plusSeconds(seconds));
61+
62+
return commentRepository.save(saved);
63+
}
5364
}

src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -82,34 +82,55 @@ void setUp() {
8282
class 댓글_조회_테스트 {
8383

8484
@Test
85-
void 게시글의_모든_댓글을_조회한다() {
85+
void 게시글의_모든_댓글과_대댓글을_생성시간_기준으로_정렬해_조회한다() {
8686
// given
8787
Comment parentComment = commentFixture.부모_댓글("부모 댓글", post, user1);
88-
Comment childComment = commentFixture.자식_댓글("자식 댓글 1", post, user2, parentComment);
89-
List<Comment> comments = List.of(parentComment, childComment);
88+
Comment childComment1 = commentFixture.자식_댓글("자식 댓글 1", post, user2, parentComment);
89+
Comment childComment2 = commentFixture.자식_댓글_지연저장("자식 댓글 2", post, user1, parentComment, 3);
90+
Comment childComment3 = commentFixture.자식_댓글_지연저장("자식 댓글 3", post, user2, parentComment, 5);
91+
List<Comment> comments = List.of(parentComment, childComment1, childComment2, childComment3);
9092

9193
// when
9294
List<PostFindCommentResponse> responses = commentService.findCommentsByPostId(user1.getId(), post.getId());
9395

9496
// then
9597
assertAll(
96-
() -> assertThat(responses).hasSize(comments.size()),
9798
() -> assertThat(responses)
9899
.filteredOn(response -> response.id().equals(parentComment.getId()))
99100
.singleElement()
100101
.satisfies(response -> assertAll(
101-
() -> assertThat(response.id()).isEqualTo(parentComment.getId()),
102102
() -> assertThat(response.parentId()).isNull(),
103103
() -> assertThat(response.isOwner()).isTrue()
104104
)),
105105
() -> assertThat(responses)
106-
.filteredOn(response -> response.id().equals(childComment.getId()))
106+
.filteredOn(response -> response.id().equals(childComment1.getId()))
107107
.singleElement()
108108
.satisfies(response -> assertAll(
109-
() -> assertThat(response.id()).isEqualTo(childComment.getId()),
110109
() -> assertThat(response.parentId()).isEqualTo(parentComment.getId()),
111110
() -> assertThat(response.isOwner()).isFalse()
112-
))
111+
)),
112+
() -> assertThat(responses)
113+
.filteredOn(response -> response.id().equals(childComment2.getId()))
114+
.singleElement()
115+
.satisfies(response -> assertAll(
116+
() -> assertThat(response.parentId()).isEqualTo(parentComment.getId()),
117+
() -> assertThat(response.isOwner()).isTrue()
118+
)),
119+
() -> assertThat(responses)
120+
.filteredOn(response -> response.id().equals(childComment3.getId()))
121+
.singleElement()
122+
.satisfies(response -> assertAll(
123+
() -> assertThat(response.parentId()).isEqualTo(parentComment.getId()),
124+
() -> assertThat(response.isOwner()).isFalse()
125+
)),
126+
() -> assertThat(responses)
127+
.extracting(PostFindCommentResponse::id)
128+
.containsExactly(
129+
parentComment.getId(),
130+
childComment1.getId(),
131+
childComment2.getId(),
132+
childComment3.getId()
133+
)
113134
);
114135
}
115136

@@ -198,24 +219,27 @@ class 댓글_조회_테스트 {
198219
userBlockFixture.유저_차단(user1.getId(), user2.getId());
199220
Comment parentComment1 = commentFixture.부모_댓글("부모 댓글1", post, user1);
200221
Comment childComment1 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentComment1);
201-
Comment childComment2 = commentFixture.자식_댓글("자식 댓글2", post, user2, parentComment1);
202-
Comment parentCommen2 = commentFixture.부모_댓글("부모 댓글2", post, user2);
203-
Comment childComment3 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentCommen2);
204-
Comment childComment4 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentCommen2);
205-
222+
Comment childComment2 = commentFixture.자식_댓글_지연저장("자식 댓글2", post, user2, parentComment1, 2);
223+
Comment childComment3 = commentFixture.자식_댓글_지연저장("자식 댓글3", post, user1, parentComment1, 3);
224+
Comment parentComment2 = commentFixture.부모_댓글("부모 댓글2", post, user2);
225+
Comment childComment4 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentComment2);
226+
Comment childComment5 = commentFixture.자식_댓글_지연저장("자식 댓글1", post, user1, parentComment2, 2);
206227

207228
// when
208229
List<PostFindCommentResponse> responses = commentService.findCommentsByPostId(user1.getId(), post.getId());
209230

210231
// then
211232
assertAll(
212-
() -> assertThat(responses).hasSize(2),
213-
() -> assertThat(responses)
214-
.extracting(PostFindCommentResponse::id)
215-
.containsExactly(parentComment1.getId(), childComment1.getId()),
216-
() -> assertThat(responses)
217-
.extracting(PostFindCommentResponse::id)
218-
.doesNotContain(childComment2.getId(), parentCommen2.getId(), childComment3.getId(), childComment4.getId())
233+
() -> assertThat(responses).hasSize(3),
234+
() -> assertThat(responses)
235+
.extracting(PostFindCommentResponse::id)
236+
.containsExactly(parentComment1.getId(), childComment1.getId(), childComment3.getId()),
237+
() -> assertThat(responses)
238+
.extracting(PostFindCommentResponse::id)
239+
.doesNotContain(childComment2.getId(), parentComment2.getId(), childComment4.getId(), childComment5.getId()),
240+
() -> assertThat(responses)
241+
.extracting(PostFindCommentResponse::id)
242+
.containsSubsequence(parentComment1.getId(), childComment1.getId(), childComment3.getId())
219243
);
220244
}
221245
}

src/test/java/com/example/solidconnection/community/post/fixture/PostFixture.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,25 @@ public class PostFixture {
4747
.siteUser(siteUser)
4848
.create();
4949
}
50+
51+
public Post 게시글_지연저장(
52+
String title,
53+
String content,
54+
Boolean isQuestion,
55+
PostCategory postCategory,
56+
Board board,
57+
SiteUser siteUser,
58+
long secondsDelay
59+
) {
60+
return postFixtureBuilder
61+
.title(title)
62+
.content(content)
63+
.isQuestion(isQuestion)
64+
.likeCount(0L)
65+
.viewCount(0L)
66+
.postCategory(postCategory)
67+
.board(board)
68+
.siteUser(siteUser)
69+
.createWithDelaySeconds(secondsDelay);
70+
}
5071
}

src/test/java/com/example/solidconnection/community/post/fixture/PostFixtureBuilder.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.example.solidconnection.community.post.fixture;
22

3+
import com.example.solidconnection.common.helper.TestTimeHelper;
34
import com.example.solidconnection.community.board.domain.Board;
45
import com.example.solidconnection.community.post.domain.Post;
56
import com.example.solidconnection.community.post.domain.PostCategory;
@@ -74,4 +75,20 @@ public Post create() {
7475
post.setBoardAndSiteUserId(board.getCode(), siteUser.getId());
7576
return postRepository.save(post);
7677
}
78+
79+
public Post createWithDelaySeconds(long seconds) {
80+
Post post = new Post(
81+
title,
82+
content,
83+
isQuestion,
84+
likeCount,
85+
viewCount,
86+
postCategory);
87+
post.setBoardAndSiteUserId(board.getCode(), siteUser.getId());
88+
89+
Post saved = postRepository.save(post);
90+
91+
TestTimeHelper.setCreatedAt(saved, saved.getCreatedAt().plusSeconds(seconds));
92+
return postRepository.save(post);
93+
}
7794
}

0 commit comments

Comments
 (0)