mirror of https://github.com/usbharu/Hideout.git
feat: AccountQueryServiceを作成し、アカウントAPIから取得される情報を正確に
This commit is contained in:
parent
ef6c97b08c
commit
69a889a8d7
|
@ -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(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
}
|
|
@ -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) }
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue