Skip to content
2 changes: 1 addition & 1 deletion api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dependencies {
implementation(project(":client"))
implementation(project(":in-message"))
implementation(project(":out-message"))
implementation(project(":client"))
implementation(project(":storage"))
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-websocket")
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/kotlin/gloddy/GloddyChatApplication.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gloddy.api
package gloddy

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
Expand Down
25 changes: 25 additions & 0 deletions api/src/main/kotlin/gloddy/controller/GroupChatQueryController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gloddy.controller

import gloddy.groupChat.GroupChatMessage
import gloddy.groupChat.service.GroupChatCommander
import gloddy.groupChat.service.GroupChatReader
import gloddy.util.CursorRequest
import gloddy.util.PageCursor
import org.springframework.web.bind.annotation.*

@RestController
class GroupChatQueryController(
private val groupChatReader: GroupChatReader,
private val groupChatCommander: GroupChatCommander
) {

@GetMapping("/group-chat-messages/{groupId}")
fun getGroupChatMessagesByCursor(
@PathVariable("groupId") groupId: Long,
userId: Long,
@RequestBody(required = false) cursorRequest: CursorRequest
): PageCursor<GroupChatMessage> {

return groupChatReader.getMessagesByCursor(groupId, userId, cursorRequest)
}
}
2 changes: 1 addition & 1 deletion api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ spring:
- application-client.yml
- application-aws-credentials.yml
- application-in-message.yml
- application-out-message
- application-out-message.yml
4 changes: 4 additions & 0 deletions domain/src/main/kotlin/gloddy/core/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ enum class ErrorCode(

//GroupChatMessage
GROUP_CHAT_MESSAGE_NOT_FOUND(404, "GROUP_CHAT_003", "그룹 채팅 메시지를 찾을 수 없습니다."),

//GroupChatUser
GROUP_CHAT_USER_NOT_FOUND(404, "GROUP_CHAT_USER_005", "유저를 찾을 수 없습니다.")

}
6 changes: 6 additions & 0 deletions domain/src/main/kotlin/gloddy/groupChat/GroupChatException.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ class GroupChatMessageNotFoundException : GloddyChatException(
statusCode = ErrorCode.GROUP_CHAT_MESSAGE_NOT_FOUND.statusCode,
errorCode = ErrorCode.GROUP_CHAT_MESSAGE_NOT_FOUND.errorCode,
message = ErrorCode.GROUP_CHAT_MESSAGE_NOT_FOUND.message
)

class GroupChatUserNotFoundException : GloddyChatException(
statusCode = ErrorCode.GROUP_CHAT_USER_NOT_FOUND.statusCode,
errorCode = ErrorCode.GROUP_CHAT_USER_NOT_FOUND.errorCode,
message = ErrorCode.GROUP_CHAT_USER_NOT_FOUND.message
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gloddy.groupChat.dto.command

import gloddy.util.CursorRequest
import java.util.*

data class GroupChatGetMessageCommand(
val groupId: Long,
val cursorRequest: CursorRequest
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package gloddy.groupChat.repository

import gloddy.groupChat.GroupChatMessage
import gloddy.util.CursorRequest
import java.time.LocalDateTime

interface GroupChatQueryRepository {
fun findWithoutKey(groupId: Long, createdAt: LocalDateTime): List<GroupChatMessage>

fun findWithKey(groupId: Long, cursorRequest: CursorRequest): List<GroupChatMessage>
fun findUserCreatedAtById(userId: Long): LocalDateTime
}
29 changes: 29 additions & 0 deletions domain/src/main/kotlin/gloddy/groupChat/service/GroupChatReader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package gloddy.groupChat.service

import gloddy.groupChat.GroupChatMessage
import gloddy.groupChat.repository.GroupChatQueryRepository
import gloddy.util.CursorRequest
import gloddy.util.PageCursor
import org.springframework.stereotype.Service

@Service
class GroupChatReader(private val groupChatQueryRepository: GroupChatQueryRepository) {

fun getMessagesByCursor(groupId: Long, userId: Long, cursorRequest: CursorRequest): PageCursor<GroupChatMessage> {
var messages = findAll(groupId, userId, cursorRequest)
var nextKey = messages.stream()
.mapToLong(GroupChatMessage::sequenceId)
.min()
.orElse(CursorRequest.NONE_KEY)
return PageCursor(cursorRequest.next(nextKey), messages.size, messages)
}

private fun findAll(groupId: Long, userId: Long, cursorRequest: CursorRequest): List<GroupChatMessage> {
return if (cursorRequest.hasKey()) {
groupChatQueryRepository.findWithKey(groupId, cursorRequest)
} else {
val createdAt = groupChatQueryRepository.findUserCreatedAtById(userId)
groupChatQueryRepository.findWithoutKey(groupId, createdAt)
}
}
}
18 changes: 18 additions & 0 deletions domain/src/main/kotlin/gloddy/util/CursorRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gloddy.util


data class CursorRequest(
val key: Long?
) {
companion object {
const val NONE_KEY: Long = -1L
}

fun hasKey(): Boolean {
return key != null
}

fun next(key: Long?): CursorRequest {
return CursorRequest(key)
}
}
7 changes: 7 additions & 0 deletions domain/src/main/kotlin/gloddy/util/PageCursor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gloddy.util

data class PageCursor<T>(
val nextCursorRequest: CursorRequest,
val size: Int,
val body: List<T>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package gloddy.adapter

import gloddy.groupChat.GroupChatMessage
import gloddy.groupChat.GroupChatUserNotFoundException
import gloddy.groupChat.repository.GroupChatQueryRepository
import gloddy.persistence.repository.GroupChatMessageJpaRepository
import gloddy.persistence.repository.GroupChatUserJpaRepository
import gloddy.persistence.util.toDomain
import gloddy.util.CursorRequest
import org.springframework.stereotype.Component
import java.time.LocalDateTime

@Component
class GroupChatQueryAdapterRepository(
private val groupChatMessageJpaRepository: GroupChatMessageJpaRepository,
private val groupChatUserJpaRepository: GroupChatUserJpaRepository,
private val groupChatCommandAdapterRepository: GroupChatCommandAdapterRepository
) : GroupChatQueryRepository {

override fun findWithoutKey(groupId: Long, createdAt: LocalDateTime): List<GroupChatMessage> {
val groupChat = groupChatCommandAdapterRepository.findByGroupId(groupId)
return groupChatMessageJpaRepository.findAllByChatIdAndOrderByIdDesc(
createdAt,
groupChat.id
).map { it.toDomain() }
}

override fun findWithKey(groupId: Long, cursorRequest: CursorRequest): List<GroupChatMessage> {
val groupChat = groupChatCommandAdapterRepository.findByGroupId(groupId)
return groupChatMessageJpaRepository.findAllByLessThanIdAndChatIdAndOrderByIdDesc(
cursorRequest.key,
groupChat.id
).map { it.toDomain() }
}

override fun findUserCreatedAtById(userId: Long): LocalDateTime {
val found = groupChatUserJpaRepository.findByUserId(userId)
return found?.createdAt ?: throw GroupChatUserNotFoundException()
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,31 @@ package gloddy.persistence.repository

import gloddy.persistence.GroupChatMessageEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.UUID
import org.springframework.data.jpa.repository.Query
import java.time.LocalDateTime
import java.util.*

interface GroupChatMessageJpaRepository : JpaRepository<GroupChatMessageEntity, Long> {
fun findById(id: UUID): GroupChatMessageEntity?
fun findFirstByOrderBySequenceIdDesc(): GroupChatMessageEntity

@Query(
value = "SELECT m.* " +
"FROM group_chat_message AS m " +
"inner JOIN group_chat_user u " +
" ON u.user_id = m.user_id " +
"WHERE m.chat_id = :chatId and :createdAt < m.created_at and not m.type in ('SYSTEM_JOIN') " +
"ORDER BY m.sequence_id desc",
nativeQuery = true
)
fun findAllByChatIdAndOrderByIdDesc(createdAt: LocalDateTime, chatId: UUID): List<GroupChatMessageEntity>

@Query(
value = "SELECT * " +
"FROM group_chat_message m " +
"WHERE chat_id = :chatId and sequence_id < :sequenceId and not m.type in ('SYSTEM_JOIN') " +
"ORDER BY sequence_id desc",
nativeQuery = true
)
fun findAllByLessThanIdAndChatIdAndOrderByIdDesc(sequenceId: Long?, chatId: UUID): List<GroupChatMessageEntity>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package gloddy.persistence.repository

import gloddy.persistence.GroupChatUserEntity
import org.springframework.data.jpa.repository.JpaRepository
import java.util.UUID
import java.util.*

interface GroupChatUserJpaRepository : JpaRepository<GroupChatUserEntity, Long> {
fun findById(id: UUID): GroupChatUserEntity?
fun findFirstByOrderBySequenceIdDesc(): GroupChatUserEntity
fun findByUserId(userId: Long): GroupChatUserEntity?
}