feat: repositoryにtransactionを追加

This commit is contained in:
usbharu 2023-05-04 23:47:24 +09:00
parent d78f5e201f
commit 5d052b9ad8
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
11 changed files with 320 additions and 344 deletions

View File

@ -3,6 +3,8 @@ package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
interface IJwtRefreshTokenRepository { interface IJwtRefreshTokenRepository {
suspend fun <T> transaction(block: suspend () -> T):T
suspend fun generateId(): Long suspend fun generateId(): Long
suspend fun save(token: JwtRefreshToken) suspend fun save(token: JwtRefreshToken)

View File

@ -4,6 +4,8 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Meta
interface IMetaRepository { interface IMetaRepository {
suspend fun <T> transaction(block: suspend () -> T):T
suspend fun save(meta: Meta) suspend fun save(meta: Meta)
suspend fun get(): Meta? suspend fun get(): Meta?

View File

@ -7,4 +7,6 @@ interface IPostRepository {
suspend fun insert(post: Post): PostEntity suspend fun insert(post: Post): PostEntity
suspend fun findOneById(id: Long): PostEntity suspend fun findOneById(id: Long): PostEntity
suspend fun delete(id: Long) suspend fun delete(id: Long)
@Suppress("InjectDispatcher")
suspend fun <T> transaction(block: suspend () -> T): T
} }

View File

@ -36,4 +36,6 @@ interface IUserRepository {
suspend fun findFollowersById(id: Long): List<User> suspend fun findFollowersById(id: Long): List<User>
suspend fun nextId(): Long suspend fun nextId(): Long
@Suppress("InjectDispatcher")
suspend fun <T> transaction(block: suspend () -> T): T
} }

View File

@ -1,6 +1,8 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
import dev.usbharu.hideout.repository.JwtRefreshTokens.id
import dev.usbharu.hideout.repository.JwtRefreshTokens.refreshToken
import dev.usbharu.hideout.service.IdGenerateService import dev.usbharu.hideout.service.IdGenerateService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
@ -25,78 +27,60 @@ class JwtRefreshTokenRepositoryImpl(
} }
@Suppress("InjectDispatcher") @Suppress("InjectDispatcher")
suspend fun <T> query(block: suspend () -> T): T = override suspend fun <T> transaction(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() } newSuspendedTransaction(Dispatchers.IO) { block() }
override suspend fun generateId(): Long = idGenerateService.generateId() override suspend fun generateId(): Long = idGenerateService.generateId()
override suspend fun save(token: JwtRefreshToken) { override suspend fun save(token: JwtRefreshToken) {
query { if (JwtRefreshTokens.select { id.eq(token.id) }.empty()) {
if (JwtRefreshTokens.select { JwtRefreshTokens.id.eq(token.id) }.empty()) { JwtRefreshTokens.insert {
JwtRefreshTokens.insert { it[id] = token.id
it[id] = token.id it[userId] = token.userId
it[userId] = token.userId it[refreshToken] = token.refreshToken
it[refreshToken] = token.refreshToken it[createdAt] = token.createdAt.toEpochMilli()
it[createdAt] = token.createdAt.toEpochMilli() it[expiresAt] = token.expiresAt.toEpochMilli()
it[expiresAt] = token.expiresAt.toEpochMilli() }
} } else {
} else { JwtRefreshTokens.update({ id eq token.id }) {
JwtRefreshTokens.update({ JwtRefreshTokens.id eq token.id }) { it[userId] = token.userId
it[userId] = token.userId it[refreshToken] = token.refreshToken
it[refreshToken] = token.refreshToken it[createdAt] = token.createdAt.toEpochMilli()
it[createdAt] = token.createdAt.toEpochMilli() it[expiresAt] = token.expiresAt.toEpochMilli()
it[expiresAt] = token.expiresAt.toEpochMilli()
}
} }
} }
} }
override suspend fun findById(id: Long): JwtRefreshToken? { override suspend fun findById(id: Long): JwtRefreshToken? {
return query { return JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }.singleOrNull()?.toJwtRefreshToken()
JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }.singleOrNull()?.toJwtRefreshToken()
}
} }
override suspend fun findByToken(token: String): JwtRefreshToken? { override suspend fun findByToken(token: String): JwtRefreshToken? {
return query { return JwtRefreshTokens.select { refreshToken.eq(token) }.singleOrNull()?.toJwtRefreshToken()
JwtRefreshTokens.select { JwtRefreshTokens.refreshToken.eq(token) }.singleOrNull()?.toJwtRefreshToken()
}
} }
override suspend fun findByUserId(userId: Long): JwtRefreshToken? { override suspend fun findByUserId(userId: Long): JwtRefreshToken? {
return query { return JwtRefreshTokens.select { JwtRefreshTokens.userId.eq(userId) }.singleOrNull()?.toJwtRefreshToken()
JwtRefreshTokens.select { JwtRefreshTokens.userId.eq(userId) }.singleOrNull()?.toJwtRefreshToken()
}
} }
override suspend fun delete(token: JwtRefreshToken) { override suspend fun delete(token: JwtRefreshToken) {
return query { JwtRefreshTokens.deleteWhere { id eq token.id }
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.id eq token.id }
}
} }
override suspend fun deleteById(id: Long) { override suspend fun deleteById(id: Long) {
return query { JwtRefreshTokens.deleteWhere { JwtRefreshTokens.id eq id }
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.id eq id }
}
} }
override suspend fun deleteByToken(token: String) { override suspend fun deleteByToken(token: String) {
return query { JwtRefreshTokens.deleteWhere { refreshToken eq token }
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.refreshToken eq token }
}
} }
override suspend fun deleteByUserId(userId: Long) { override suspend fun deleteByUserId(userId: Long) {
return query { JwtRefreshTokens.deleteWhere { JwtRefreshTokens.userId eq userId }
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.userId eq userId }
}
} }
override suspend fun deleteAll() { override suspend fun deleteAll() {
return query { JwtRefreshTokens.deleteAll()
JwtRefreshTokens.deleteAll()
}
} }
} }

