feat: AccountQueryServiceを作成し、アカウントAPIから取得される情報を正確に

This commit is contained in:
usbharu 2023-12-12 16:48:25 +09:00
parent ef6c97b08c
commit 69a889a8d7
3 changed files with 113 additions and 35 deletions

View File

@ -0,0 +1,100 @@
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
import dev.usbharu.hideout.core.domain.model.relationship.Relationships
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.mastodon.query.AccountQueryService
import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.springframework.stereotype.Repository
import java.time.Instant
@Repository
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
override suspend fun findById(accountId: Long): Account {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count")
val followersCount = Count(Relationships.targetActorId.eq(Actors.id), true).alias("followers_count")
val postsCount = Posts.id.countDistinct().alias("posts_count")
val lastCreated = Posts.createdAt.max().alias("last_created")
val query = Actors
.join(Relationships, JoinType.LEFT) {
Actors.id eq Relationships.actorId or (Actors.id eq Relationships.targetActorId)
}
.leftJoin(Posts)
.slice(
followingCount,
followersCount,
*(Actors.realFields.toTypedArray()),
lastCreated,
postsCount
)
.select { Actors.id eq accountId and (Relationships.following eq true or (Relationships.following.isNull())) }
.groupBy(Actors.id)
return query
.singleOr { FailedToGetResourcesException("accountId: $accountId wad not exist or duplicate", it) }
.let { toAccount(it, followingCount, followersCount, postsCount, lastCreated) }
}
override suspend fun findByIds(accountIds: List<Long>): List<Account> {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count")
val followersCount = Count(Relationships.targetActorId.eq(Actors.id), true).alias("followers_count")
val postsCount = Posts.id.countDistinct().alias("posts_count")
val lastCreated = Posts.createdAt.max().alias("last_created")
val query = Actors
.join(Relationships, JoinType.LEFT) {
Actors.id eq Relationships.actorId or (Actors.id eq Relationships.targetActorId)
}
.leftJoin(Posts)
.slice(
followingCount,
followersCount,
*(Actors.realFields.toTypedArray()),
lastCreated,
postsCount
)
.select { Actors.id inList accountIds and (Relationships.following eq true or (Relationships.following.isNull())) }
.groupBy(Actors.id)
return query
.map { toAccount(it, followingCount, followersCount, postsCount, lastCreated) }
}
private fun toAccount(
resultRow: ResultRow,
followingCount: ExpressionAlias<Long>,
followersCount: ExpressionAlias<Long>,
postsCount: ExpressionAlias<Long>,
lastCreated: ExpressionAlias<Long?>
): Account {
val userUrl = "${applicationConfig.url}/users/${resultRow[Actors.id]}"
return Account(
id = resultRow[Actors.id].toString(),
username = resultRow[Actors.name],
acct = "${resultRow[Actors.name]}@${resultRow[Actors.domain]}",
url = resultRow[Actors.url],
displayName = resultRow[Actors.screenName],
note = resultRow[Actors.description],
avatar = userUrl + "/icon.jpg",
avatarStatic = userUrl + "/icon.jpg",
header = userUrl + "/header.jpg",
headerStatic = userUrl + "/header.jpg",
locked = resultRow[Actors.locked],
fields = emptyList(),
emojis = emptyList(),
bot = false,
group = false,
discoverable = true,
createdAt = Instant.ofEpochMilli(resultRow[Actors.createdAt]).toString(),
lastStatusAt = resultRow[lastCreated]?.let { Instant.ofEpochMilli(it).toString() },
statusesCount = resultRow[postsCount].toInt(),
followersCount = resultRow[followersCount].toInt(),
followingCount = resultRow[followingCount].toInt(),
)
}
}

View File

@ -0,0 +1,8 @@
package dev.usbharu.hideout.mastodon.query
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
interface AccountQueryService {
suspend fun findById(accountId: Long): Account
suspend fun findByIds(accountIds: List<Long>): List<Account>
}

View File

@ -1,9 +1,7 @@
package dev.usbharu.hideout.mastodon.service.account package dev.usbharu.hideout.mastodon.service.account
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.query.ActorQueryService
import dev.usbharu.hideout.domain.mastodon.model.generated.Account import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.mastodon.query.AccountQueryService
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
@ -14,41 +12,13 @@ interface AccountService {
@Service @Service
class AccountServiceImpl( class AccountServiceImpl(
private val actorQueryService: ActorQueryService, private val accountQueryService: AccountQueryService
private val applicationConfig: ApplicationConfig
) : AccountService { ) : AccountService {
override suspend fun findById(id: Long): Account { override suspend fun findById(id: Long): Account {
val findById = actorQueryService.findById(id) return accountQueryService.findById(id)
return toAccount(findById)
} }
private fun toAccount(findById: Actor): Account { override suspend fun findByIds(ids: List<Long>): List<Account> {
val userUrl = applicationConfig.url.toString() + "/users/" + findById.id.toString() return accountQueryService.findByIds(ids)
return Account(
id = findById.id.toString(),
username = findById.name,
acct = "${findById.name}@${findById.domain}",
url = findById.url,
displayName = findById.screenName,
note = findById.description,
avatar = "$userUrl/icon.jpg",
avatarStatic = "$userUrl/icon.jpg",
header = "$userUrl/header.jpg",
headerStatic = "$userUrl/header.jpg",
locked = findById.locked,
fields = emptyList(),
emojis = emptyList(),
bot = false,
group = false,
discoverable = false,
createdAt = findById.createdAt.toString(),
lastStatusAt = findById.createdAt.toString(),
statusesCount = 0,
followersCount = 0,
)
} }
override suspend fun findByIds(ids: List<Long>): List<Account> =
actorQueryService.findByIds(ids).map { toAccount(it) }
} }