feat(content-ranking): 랭킹 차단 조회 포트를 추가한다

This commit is contained in:
2026-06-24 19:01:58 +09:00
parent 6fabcca03f
commit 90c5149df8
3 changed files with 144 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
package kr.co.vividnext.sodalive.v2.content.ranking.adapter.out.persistence
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.member.block.QBlockMember
import kr.co.vividnext.sodalive.v2.content.ranking.port.out.AudioRankingBlockPort
import org.springframework.stereotype.Repository
@Repository
class DefaultAudioRankingBlockRepository(
private val queryFactory: JPAQueryFactory
) : AudioRankingBlockPort {
override fun findBlockedCreatorMemberIds(memberId: Long, creatorMemberIds: Set<Long>): Set<Long> {
if (creatorMemberIds.isEmpty()) return emptySet()
val viewerBlock = QBlockMember("audioRankingViewerBlock")
val creatorBlock = QBlockMember("audioRankingCreatorBlock")
val viewerBlockedIds = queryFactory
.select(viewerBlock.blockedMember.id)
.from(viewerBlock)
.where(
viewerBlock.isActive.isTrue,
viewerBlock.member.id.eq(memberId),
viewerBlock.blockedMember.id.`in`(creatorMemberIds)
)
.fetch()
val creatorBlockedIds = queryFactory
.select(creatorBlock.member.id)
.from(creatorBlock)
.where(
creatorBlock.isActive.isTrue,
creatorBlock.member.id.`in`(creatorMemberIds),
creatorBlock.blockedMember.id.eq(memberId)
)
.fetch()
return (viewerBlockedIds + creatorBlockedIds).toSet()
}
}

View File

@@ -0,0 +1,5 @@
package kr.co.vividnext.sodalive.v2.content.ranking.port.out
interface AudioRankingBlockPort {
fun findBlockedCreatorMemberIds(memberId: Long, creatorMemberIds: Set<Long>): Set<Long>
}

View File

@@ -0,0 +1,100 @@
package kr.co.vividnext.sodalive.v2.content.ranking.adapter.out.persistence
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.configs.QueryDslConfig
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.member.block.BlockMember
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.context.annotation.Import
import javax.persistence.EntityManager
@DataJpaTest(
properties = [
"spring.cache.type=none",
"spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;NON_KEYWORDS=VALUE"
]
)
@Import(QueryDslConfig::class)
class DefaultAudioRankingBlockRepositoryTest @Autowired constructor(
private val entityManager: EntityManager,
queryFactory: JPAQueryFactory
) {
private val repository = DefaultAudioRankingBlockRepository(queryFactory)
@Test
@DisplayName("활성 양방향 차단된 크리에이터 member id만 조회한다")
fun shouldFindActiveBlockedCreatorMemberIdsInBothDirections() {
val viewer = saveUser("viewer")
val blockedByViewer = saveCreator("blocked-by-viewer")
val blocksViewer = saveCreator("blocks-viewer")
val inactiveBlocked = saveCreator("inactive-blocked")
val allowed = saveCreator("allowed")
val outsideInput = saveCreator("outside-input")
saveBlock(viewer, blockedByViewer, isActive = true)
saveBlock(blocksViewer, viewer, isActive = true)
saveBlock(viewer, inactiveBlocked, isActive = false)
saveBlock(viewer, outsideInput, isActive = true)
flushAndClear()
val blockedCreatorMemberIds = repository.findBlockedCreatorMemberIds(
memberId = viewer.id!!,
creatorMemberIds = setOf(blockedByViewer.id!!, blocksViewer.id!!, inactiveBlocked.id!!, allowed.id!!)
)
assertEquals(setOf(blockedByViewer.id, blocksViewer.id), blockedCreatorMemberIds)
}
@Test
@DisplayName("크리에이터 member id 목록이 비어 있으면 빈 집합을 반환한다")
fun shouldReturnEmptySetWhenCreatorMemberIdsIsEmpty() {
val viewer = saveUser("empty-viewer")
val creator = saveCreator("empty-creator")
saveBlock(viewer, creator, isActive = true)
flushAndClear()
val blockedCreatorMemberIds = repository.findBlockedCreatorMemberIds(
memberId = viewer.id!!,
creatorMemberIds = emptySet()
)
assertEquals(emptySet<Long>(), blockedCreatorMemberIds)
}
private fun saveCreator(nickname: String): Member {
return saveMember(nickname, MemberRole.CREATOR)
}
private fun saveUser(nickname: String): Member {
return saveMember(nickname, MemberRole.USER)
}
private fun saveMember(nickname: String, role: MemberRole): Member {
val member = Member(
email = "$nickname@test.com",
password = "password",
nickname = nickname,
role = role,
isActive = true
)
entityManager.persist(member)
entityManager.flush()
return member
}
private fun saveBlock(member: Member, blockedMember: Member, isActive: Boolean) {
val block = BlockMember(isActive = isActive)
block.member = member
block.blockedMember = blockedMember
entityManager.persist(block)
}
private fun flushAndClear() {
entityManager.flush()
entityManager.clear()
}
}