View File

@ -1,6 +1,8 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Jwt import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
import dev.usbharu.hideout.repository.Meta.id
import dev.usbharu.hideout.repository.Meta.kid
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
@ -19,38 +21,34 @@ class MetaRepositoryImpl(private val database: Database) : IMetaRepository {
} }
@Suppress("InjectDispatcher") @Suppress("InjectDispatcher")
suspend fun <T> query(block: suspend () -> T): T = override suspend fun <T> transaction(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() } newSuspendedTransaction(Dispatchers.IO) { block() }
override suspend fun save(meta: dev.usbharu.hideout.domain.model.hideout.entity.Meta) { override suspend fun save(meta: dev.usbharu.hideout.domain.model.hideout.entity.Meta) {
return query { if (Meta.select { id eq 1 }.empty()) {
if (Meta.select { Meta.id eq 1 }.empty()) { Meta.insert {
Meta.insert { it[id] = 1
it[id] = 1 it[version] = meta.version
it[this.version] = meta.version it[kid] = UUID.randomUUID().toString()
it[kid] = UUID.randomUUID().toString() it[jwtPrivateKey] = meta.jwt.privateKey
it[this.jwtPrivateKey] = meta.jwt.privateKey it[jwtPublicKey] = meta.jwt.publicKey
it[this.jwtPublicKey] = meta.jwt.publicKey }
} } else {
} else { Meta.update({ id eq 1 }) {
Meta.update({ Meta.id eq 1 }) { it[version] = meta.version
it[this.version] = meta.version it[kid] = UUID.randomUUID().toString()
it[kid] = UUID.randomUUID().toString() it[jwtPrivateKey] = meta.jwt.privateKey
it[this.jwtPrivateKey] = meta.jwt.privateKey it[jwtPublicKey] = meta.jwt.publicKey
it[this.jwtPublicKey] = meta.jwt.publicKey
}
} }
} }
} }
override suspend fun get(): dev.usbharu.hideout.domain.model.hideout.entity.Meta? { override suspend fun get(): dev.usbharu.hideout.domain.model.hideout.entity.Meta? {
return query { return Meta.select { id eq 1 }.singleOrNull()?.let {
Meta.select { Meta.id eq 1 }.singleOrNull()?.let { dev.usbharu.hideout.domain.model.hideout.entity.Meta(
dev.usbharu.hideout.domain.model.hideout.entity.Meta( it[Meta.version],
it[Meta.version], Jwt(UUID.fromString(it[kid]), it[Meta.jwtPrivateKey], it[Meta.jwtPublicKey])
Jwt(UUID.fromString(it[Meta.kid]), it[Meta.jwtPrivateKey], it[Meta.jwtPublicKey]) )
)
}
} }
} }
} }

