Skip to content

Commit

Permalink
feat(chat) : 채팅메시지 조회 api 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
waterfogSW committed Feb 14, 2025
1 parent 5adcfac commit dd41bee
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
package com.threedays.bootstrap.api.chat.adapter.rest

import com.threedays.domain.chat.repository.MessageQueryRepository
import com.threedays.oas.api.ChatApi
import com.threedays.oas.model.GetChannelMessagesResponse
import com.threedays.oas.model.Message
import com.threedays.oas.model.MessageContent
import com.threedays.support.common.base.domain.UUIDTypeId
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import java.time.ZoneOffset
import java.util.*

@RestController
class ChatRestController
class ChatRestController(
private val messageQueryRepository: MessageQueryRepository
) : ChatApi {

override fun getChannelMessages(
channelId: UUID,
next: UUID?,
limit: Int
): ResponseEntity<GetChannelMessagesResponse> {
val (resultMessages, resultNext) = messageQueryRepository.scrollByChannelId(
channelId = UUIDTypeId.from(channelId),
next = next?.let { UUIDTypeId.from(it) },
limit = limit
)

return ResponseEntity.ok(createMessageResponse(resultMessages, resultNext))
}

private fun createMessageResponse(
messages: List<com.threedays.domain.chat.entity.Message>,
nextID: com.threedays.domain.chat.entity.Message.Id?,
): GetChannelMessagesResponse {
val messageResponse = messages.map {
Message(
id = it.id.value,
channelId = it.channelId.value,
senderUserId = it.senderUserId.value,

content = MessageContent(
text = when (it.content) {
is com.threedays.domain.chat.entity.Message.Content.Text -> (it.content as com.threedays.domain.chat.entity.Message.Content.Text).text
is com.threedays.domain.chat.entity.Message.Content.Card -> (it.content as com.threedays.domain.chat.entity.Message.Content.Card).text
},
cardColor = when (it.content) {
is com.threedays.domain.chat.entity.Message.Content.Card -> (it.content as com.threedays.domain.chat.entity.Message.Content.Card).color.name
else -> null
}
),
createdAt = it.createdAt.atOffset(ZoneOffset.UTC)
)
}
return GetChannelMessagesResponse(
messages = messageResponse,
next = nextID?.value
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.threedays.domain.chat.repository

import com.threedays.domain.chat.entity.Channel
import com.threedays.domain.chat.entity.Message
import com.threedays.support.common.base.domain.QueryRepository

interface MessageQueryRepository : QueryRepository<Message, Message.Id> {

fun scrollByChannelId(
channelId: Channel.Id,
next: Message.Id?,
limit: Int,
): Pair<List<Message>, Message.Id?>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.threedays.persistence.chat.adapter

import com.linecorp.kotlinjdsl.dsl.jpql.jpql
import com.linecorp.kotlinjdsl.querymodel.jpql.select.SelectQuery
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.createQuery
import com.threedays.domain.chat.entity.Channel
import com.threedays.domain.chat.entity.Message
import com.threedays.domain.chat.repository.MessageQueryRepository
import com.threedays.persistence.chat.entity.MessageJpaEntity
import com.threedays.persistence.chat.repository.MessageJpaRepository
import jakarta.persistence.EntityManager
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional

@Component
@Transactional(readOnly = true)
class MessageQueryPersistenceAdapter(
private val entityManager: EntityManager,
private val jdslRenderContext: RenderContext,
private val messageJpaRepository: MessageJpaRepository,
) : MessageQueryRepository {

override fun find(id: Message.Id): Message? {
return messageJpaRepository
.findById(id.value)
.map { it.toDomain() }
.orElse(null)
}

override fun scrollByChannelId(
channelId: Channel.Id,
next: Message.Id?,
limit: Int
): Pair<List<Message>, Message.Id?> {
val query: SelectQuery<MessageJpaEntity> = jpql {
select(
entity(MessageJpaEntity::class)
).from(
entity(MessageJpaEntity::class)
).whereAnd(
path(MessageJpaEntity::channelId).eq(channelId.value),
next?.let { path(MessageJpaEntity::id).greaterThanOrEqualTo(it.value) }
).orderBy(
path(MessageJpaEntity::id).desc()
)
}

val result: List<Message> = entityManager
.createQuery(query, jdslRenderContext)
.apply { maxResults = limit + 1 }
.resultList
.map { it.toDomain() }


val hasNextPage: Boolean = result.size > limit
val nextId: Message.Id? = if (hasNextPage) {
result[limit].id
} else {
null
}

return result.take(limit) to nextId
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CompanyQueryPersistenceAdapter(

val result: List<Company> = entityManager
.createQuery(query, jdslRenderContext)
.apply { setMaxResults(limit + 1) }
.apply { maxResults = limit + 1 }
.resultList
.map { it.toDomainEntity() }

Expand Down
2 changes: 1 addition & 1 deletion openapi
Submodule openapi updated 1 files
+18 −38 openapi.yaml

0 comments on commit dd41bee

Please sign in to comment.