feat(subbanner): 기간 조회와 소프트 삭제 저장소를 추가한다

This commit is contained in:
2026-10-29 23:20:38 +09:00
parent 5f6b8d4cf5
commit aa6863f4f9
5 changed files with 546 additions and 0 deletions
@@ -0,0 +1,73 @@
package kr.co.vividnext.sodalive.v2.subbanner.adapter.out.persistence
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.v2.subbanner.adapter.out.persistence.QSubBannerEntity.subBannerEntity
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBanner
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBannerPlacement
import kr.co.vividnext.sodalive.v2.subbanner.port.out.SubBannerRepository
import org.springframework.stereotype.Repository
import java.time.LocalDateTime
import java.time.temporal.ChronoUnit
import javax.persistence.EntityManager
@Repository
class DefaultSubBannerRepository(
private val entityManager: EntityManager,
private val queryFactory: JPAQueryFactory
) : SubBannerRepository {
override fun findById(id: Long): SubBanner? = entityManager.find(SubBannerEntity::class.java, id)
?.takeIf { it.isActive }?.toDomain()
override fun findAllByPlacement(placement: SubBannerPlacement): List<SubBanner> = queryFactory
.selectFrom(subBannerEntity)
.where(subBannerEntity.placement.eq(placement), subBannerEntity.isActive.isTrue)
.orderBy(subBannerEntity.id.asc())
.fetch()
.map { it.toDomain() }
override fun findVisibleByPlacement(placement: SubBannerPlacement, now: LocalDateTime): List<SubBanner> {
val visibleAt = now.truncatedTo(ChronoUnit.SECONDS)
return queryFactory
.selectFrom(subBannerEntity)
.where(
subBannerEntity.placement.eq(placement),
subBannerEntity.isActive.isTrue,
subBannerEntity.startDate.isNull.or(subBannerEntity.startDate.loe(visibleAt)),
subBannerEntity.endDate.isNull.or(subBannerEntity.endDate.goe(visibleAt))
)
.orderBy(subBannerEntity.id.asc())
.fetch()
.map { it.toDomain() }
}
override fun save(subBanner: SubBanner): SubBanner {
val startDate = subBanner.startDate?.truncatedTo(ChronoUnit.SECONDS)
val endDate = subBanner.endDate?.truncatedTo(ChronoUnit.SECONDS)
val entity = if (subBanner.id == null) {
SubBannerEntity(
subBanner.placement,
subBanner.imagePath,
subBanner.webUrl,
subBanner.androidDeepLink,
subBanner.iosDeepLink,
startDate,
endDate
).also { entityManager.persist(it) }
} else {
entityManager.find(SubBannerEntity::class.java, subBanner.id).apply {
placement = subBanner.placement
imagePath = subBanner.imagePath
webUrl = subBanner.webUrl
androidDeepLink = subBanner.androidDeepLink
iosDeepLink = subBanner.iosDeepLink
this.startDate = startDate
this.endDate = endDate
}
}
return entity.toDomain()
}
override fun deleteById(id: Long) {
entityManager.find(SubBannerEntity::class.java, id).isActive = false
}
}
@@ -0,0 +1,45 @@
package kr.co.vividnext.sodalive.v2.subbanner.adapter.out.persistence
import kr.co.vividnext.sodalive.common.BaseEntity
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBanner
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBannerPlacement
import org.hibernate.annotations.DynamicUpdate
import java.time.LocalDateTime
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
import javax.persistence.Index
import javax.persistence.Table
@Entity
@DynamicUpdate
@Table(name = "sub_banner", indexes = [Index(name = "idx_sub_banner_placement_id", columnList = "placement, id")])
class SubBannerEntity(
@Enumerated(EnumType.STRING)
@Column(name = "placement", nullable = false, length = 32)
var placement: SubBannerPlacement,
@Column(name = "image_path", nullable = false, columnDefinition = "LONGTEXT")
var imagePath: String,
@Column(name = "web_url", columnDefinition = "LONGTEXT")
var webUrl: String?,
@Column(name = "android_deep_link", columnDefinition = "LONGTEXT")
var androidDeepLink: String?,
@Column(name = "ios_deep_link", columnDefinition = "LONGTEXT")
var iosDeepLink: String?,
@Column(name = "start_date", columnDefinition = "TIMESTAMP")
var startDate: LocalDateTime?,
@Column(name = "end_date", columnDefinition = "TIMESTAMP")
var endDate: LocalDateTime?,
@Column(name = "is_active", nullable = false)
var isActive: Boolean = true
) : BaseEntity() {
fun toDomain(): SubBanner = SubBanner(id, placement, imagePath, webUrl, androidDeepLink, iosDeepLink, startDate, endDate)
}
@@ -0,0 +1,13 @@
package kr.co.vividnext.sodalive.v2.subbanner.port.out
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBanner
import kr.co.vividnext.sodalive.v2.subbanner.domain.SubBannerPlacement
import java.time.LocalDateTime
interface SubBannerRepository {
fun findById(id: Long): SubBanner?
fun findAllByPlacement(placement: SubBannerPlacement): List<SubBanner>
fun findVisibleByPlacement(placement: SubBannerPlacement, now: LocalDateTime): List<SubBanner>
fun save(subBanner: SubBanner): SubBanner
fun deleteById(id: Long)
}