From a0bd611ae5ea364b6a527e78a3ab51b92bb100cd Mon Sep 17 00:00:00 2001 From: Chanhyuk Yang Date: Tue, 5 Dec 2023 01:04:12 +0900 Subject: [PATCH] feat: feat pagination in get reactions API --- .../domain/emoji/service/EmojiService.kt | 10 +-- .../reaction/controller/ReactionController.kt | 6 +- .../reaction/service/ReactionService.kt | 32 ++++++++- .../emoji/controller/EmojiControllerTest.kt | 8 +-- .../post/controller/PostControllerTest.kt | 6 +- .../controller/ReactionControllerTest.kt | 17 +++-- .../reaction/service/ReactionServiceTest.kt | 67 +++++++++++++++---- 7 files changed, 111 insertions(+), 35 deletions(-) diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt index f788dd4c..02fabaea 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/emoji/service/EmojiService.kt @@ -60,12 +60,12 @@ class EmojiService( // sort if (emojiList.size != 0) { emojiList.sortByDescending { it.created_at } + // pagination + emojiList = emojiList.subList( + min((index - 1) * count, emojiList.size - 1), + min(index * count, emojiList.size) + ) } - // pagination - emojiList = emojiList.subList( - min((index - 1) * count, emojiList.size - 1), - min(index * count, emojiList.size) - ) } return emojiList } diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionController.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionController.kt index 50832673..d5f77bd4 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionController.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionController.kt @@ -14,8 +14,11 @@ class ReactionController(private val reactionService: ReactionService) { @GetMapping fun getReactionsOfPost( @RequestParam(value = "postId", defaultValue = "") postId: String, + @RequestParam(value = "emojiUnicode", defaultValue = "") emojiUnicode: String, + @RequestParam(value = "index", defaultValue = 1.toString()) index: Int, + @RequestParam(value = "count", defaultValue = 10.toString()) count: Int ): ResponseEntity> { - return ResponseEntity.ok(reactionService.getReactionsOfPost(postId)) + return ResponseEntity.ok(reactionService.getReactionsOfPost(postId, emojiUnicode, index, count)) } @PostMapping @@ -23,7 +26,6 @@ class ReactionController(private val reactionService: ReactionService) { @CurrentUser username: String, @RequestParam(value = "postId", defaultValue = "") postId: String, @RequestParam(value = "emojiId", defaultValue = "") emojiId: String - ): ResponseEntity { return ResponseEntity( reactionService.postReaction(username, postId, emojiId), HttpStatus.CREATED diff --git a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionService.kt b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionService.kt index 7afc98e0..c0eba922 100644 --- a/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionService.kt +++ b/springboot/src/main/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionService.kt @@ -5,8 +5,11 @@ import com.goliath.emojihub.springboot.domain.post.dao.PostDao import com.goliath.emojihub.springboot.domain.reaction.dao.ReactionDao import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto import com.goliath.emojihub.springboot.domain.user.dao.UserDao +import com.goliath.emojihub.springboot.global.exception.CustomHttp400 import com.goliath.emojihub.springboot.global.exception.CustomHttp403 import com.goliath.emojihub.springboot.global.exception.CustomHttp404 +import com.goliath.emojihub.springboot.global.exception.ErrorType.BadRequest.INDEX_OUT_OF_BOUND +import com.goliath.emojihub.springboot.global.exception.ErrorType.BadRequest.COUNT_OUT_OF_BOUND import com.goliath.emojihub.springboot.global.exception.ErrorType.Forbidden.USER_ALREADY_REACT import com.goliath.emojihub.springboot.global.exception.ErrorType.Forbidden.REACTION_DELETE_FORBIDDEN import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.POST_NOT_FOUND @@ -15,6 +18,7 @@ import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.EMOJI import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.REACTION_NOT_FOUND import com.goliath.emojihub.springboot.global.util.StringValue.ReactionField.POST_ID import org.springframework.stereotype.Service +import java.lang.Integer.min @Service class ReactionService( @@ -24,9 +28,31 @@ class ReactionService( private val emojiDao: EmojiDao ) { - fun getReactionsOfPost(postId: String): List { - if (!postDao.existPost(postId)) throw CustomHttp404(POST_NOT_FOUND) - return reactionDao.getReactionsWithField(postId, POST_ID.string) + fun getReactionsOfPost(postId: String, emojiUnicode: String, index: Int, count: Int): List { + if (index <= 0) throw CustomHttp400(INDEX_OUT_OF_BOUND) + if (count <= 0) throw CustomHttp400(COUNT_OUT_OF_BOUND) + val post = postDao.getPost(postId) ?: throw CustomHttp404(POST_NOT_FOUND) + if (emojiUnicode == "") { + return reactionDao.getReactionsWithField(postId, POST_ID.string) + } else { + var reactionList = mutableListOf() + for (reactionWithEmojiUnicode in post.reactions) { + if (reactionWithEmojiUnicode.emoji_unicode != emojiUnicode) + continue + val reaction = reactionDao.getReaction(reactionWithEmojiUnicode.id) ?: continue + reactionList.add(reaction) + } + // sort + if (reactionList.size != 0) { + reactionList.sortByDescending { it.created_at } + // pagination + reactionList = reactionList.subList( + min((index - 1) * count, reactionList.size - 1), + min(index * count, reactionList.size) + ) + } + return reactionList + } } fun postReaction(username: String, postId: String, emojiId: String) { diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt index 1cfcc570..29abae7e 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/emoji/controller/EmojiControllerTest.kt @@ -7,7 +7,7 @@ import com.goliath.emojihub.springboot.domain.emoji.dto.PostEmojiRequest import com.goliath.emojihub.springboot.domain.emoji.service.EmojiService import com.goliath.emojihub.springboot.global.util.StringValue.UserField.CREATED_EMOJIS import com.goliath.emojihub.springboot.global.util.StringValue.UserField.SAVED_EMOJIS -import org.hamcrest.Matchers +import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test import org.junit.jupiter.api.DisplayName @@ -64,7 +64,7 @@ internal class EmojiControllerTest @Autowired constructor( // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(emojiList.size))) + .andExpect(jsonPath("$.length()", equalTo(emojiList.size))) .andExpect(jsonPath("$[0].id").value(emojiList[0].id)) .andExpect(jsonPath("$[0].created_by").value(emojiList[0].created_by)) .andExpect(jsonPath("$[0].video_url").value(emojiList[0].video_url)) @@ -95,7 +95,7 @@ internal class EmojiControllerTest @Autowired constructor( // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(emojiList.size))) + .andExpect(jsonPath("$.length()", equalTo(emojiList.size))) .andExpect(jsonPath("$[0].id").value(emojiList[0].id)) .andExpect(jsonPath("$[0].created_by").value(emojiList[0].created_by)) .andExpect(jsonPath("$[0].video_url").value(emojiList[0].video_url)) @@ -126,7 +126,7 @@ internal class EmojiControllerTest @Autowired constructor( // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(emojiList.size))) + .andExpect(jsonPath("$.length()", equalTo(emojiList.size))) .andExpect(jsonPath("$[0].id").value(emojiList[0].id)) .andExpect(jsonPath("$[0].created_by").value(emojiList[0].created_by)) .andExpect(jsonPath("$[0].video_url").value(emojiList[0].video_url)) diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt index 977426e2..b5b12756 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/post/controller/PostControllerTest.kt @@ -6,7 +6,7 @@ import com.goliath.emojihub.springboot.domain.WithCustomUser import com.goliath.emojihub.springboot.domain.post.dto.PostDto import com.goliath.emojihub.springboot.domain.post.dto.PostRequest import com.goliath.emojihub.springboot.domain.post.service.PostService -import org.hamcrest.Matchers +import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test import org.junit.jupiter.api.DisplayName @@ -87,7 +87,7 @@ internal class PostControllerTest @Autowired constructor( // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(postList.size))) + .andExpect(jsonPath("$.length()", equalTo(postList.size))) .andExpect(jsonPath("$[0].id").value(postList[0].id)) .andExpect(jsonPath("$[0].created_by").value(postList[0].created_by)) .andExpect(jsonPath("$[0].content").value(postList[0].content)) @@ -123,7 +123,7 @@ internal class PostControllerTest @Autowired constructor( // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(posts.size))) + .andExpect(jsonPath("$.length()", equalTo(posts.size))) .andExpect(jsonPath("$[0].id").value(posts[0].id)) .andExpect(jsonPath("$[0].created_by").value(posts[0].created_by)) .andExpect(jsonPath("$[0].content").value(posts[0].content)) diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionControllerTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionControllerTest.kt index 113dab5b..1b04d930 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionControllerTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/controller/ReactionControllerTest.kt @@ -4,7 +4,7 @@ import com.goliath.emojihub.springboot.domain.TestDto import com.goliath.emojihub.springboot.domain.WithCustomUser import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto import com.goliath.emojihub.springboot.domain.reaction.service.ReactionService -import org.hamcrest.Matchers +import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test import org.junit.jupiter.api.DisplayName @@ -38,31 +38,38 @@ internal class ReactionControllerTest @Autowired constructor( @DisplayName("게시글의 리액션 가져오기 테스트") fun getReactionsOfPost() { // given - val postId = reactionList[0].post_id + val post = testDto.postList[0] + val postId = post.id + val emojiUnicode = "" + val index = 1 + val count = 10 val reactions = mutableListOf() for (reaction in reactionList) { if (reaction.post_id == postId) { reactions.add(reaction) } } - Mockito.`when`(reactionService.getReactionsOfPost(postId)).thenReturn(reactions) + Mockito.`when`(reactionService.getReactionsOfPost(postId, emojiUnicode, index, count)).thenReturn(reactions) // when val result = this.mockMvc.perform( get("/api/reaction") .param("postId", postId) + .param("emojiUnicode", emojiUnicode) + .param("index", index.toString()) + .param("count", count.toString()) ) // then result.andExpect(status().isOk) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()", Matchers.equalTo(reactions.size))) + .andExpect(jsonPath("$.length()", equalTo(reactions.size))) .andExpect(jsonPath("$[0].id").value(reactions[0].id)) .andExpect(jsonPath("$[0].created_by").value(reactions[0].created_by)) .andExpect(jsonPath("$[0].post_id").value(reactions[0].post_id)) .andExpect(jsonPath("$[0].emoji_id").value(reactions[0].emoji_id)) .andExpect(jsonPath("$[0].created_at").value(reactions[0].created_at)) - verify(reactionService, times(1)).getReactionsOfPost(postId) + verify(reactionService, times(1)).getReactionsOfPost(postId, emojiUnicode, index, count) } @Test diff --git a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionServiceTest.kt b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionServiceTest.kt index dcb89fd3..4965af09 100644 --- a/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionServiceTest.kt +++ b/springboot/src/test/kotlin/com/goliath/emojihub/springboot/domain/reaction/service/ReactionServiceTest.kt @@ -6,8 +6,11 @@ import com.goliath.emojihub.springboot.domain.post.dao.PostDao import com.goliath.emojihub.springboot.domain.reaction.dao.ReactionDao import com.goliath.emojihub.springboot.domain.reaction.dto.ReactionDto import com.goliath.emojihub.springboot.domain.user.dao.UserDao +import com.goliath.emojihub.springboot.global.exception.CustomHttp400 import com.goliath.emojihub.springboot.global.exception.CustomHttp403 import com.goliath.emojihub.springboot.global.exception.CustomHttp404 +import com.goliath.emojihub.springboot.global.exception.ErrorType.BadRequest.INDEX_OUT_OF_BOUND +import com.goliath.emojihub.springboot.global.exception.ErrorType.BadRequest.COUNT_OUT_OF_BOUND import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.USER_NOT_FOUND import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.POST_NOT_FOUND import com.goliath.emojihub.springboot.global.exception.ErrorType.NotFound.EMOJI_NOT_FOUND @@ -55,32 +58,70 @@ internal class ReactionServiceTest { @DisplayName("게시글의 리액션 가져오기") fun getReactionsOfPost() { // given - val postId = testDto.postList[0].id + val post = testDto.postList[0] + val postId = post.id + val index = 1 + val wrongIndex = 0 + val count = 10 + val wrongCount = 0 + val emojiUnicodeAll = "" + val emojiUnicodeSpecific = if (post.reactions.size != 0) post.reactions[0].emoji_unicode else "" val wrongId = "wrong_post_id" - val reactions = mutableListOf() - Mockito.`when`(postDao.existPost(postId)).thenReturn(true) - Mockito.`when`(postDao.existPost(wrongId)).thenReturn(false) + val reactionsAll = mutableListOf() + var reactionsSpecific = mutableListOf() + Mockito.`when`(postDao.getPost(postId)).thenReturn(post) + Mockito.`when`(postDao.getPost(wrongId)).thenReturn(null) + for (reactionWithEmojiUnicode in post.reactions) { + if (reactionWithEmojiUnicode.emoji_unicode != emojiUnicodeSpecific) continue + for (reaction in testDto.reactionList) { + if (reaction.id != reactionWithEmojiUnicode.id) continue + reactionsSpecific.add(reaction) + } + } for (reaction in testDto.reactionList) { if (reaction.post_id == postId) { - reactions.add(reaction) + reactionsAll.add(reaction) } } - Mockito.`when`(reactionDao.getReactionsWithField(postId, POST_ID.string)).thenReturn(reactions) + if (reactionsSpecific.size != 0) { + reactionsSpecific.sortByDescending { it.created_at } + reactionsSpecific = reactionsSpecific.subList( + Integer.min((index - 1) * count, reactionsSpecific.size - 1), + Integer.min(index * count, reactionsSpecific.size) + ) + } + Mockito.`when`(reactionDao.getReactionsWithField(postId, POST_ID.string)).thenReturn(reactionsAll) + for (reaction in reactionsSpecific) { + Mockito.`when`(reactionDao.getReaction(reaction.id)).thenReturn(reaction) + } // when - val result = reactionService.getReactionsOfPost(postId) - val assertThrows = assertThrows(CustomHttp404::class.java) { - reactionService.getReactionsOfPost(wrongId) + val result1 = reactionService.getReactionsOfPost(postId, emojiUnicodeAll, index, count) + val result2 = reactionService.getReactionsOfPost(postId, emojiUnicodeSpecific, index, count) + val assertThrows1 = assertThrows(CustomHttp400::class.java) { + reactionService.getReactionsOfPost(postId, emojiUnicodeAll, wrongIndex, count) + } + val assertThrows2 = assertThrows(CustomHttp400::class.java) { + reactionService.getReactionsOfPost(postId, emojiUnicodeAll, index, wrongCount) + } + val assertThrows3 = assertThrows(CustomHttp404::class.java) { + reactionService.getReactionsOfPost(wrongId, emojiUnicodeAll, index, count) } // then assertAll( - { assertEquals(result, reactions) }, - { assertEquals(assertThrows.message, POST_NOT_FOUND.getMessage()) } + { assertEquals(result1, reactionsAll) }, + { assertEquals(result2, reactionsSpecific) }, + { assertEquals(assertThrows1.message, INDEX_OUT_OF_BOUND.getMessage()) }, + { assertEquals(assertThrows2.message, COUNT_OUT_OF_BOUND.getMessage()) }, + { assertEquals(assertThrows3.message, POST_NOT_FOUND.getMessage()) }, ) - verify(postDao, times(1)).existPost(postId) - verify(postDao, times(1)).existPost(wrongId) + verify(postDao, times(2)).getPost(postId) + verify(postDao, times(1)).getPost(wrongId) verify(reactionDao, times(1)).getReactionsWithField(postId, POST_ID.string) + for (reaction in reactionsSpecific) { + verify(reactionDao, times(1)).getReaction(reaction.id) + } } @Test