View File

@ -23,48 +23,40 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
} }
@Suppress("InjectDispatcher") @Suppress("InjectDispatcher")
suspend fun <T> query(block: suspend () -> T): T = override suspend fun <T> transaction(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() } newSuspendedTransaction(Dispatchers.IO) { block() }
override suspend fun insert(post: Post): PostEntity { override suspend fun insert(post: Post): PostEntity {
return query { val generateId = idGenerateService.generateId()
val generateId = idGenerateService.generateId() val name = Users.select { Users.id eq post.userId }.single().toUser().name
val name = Users.select { Users.id eq post.userId }.single().toUser().name val postUrl = Config.configData.url + "/users/$name/posts/$generateId"
val postUrl = Config.configData.url + "/users/$name/posts/$generateId" Posts.insert {
Posts.insert { it[id] = generateId
it[id] = generateId it[userId] = post.userId
it[userId] = post.userId it[overview] = post.overview
it[overview] = post.overview it[text] = post.text
it[text] = post.text it[createdAt] = post.createdAt
it[createdAt] = post.createdAt it[visibility] = post.visibility
it[visibility] = post.visibility it[url] = postUrl
it[url] = postUrl it[repostId] = post.repostId
it[repostId] = post.repostId it[replyId] = post.replyId
it[replyId] = post.replyId
}
return@query PostEntity(
id = generateId,
userId = post.userId,
overview = post.overview,
text = post.text,
createdAt = post.createdAt,
visibility = post.visibility,
url = postUrl,
repostId = post.repostId,
replyId = post.replyId
)
} }
return PostEntity(
id = generateId,
userId = post.userId,
overview = post.overview,
text = post.text,
createdAt = post.createdAt,
visibility = post.visibility,
url = postUrl,
repostId = post.repostId,
replyId = post.replyId
)
} }
override suspend fun findOneById(id: Long): PostEntity { override suspend fun findOneById(id: Long): PostEntity = Posts.select { Posts.id eq id }.single().toPost()
return query {
Posts.select { Posts.id eq id }.single().toPost()
}
}
override suspend fun delete(id: Long) { override suspend fun delete(id: Long) {
return query { Posts.deleteWhere { Posts.id eq id }
Posts.deleteWhere { Posts.id eq id }
}
} }
} }

View File

