feat: クエリ実行結果とのマッピングをクラスに切り出し

This commit is contained in:
usbharu 2023-10-23 13:15:28 +09:00
parent e869fad11d
commit 6155e61285
7 changed files with 76 additions and 9 deletions

View File

@ -4,27 +4,32 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Post
import dev.usbharu.hideout.exception.FailedToGetResourcesException import dev.usbharu.hideout.exception.FailedToGetResourcesException
import dev.usbharu.hideout.repository.Posts import dev.usbharu.hideout.repository.Posts
import dev.usbharu.hideout.repository.PostsMedia import dev.usbharu.hideout.repository.PostsMedia
import dev.usbharu.hideout.repository.toPost import dev.usbharu.hideout.repository.QueryMapper
import dev.usbharu.hideout.repository.ResultRowMapper
import dev.usbharu.hideout.util.singleOr import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
class PostQueryServiceImpl : PostQueryService { class PostQueryServiceImpl(
private val postResultRowMapper: ResultRowMapper<Post>,
private val postQueryMapper: QueryMapper<Post>
) : PostQueryService {
override suspend fun findById(id: Long): Post = override suspend fun findById(id: Long): Post =
Posts.leftJoin(PostsMedia) Posts.leftJoin(PostsMedia)
.select { Posts.id eq id } .select { Posts.id eq id }
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }.toPost() .singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }
.let(postResultRowMapper::map)!!
override suspend fun findByUrl(url: String): Post = override suspend fun findByUrl(url: String): Post =
Posts.leftJoin(PostsMedia) Posts.leftJoin(PostsMedia)
.select { Posts.url eq url } .select { Posts.url eq url }
.toPost() .let(postQueryMapper::map)
.singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) } .singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }
override suspend fun findByApId(string: String): Post = override suspend fun findByApId(string: String): Post =
Posts.leftJoin(PostsMedia) Posts.leftJoin(PostsMedia)
.select { Posts.apId eq string } .select { Posts.apId eq string }
.toPost() .let(postQueryMapper::map)
.singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) } .singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) }
} }

View File

@ -13,14 +13,15 @@ import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Repository @Repository
class NoteQueryServiceImpl(private val postRepository: PostRepository) : NoteQueryService { class NoteQueryServiceImpl(private val postRepository: PostRepository, private val postQueryMapper: QueryMapper<Post>) :
NoteQueryService {
override suspend fun findById(id: Long): Pair<Note, Post> { override suspend fun findById(id: Long): Pair<Note, Post> {
return Posts return Posts
.leftJoin(Users) .leftJoin(Users)
.leftJoin(PostsMedia) .leftJoin(PostsMedia)
.leftJoin(Media) .leftJoin(Media)
.select { Posts.id eq id } .select { Posts.id eq id }
.let { it.toNote() to it.toPost().first() } .let { it.toNote() to postQueryMapper.map(it).first() }
} }

View File

@ -0,0 +1,17 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Post
import org.jetbrains.exposed.sql.Query
import org.springframework.stereotype.Component
@Component
class PostQueryMapper(private val postResultRowMapper: ResultRowMapper<Post>) : QueryMapper<Post> {
override fun map(query: Query): List<Post> {
return query.groupBy { it[Posts.id] }
.map { it.value }
.map {
it.first().let(postResultRowMapper::map)!!
.copy(mediaIds = it.mapNotNull { it.getOrNull(PostsMedia.mediaId) })
}
}
}

View File

@ -9,7 +9,10 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : PostRepository { class PostRepositoryImpl(
private val idGenerateService: IdGenerateService,
private val postQueryMapper: QueryMapper<Post>
) : PostRepository {
override suspend fun generateId(): Long = idGenerateService.generateId() override suspend fun generateId(): Long = idGenerateService.generateId()
@ -65,7 +68,7 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos
override suspend fun findById(id: Long): Post = override suspend fun findById(id: Long): Post =
Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId })
.select { Posts.id eq id } .select { Posts.id eq id }
.toPost() .let(postQueryMapper::map)
.singleOrNull() .singleOrNull()
?: throw FailedToGetResourcesException("id: $id was not found.") ?: throw FailedToGetResourcesException("id: $id was not found.")
@ -95,6 +98,7 @@ object PostsMedia : Table() {
override val primaryKey = PrimaryKey(postId, mediaId) override val primaryKey = PrimaryKey(postId, mediaId)
} }
@Deprecated("toPost is depracated")
fun ResultRow.toPost(): Post { fun ResultRow.toPost(): Post {
return Post.of( return Post.of(
id = this[Posts.id], id = this[Posts.id],
@ -111,6 +115,7 @@ fun ResultRow.toPost(): Post {
) )
} }
@Deprecated("toPost is deprecated")
fun Query.toPost(): List<Post> { fun Query.toPost(): List<Post> {
return this.groupBy { it[Posts.id] } return this.groupBy { it[Posts.id] }
.map { it.value } .map { it.value }

View File

@ -0,0 +1,25 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Post
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
import org.jetbrains.exposed.sql.ResultRow
import org.springframework.stereotype.Component
@Component
class PostResultRowMapper(private val postBuilder: Post.PostBuilder) : ResultRowMapper<Post> {
override fun map(resultRow: ResultRow): Post {
return postBuilder.of(
id = resultRow[Posts.id],
userId = resultRow[Posts.userId],
overview = resultRow[Posts.overview],
text = resultRow[Posts.text],
createdAt = resultRow[Posts.createdAt],
visibility = Visibility.values().first { visibility -> visibility.ordinal == resultRow[Posts.visibility] },
url = resultRow[Posts.url],
repostId = resultRow[Posts.repostId],
replyId = resultRow[Posts.replyId],
sensitive = resultRow[Posts.sensitive],
apId = resultRow[Posts.apId],
)
}
}

View File

@ -0,0 +1,7 @@
package dev.usbharu.hideout.repository
import org.jetbrains.exposed.sql.Query
interface QueryMapper<T> {
fun map(query: Query): List<T>
}

View File

@ -0,0 +1,7 @@
package dev.usbharu.hideout.repository
import org.jetbrains.exposed.sql.ResultRow
interface ResultRowMapper<T> {
fun map(resultRow: ResultRow): T?
}