refactor: RelationshipRepositoryをPagination APIに変更

This commit is contained in:
usbharu 2024-01-29 17:59:46 +09:00
parent ba6e21decd
commit deb2d5b0b5
5 changed files with 138 additions and 23 deletions

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.application.infrastructure.exposed
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.ExpressionWithColumnType
import org.jetbrains.exposed.sql.Query
import org.jetbrains.exposed.sql.SortOrder
@ -7,11 +8,24 @@ import org.jetbrains.exposed.sql.andWhere
fun Query.pagination(page: Page, exp: ExpressionWithColumnType<Long>): Query {
if (page.minId != null) {
page.maxId?.let { andWhere { exp.lessEq(it) } }
page.minId?.let { andWhere { exp.greaterEq(it) } }
page.maxId?.let { andWhere { exp.less(it) } }
page.minId?.let { andWhere { exp.greater(it) } }
} else {
page.maxId?.let { andWhere { exp.lessEq(it) } }
page.sinceId?.let { andWhere { exp.greaterEq(it) } }
page.maxId?.let { andWhere { exp.less(it) } }
page.sinceId?.let { andWhere { exp.greater(it) } }
this.orderBy(exp, SortOrder.DESC)
}
page.limit?.let { limit(it) }
return this
}
fun Query.pagination(page: Page, exp: ExpressionWithColumnType<EntityID<Long>>): Query {
if (page.minId != null) {
page.maxId?.let { andWhere { exp.less(it) } }
page.minId?.let { andWhere { exp.greater(it) } }
} else {
page.maxId?.let { andWhere { exp.less(it) } }
page.sinceId?.let { andWhere { exp.greater(it) } }
this.orderBy(exp, SortOrder.DESC)
}
page.limit?.let { limit(it) }

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.core.domain.model.relationship
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
/**
* [Relationship]の永続化
*
@ -43,6 +46,13 @@ interface RelationshipRepository {
ignoreFollowRequest: Boolean
): List<Relationship>
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
targetIdLong: Long,
followRequest: Boolean,
ignoreFollowRequest: Boolean,
page: Page.PageByMaxId
): PaginationList<Relationship, Long>
@Suppress("FunctionMaxLength")
suspend fun findByActorIdAntMutingAndMaxIdAndSinceId(
actorId: Long,
@ -51,4 +61,10 @@ interface RelationshipRepository {
sinceId: Long?,
limit: Int
): List<Relationship>
suspend fun findByActorIdAndMuting(
actorId: Long,
muting: Boolean,
page: Page.PageByMaxId
): PaginationList<Relationship, Long>
}

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.core.domain.model.relationship
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
import dev.usbharu.hideout.application.infrastructure.exposed.pagination
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
import org.jetbrains.exposed.dao.id.LongIdTable
@ -97,6 +100,26 @@ class RelationshipRepositoryImpl : RelationshipRepository, AbstractRepository()
return@query query.map { it.toRelationships() }
}
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
targetId: Long,
followRequest: Boolean,
ignoreFollowRequest: Boolean,
page: Page.PageByMaxId
): PaginationList<Relationship, Long> = query {
val query = Relationships.select {
Relationships.targetActorId.eq(targetId).and(Relationships.followRequest.eq(followRequest))
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
}
val resultRowList = query.pagination(page, Relationships.id).toList()
return@query PaginationList(
query.map { it.toRelationships() },
resultRowList.lastOrNull()?.getOrNull(Relationships.id)?.value,
resultRowList.firstOrNull()?.getOrNull(Relationships.id)?.value
)
}
override suspend fun findByActorIdAntMutingAndMaxIdAndSinceId(
actorId: Long,
muting: Boolean,
@ -119,6 +142,24 @@ class RelationshipRepositoryImpl : RelationshipRepository, AbstractRepository()
return@query query.map { it.toRelationships() }
}
override suspend fun findByActorIdAndMuting(
actorId: Long,
muting: Boolean,
page: Page.PageByMaxId
): PaginationList<Relationship, Long> = query {
val query = Relationships.select {
Relationships.actorId.eq(actorId).and(Relationships.muting.eq(muting))
}
val resultRowList = query.pagination(page, Relationships.id).toList()
return@query PaginationList(
query.map { it.toRelationships() },
resultRowList.lastOrNull()?.getOrNull(Relationships.id)?.value,
resultRowList.firstOrNull()?.getOrNull(Relationships.id)?.value
)
}
companion object {
private val logger = LoggerFactory.getLogger(RelationshipRepositoryImpl::class.java)
}

View File

@ -1,6 +1,9 @@
package dev.usbharu.hideout.mastodon.interfaces.api.account
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.toHttpHeader
import dev.usbharu.hideout.controller.mastodon.generated.AccountApi
import dev.usbharu.hideout.core.infrastructure.springframework.security.LoginUserContextHolder
import dev.usbharu.hideout.core.service.user.UserCreateDto
@ -19,12 +22,12 @@ import java.net.URI
class MastodonAccountApiController(
private val accountApiService: AccountApiService,
private val transaction: Transaction,
private val loginUserContextHolder: LoginUserContextHolder
private val loginUserContextHolder: LoginUserContextHolder,
private val applicationConfig: ApplicationConfig
) : AccountApi {
override suspend fun apiV1AccountsIdFollowPost(
id: String,
followRequestBody: FollowRequestBody?
id: String, followRequestBody: FollowRequestBody?
): ResponseEntity<Relationship> {
val userid = loginUserContextHolder.getLoginUserId()
@ -35,17 +38,11 @@ class MastodonAccountApiController(
ResponseEntity.ok(accountApiService.account(id.toLong()))
override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> = ResponseEntity(
accountApiService.verifyCredentials(loginUserContextHolder.getLoginUserId()),
HttpStatus.OK
accountApiService.verifyCredentials(loginUserContextHolder.getLoginUserId()), HttpStatus.OK
)
override suspend fun apiV1AccountsPost(
username: String,
password: String,
email: String?,
agreement: Boolean?,
locale: Boolean?,
reason: String?
username: String, password: String, email: String?, agreement: Boolean?, locale: Boolean?, reason: String?
): ResponseEntity<Unit> {
transaction.transaction {
accountApiService.registerAccount(UserCreateDto(username, username, "", password))
@ -85,8 +82,7 @@ class MastodonAccountApiController(
}
override fun apiV1AccountsRelationshipsGet(
id: List<String>?,
withSuspended: Boolean
id: List<String>?, withSuspended: Boolean
): ResponseEntity<Flow<Relationship>> = runBlocking {
val userid = loginUserContextHolder.getLoginUserId()
@ -128,8 +124,7 @@ class MastodonAccountApiController(
return ResponseEntity.ok(removeFromFollowers)
}
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?):
ResponseEntity<Account> {
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): ResponseEntity<Account> {
val userid = loginUserContextHolder.getLoginUserId()
val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials)
@ -157,10 +152,23 @@ class MastodonAccountApiController(
runBlocking {
val userid = loginUserContextHolder.getLoginUserId()
val accountFlow =
accountApiService.followRequests(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20, false)
.asFlow()
ResponseEntity.ok(accountFlow)
val followRequests = accountApiService.followRequests(
userid, false, Page.PageByMaxId(
maxId?.toLongOrNull(), sinceId?.toLongOrNull(), limit?.coerceIn(0, 80) ?: 40
)
)
val httpHeader = followRequests.toHttpHeader(
{ "${applicationConfig.url}/api/v1/follow_requests?max_id=$it" },
{ "${applicationConfig.url}/api/v1/follow_requests?min_id=$it" },
)
if (httpHeader != null) {
return@runBlocking ResponseEntity.ok().header("Link", httpHeader).body(followRequests.asFlow())
}
ResponseEntity.ok(followRequests.asFlow())
}
override suspend fun apiV1AccountsIdMutePost(id: String): ResponseEntity<Relationship> {

View File

@ -1,6 +1,8 @@
package dev.usbharu.hideout.mastodon.service.account
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.service.media.MediaService
import dev.usbharu.hideout.core.service.relationship.RelationshipService
@ -58,11 +60,18 @@ interface AccountApiService {
withIgnore: Boolean
): List<Account>
suspend fun followRequests(
loginUser: Long,
withIgnore: Boolean,
pageByMaxId: Page.PageByMaxId
): PaginationList<Account, Long>
suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship
suspend fun rejectFollowRequest(loginUser: Long, target: Long): Relationship
suspend fun mute(userid: Long, target: Long): Relationship
suspend fun unmute(userid: Long, target: Long): Relationship
suspend fun mutesAccount(userid: Long, maxId: Long?, sinceId: Long?, limit: Int): List<Account>
suspend fun mutesAccount(userid: Long, pageByMaxId: Page.PageByMaxId): PaginationList<Account, Long>
}
@Service
@ -236,6 +245,23 @@ class AccountApiServiceImpl(
return@transaction accountService.findByIds(actorIdList)
}
override suspend fun followRequests(
loginUser: Long,
withIgnore: Boolean,
pageByMaxId: Page.PageByMaxId
): PaginationList<Account, Long> = transaction.transaction {
val request =
relationshipRepository.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
loginUser,
true,
withIgnore,
pageByMaxId
)
val actorIds = request.map { it.actorId }
return@transaction PaginationList(accountService.findByIds(actorIds), request.next, request.prev)
}
override suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship = transaction.transaction {
relationshipService.acceptFollowRequest(loginUser, target)
@ -267,6 +293,16 @@ class AccountApiServiceImpl(
return accountService.findByIds(mutedAccounts.map { it.targetActorId })
}
override suspend fun mutesAccount(userid: Long, pageByMaxId: Page.PageByMaxId): PaginationList<Account, Long> {
val mutedAccounts = relationshipRepository.findByActorIdAndMuting(userid, true, pageByMaxId)
return PaginationList(
accountService.findByIds(mutedAccounts.map { it.targetActorId }),
mutedAccounts.next,
mutedAccounts.prev
)
}
private fun from(account: Account): CredentialAccount {
return CredentialAccount(
id = account.id,