@ -1,6 +1,19 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import dev.usbharu.hideout.repository.Users.createdAt
import dev.usbharu.hideout.repository.Users.description
import dev.usbharu.hideout.repository.Users.domain
import dev.usbharu.hideout.repository.Users.id
import dev.usbharu.hideout.repository.Users.inbox
import dev.usbharu.hideout.repository.Users.name
import dev.usbharu.hideout.repository.Users.outbox
import dev.usbharu.hideout.repository.Users.password
import dev.usbharu.hideout.repository.Users.privateKey
import dev.usbharu.hideout.repository.Users.publicKey
import dev.usbharu.hideout.repository.Users.screenName
import dev.usbharu.hideout.repository.Users.url
import dev.usbharu.hideout.repository.UsersFollowers.followerId
import dev.usbharu.hideout.service.IdGenerateService import dev.usbharu.hideout.service.IdGenerateService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.dao.id.LongIdTable
@ -24,185 +37,148 @@ class UserRepository(private val database: Database, private val idGenerateServi
} }
@Suppress("InjectDispatcher") @Suppress("InjectDispatcher")
suspend fun <T> query(block: suspend () -> T): T = override suspend fun <T> transaction(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() } newSuspendedTransaction(Dispatchers.IO) { block() }
override suspend fun save(user: User): User { override suspend fun save(user: User): User {
return query { val singleOrNull = Users.select { id eq user.id }.singleOrNull()
val singleOrNull = Users.select { Users.id eq user.id }.singleOrNull() if (singleOrNull == null) {
if (singleOrNull == null) { Users.insert {
Users.insert { it[id] = user.id
it[id] = user.id it[name] = user.name
it[name] = user.name it[domain] = user.domain
it[domain] = user.domain it[screenName] = user.screenName
it[screenName] = user.screenName it[description] = user.description
it[description] = user.description it[password] = user.password
it[password] = user.password it[inbox] = user.inbox
it[inbox] = user.inbox it[outbox] = user.outbox
it[outbox] = user.outbox it[url] = user.url
it[url] = user.url it[createdAt] = user.createdAt.toEpochMilli()
it[createdAt] = user.createdAt.toEpochMilli() it[publicKey] = user.publicKey
it[publicKey] = user.publicKey it[privateKey] = user.privateKey
it[privateKey] = user.privateKey }
} } else {
} else { Users.update({ id eq user.id }) {
Users.update({ Users.id eq user.id }) { it[name] = user.name
it[name] = user.name it[domain] = user.domain
it[domain] = user.domain it[screenName] = user.screenName
it[screenName] = user.screenName it[description] = user.description
it[description] = user.description it[password] = user.password
it[password] = user.password it[inbox] = user.inbox
it[inbox] = user.inbox it[outbox] = user.outbox
it[outbox] = user.outbox it[url] = user.url
it[url] = user.url it[createdAt] = user.createdAt.toEpochMilli()
it[createdAt] = user.createdAt.toEpochMilli() it[publicKey] = user.publicKey
it[publicKey] = user.publicKey it[privateKey] = user.privateKey
it[privateKey] = user.privateKey
}
} }
return@query user
} }
return user
} }
override suspend fun createFollower(id: Long, follower: Long) { override suspend fun createFollower(id: Long, follower: Long) {
return query { UsersFollowers.insert {
UsersFollowers.insert { it[userId] = id
it[userId] = id it[followerId] = follower
it[followerId] = follower
}
} }
} }
override suspend fun findById(id: Long): User? { override suspend fun findById(id: Long): User? {
return query { return Users.select { Users.id eq id }.map {
Users.select { Users.id eq id }.map { it.toUser()
it.toUser() }.singleOrNull()
}.singleOrNull()
}
} }
override suspend fun findByIds(ids: List<Long>): List<User> { override suspend fun findByIds(ids: List<Long>): List<User> {
return query { return Users.select { id inList ids }.map {
Users.select { Users.id inList ids }.map { it.toUser()
it.toUser()
}
} }
} }
override suspend fun findByName(name: String): List<User> { override suspend fun findByName(name: String): List<User> {
return query { return Users.select { Users.name eq name }.map {
Users.select { Users.name eq name }.map { it.toUser()
it.toUser()
}
} }
} }
override suspend fun findByNameAndDomain(name: String, domain: String): User? { override suspend fun findByNameAndDomain(name: String, domain: String): User? =
return query { Users.select { Users.name eq name and (Users.domain eq domain) }.singleOrNull()?.toUser()
Users.select { Users.name eq name and (Users.domain eq domain) }.singleOrNull()?.toUser()
}
}
override suspend fun findByDomain(domain: String): List<User> { override suspend fun findByDomain(domain: String): List<User> {
return query { return Users.select { Users.domain eq domain }.map {
Users.select { Users.domain eq domain }.map { it.toUser()
it.toUser()
}
} }
} }
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> { override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> {
return query { val selectAll = Users.selectAll()
val selectAll = Users.selectAll() names.forEach { (name, domain) ->
names.forEach { (name, domain) -> selectAll.orWhere { Users.name eq name and (Users.domain eq domain) }
selectAll.orWhere { Users.name eq name and (Users.domain eq domain) }
}
selectAll.map { it.toUser() }
} }
return selectAll.map { it.toUser() }
} }
override suspend fun findByUrl(url: String): User? { override suspend fun findByUrl(url: String): User? = Users.select { Users.url eq url }.singleOrNull()?.toUser()
return query {
Users.select { Users.url eq url }.singleOrNull()?.toUser()
}
}
override suspend fun findByUrls(urls: List<String>): List<User> { override suspend fun findByUrls(urls: List<String>): List<User> =
return query { Users.select { url inList urls }.map { it.toUser() }
Users.select { Users.url inList urls }.map { it.toUser() }
}
}
override suspend fun findFollowersById(id: Long): List<User> { override suspend fun findFollowersById(id: Long): List<User> {
return query { val followers = Users.alias("FOLLOWERS")
val followers = Users.alias("FOLLOWERS") return Users.innerJoin(
Users.innerJoin( otherTable = UsersFollowers,
otherTable = UsersFollowers, onColumn = { Users.id },
onColumn = { Users.id }, otherColumn = { userId }
otherColumn = { userId } )
.innerJoin(
otherTable = followers,
onColumn = { followerId },
otherColumn = { followers[Users.id] }
) )
.innerJoin( .slice(
otherTable = followers, followers.get(Users.id),
onColumn = { UsersFollowers.followerId }, followers.get(name),
otherColumn = { followers[Users.id] } followers.get(domain),
followers.get(screenName),
followers.get(description),
followers.get(password),
followers.get(inbox),
followers.get(outbox),
followers.get(url),
followers.get(publicKey),
followers.get(privateKey),
followers.get(createdAt)
)
.select { Users.id eq id }
.map {
User(
id = it[followers[Users.id]],
name = it[followers[name]],
domain = it[followers[domain]],
screenName = it[followers[screenName]],
description = it[followers[description]],
password = it[followers[password]],
inbox = it[followers[inbox]],
outbox = it[followers[outbox]],
url = it[followers[url]],
publicKey = it[followers[publicKey]],
privateKey = it[followers[privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[createdAt]])
) )
.slice( }
followers.get(Users.id),
followers.get(Users.name),
followers.get(Users.domain),
followers.get(Users.screenName),
followers.get(Users.description),
followers.get(Users.password),
followers.get(Users.inbox),
followers.get(Users.outbox),
followers.get(Users.url),
followers.get(Users.publicKey),
followers.get(Users.privateKey),
followers.get(Users.createdAt)
)
.select { Users.id eq id }
.map {
User(
id = it[followers[Users.id]],
name = it[followers[Users.name]],
domain = it[followers[Users.domain]],
screenName = it[followers[Users.screenName]],
description = it[followers[Users.description]],
password = it[followers[Users.password]],
inbox = it[followers[Users.inbox]],
outbox = it[followers[Users.outbox]],
url = it[followers[Users.url]],
publicKey = it[followers[Users.publicKey]],
privateKey = it[followers[Users.privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
)
}
}
} }
override suspend fun delete(id: Long) { override suspend fun delete(id: Long) {
query { Users.deleteWhere { Users.id.eq(id) }
Users.deleteWhere { Users.id.eq(id) }
}
} }
override suspend fun deleteFollower(id: Long, follower: Long) { override suspend fun deleteFollower(id: Long, follower: Long) {
query { UsersFollowers.deleteWhere { (userId eq id).and(followerId eq follower) }
UsersFollowers.deleteWhere { (userId eq id).and(followerId eq follower) }
}
} }
override suspend fun findAll(): List<User> { override suspend fun findAll(): List<User> = Users.selectAll().map { it.toUser() }
return query {
Users.selectAll().map { it.toUser() }
}
}
override suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long): List<User> { override suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long): List<User> =
return query { Users.selectAll().limit(limit, offset).map { it.toUser() }
Users.selectAll().limit(limit, offset).map { it.toUser() }
}
}
override suspend fun nextId(): Long = idGenerateService.generateId() override suspend fun nextId(): Long = idGenerateService.generateId()
} }

View File

@ -16,19 +16,22 @@ class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) :
val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java) val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java)
override suspend fun init() { override suspend fun init() {
val savedMeta = metaRepository.get() metaRepository.transaction {
val implementationVersion = ServerUtil.getImplementationVersion()
if (wasInitialised(savedMeta).not()) { val savedMeta = metaRepository.get()
logger.info("Start Initialise") val implementationVersion = ServerUtil.getImplementationVersion()
initialise(implementationVersion) if (wasInitialised(savedMeta).not()) {
logger.info("Finish Initialise") logger.info("Start Initialise")
return initialise(implementationVersion)
logger.info("Finish Initialise")
return@transaction
}
if (isVersionChanged(savedMeta!!)) {
logger.info("Version changed!! (${savedMeta.version} -> $implementationVersion)")
updateVersion(savedMeta, implementationVersion)
}
} }
if (isVersionChanged(savedMeta!!)) {
logger.info("Version changed!! (${savedMeta.version} -> $implementationVersion)")
updateVersion(savedMeta, implementationVersion)
}
} }
private fun wasInitialised(meta: Meta?): Boolean { private fun wasInitialised(meta: Meta?): Boolean {

View File

@ -9,6 +9,7 @@ import kotlinx.coroutines.test.runTest
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertIterableEquals import org.junit.jupiter.api.Assertions.assertIterableEquals
@ -41,111 +42,115 @@ class UserRepositoryTest {
@Test @Test
fun `findFollowersById フォロワー一覧を取得`() = runTest { fun `findFollowersById フォロワー一覧を取得`() = runTest {
val userRepository = UserRepository( newSuspendedTransaction {
db, val userRepository = UserRepository(
object : IdGenerateService { db,
override suspend fun generateId(): Long { object : IdGenerateService {
TODO("Not yet implemented") override suspend fun generateId(): Long {
TODO("Not yet implemented")
}
} }
)
val user = userRepository.save(
User(
id = 0L,
name = "test",
domain = "example.com",
screenName = "testUser",
description = "This user is test user.",
password = "https://example.com/inbox",
inbox = "",
outbox = "https://example.com/outbox",
url = "https://example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
val follower = userRepository.save(
User(
id = 1L,
name = "follower",
domain = "follower.example.com",
screenName = "followerUser",
description = "This user is follower user.",
password = "",
inbox = "https://follower.example.com/inbox",
outbox = "https://follower.example.com/outbox",
url = "https://follower.example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
val follower2 = userRepository.save(
User(
id = 3L,
name = "follower2",
domain = "follower2.example.com",
screenName = "followerUser2",
description = "This user is follower user 2.",
password = "",
inbox = "https://follower2.example.com/inbox",
outbox = "https://follower2.example.com/outbox",
url = "https://follower2.example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
userRepository.createFollower(user.id, follower.id)
userRepository.createFollower(user.id, follower2.id)
userRepository.findFollowersById(user.id).let {
assertIterableEquals(listOf(follower, follower2), it)
} }
)
val user = userRepository.save(
User(
id = 0L,
name = "test",
domain = "example.com",
screenName = "testUser",
description = "This user is test user.",
password = "https://example.com/inbox",
inbox = "",
outbox = "https://example.com/outbox",
url = "https://example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
val follower = userRepository.save(
User(
id = 1L,
name = "follower",
domain = "follower.example.com",
screenName = "followerUser",
description = "This user is follower user.",
password = "",
inbox = "https://follower.example.com/inbox",
outbox = "https://follower.example.com/outbox",
url = "https://follower.example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
val follower2 = userRepository.save(
User(
id = 3L,
name = "follower2",
domain = "follower2.example.com",
screenName = "followerUser2",
description = "This user is follower user 2.",
password = "",
inbox = "https://follower2.example.com/inbox",
outbox = "https://follower2.example.com/outbox",
url = "https://follower2.example.com",
publicKey = "",
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
)
)
userRepository.createFollower(user.id, follower.id)
userRepository.createFollower(user.id, follower2.id)
userRepository.findFollowersById(user.id).let {
assertIterableEquals(listOf(follower, follower2), it)
} }
} }
@Test @Test
fun `createFollower フォロワー追加`() = runTest { fun `createFollower フォロワー追加`() = runTest {
val userRepository = UserRepository( newSuspendedTransaction {
db, val userRepository = UserRepository(
object : IdGenerateService { db,
override suspend fun generateId(): Long { object : IdGenerateService {
TODO("Not yet implemented") override suspend fun generateId(): Long {
TODO("Not yet implemented")
}
} }
}
)
val user = userRepository.save(
User(
0L,
"test",
"example.com",
"testUser",
"This user is test user.",
"https://example.com/inbox",
"",
"https://example.com/outbox",
"https://example.com",
publicKey = "",
createdAt = Instant.now()
) )
) val user = userRepository.save(
val follower = userRepository.save( User(
User( 0L,
1L, "test",
"follower", "example.com",
"follower.example.com", "testUser",
"followerUser", "This user is test user.",
"This user is follower user.", "https://example.com/inbox",
"", "",
"https://follower.example.com/inbox", "https://example.com/outbox",
"https://follower.example.com/outbox", "https://example.com",
"https://follower.example.com", publicKey = "",
publicKey = "", createdAt = Instant.now()
createdAt = Instant.now() )
) )
) val follower = userRepository.save(
userRepository.createFollower(user.id, follower.id) User(
transaction { 1L,
"follower",
"follower.example.com",
"followerUser",
"This user is follower user.",
"",
"https://follower.example.com/inbox",
"https://follower.example.com/outbox",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
)
)
userRepository.createFollower(user.id, follower.id)
val followerIds = val followerIds =
UsersFollowers.select { UsersFollowers.userId eq user.id }.map { it[UsersFollowers.followerId] } UsersFollowers.select { UsersFollowers.userId eq user.id }.map { it[UsersFollowers.followerId] }
assertIterableEquals(listOf(follower.id), followerIds) assertIterableEquals(listOf(follower.id), followerIds)
} }
} }
} }

View File

@ -19,38 +19,48 @@ class ServerInitialiseServiceImplTest {
val metaRepository = mock<IMetaRepository> { val metaRepository = mock<IMetaRepository> {
onBlocking { get() } doReturn null onBlocking { get() } doReturn null
onBlocking { save(any()) } doReturn Unit onBlocking { save(any()) } doReturn Unit
onBlocking {
transaction(any<suspend () -> Unit>())
} doSuspendableAnswer {
(it.arguments[0] as suspend () -> Unit).invoke()
}
} }
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository) val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
serverInitialiseServiceImpl.init() serverInitialiseServiceImpl.init()
verify(metaRepository,times(1)).save(any()) verify(metaRepository, times(1)).save(any())
} }
@Test @Test
fun `init メタデータが存在して同じバージョンのときは何もしない`() = runTest { fun `init メタデータが存在して同じバージョンのときは何もしない`() = runTest {
val meta = Meta(ServerUtil.getImplementationVersion(), Jwt(UUID.randomUUID(),"aaafafd","afafasdf")) val meta = Meta(ServerUtil.getImplementationVersion(), Jwt(UUID.randomUUID(), "aaafafd", "afafasdf"))
val metaRepository = mock<IMetaRepository> { val metaRepository = mock<IMetaRepository> {
onBlocking { get() } doReturn meta onBlocking { get() } doReturn meta
} }
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository) val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
serverInitialiseServiceImpl.init() serverInitialiseServiceImpl.init()
verify(metaRepository,times(0)).save(any()) verify(metaRepository, times(0)).save(any())
} }
@Test @Test
fun `init メタデータが存在して違うバージョンのときはバージョンを変更する`() = runTest { fun `init メタデータが存在して違うバージョンのときはバージョンを変更する`() = runTest {
val meta = Meta("1.0.0", Jwt(UUID.randomUUID(),"aaafafd","afafasdf")) val meta = Meta("1.0.0", Jwt(UUID.randomUUID(), "aaafafd", "afafasdf"))
val metaRepository = mock<IMetaRepository> { val metaRepository = mock<IMetaRepository> {
onBlocking { get() } doReturn meta onBlocking { get() } doReturn meta
onBlocking { save(any()) } doReturn Unit onBlocking { save(any()) } doReturn Unit
onBlocking {
transaction(any<suspend () -> Unit>())
} doSuspendableAnswer {
(it.arguments[0] as suspend () -> Unit).invoke()
}
} }
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository) val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
serverInitialiseServiceImpl.init() serverInitialiseServiceImpl.init()
verify(metaRepository,times(1)).save(any()) verify(metaRepository, times(1)).save(any())
argumentCaptor<Meta> { argumentCaptor<Meta> {
verify(metaRepository,times(1)).save(capture()) verify(metaRepository, times(1)).save(capture())
assertEquals(ServerUtil.getImplementationVersion(),firstValue.version) assertEquals(ServerUtil.getImplementationVersion(), firstValue.version)
} }
} }
} }