kotlin에서 Query-dsl을 사용하다 보면 이래저래 불편함이 있죠.
그렇다고 안 쓰기엔 JPA로 동적쿼리를 작성하기엔 JPA로는 굉장히 불편하죠
그래서 Kotlin-Jdsl을 사용하기로 하였습니다.
라인에서 만든 라이브러리죠 github 링크입니다 - kotlin-jdsl
그런데 구글링 중 Kotlin-Jdsl로 Dynamic Query 작성하는 법을 찾을 수가 없더라고요
그래서 제가 사용하는 방법을 공유합니다. 더 좋은 방법이 있으면 댓글 부탁드립니다 :)
repository를 작성해보겠습니다.
interface PostRepository {
fun findByTitleOrAuthor(title: String?, authorName: String?) : List<Post>
}
@Repository
internal class PostRepositoryImpl(
private val queryFactory: SpringDataQueryFactory,
) : PostRepository {
override fun findByTitleOrAuthor(title: String?, authorName: String?): List<Post> {
return queryFactory.listQuery<PostEntity> {
select(entity(PostEntity::class))
from(entity(PostEntity::class))
fetch(PostEntity::author)
// title과 authorName의 값에 따라 동적쿼리를 작성합니다
where(dynamicAndFactory(title, authorName))
}
}
}
이제 title과 authorName으로 동적쿼리를 작성해보겠습니다.
private fun <T> SpringDataCriteriaQueryDsl<T>.dynamicAndFactory(
title: String?,
authorName: String?
): PredicateSpec {
return and(
title?.let { column(PostEntity::title).equal(title) },
authorName?.let { column(AuthorEntity::name).equal(authorName)}
)
}
다음과 같은 방식으로 작성가능합니다.
코틀린의 확장함수기능을 활용하여 작성하였습니다.
title과 authorName이 null이면 where조건이 작성되지 않습니다.
검증하는 코드는 다음과 같습니다
... 데이터 setup
@Autowired
private lateinit var sut: PostRepositoryImpl
@Test
fun `제목과 작가를 null로 조회합니다`() {
//given //when
val result = sut.findByTitleOrAuthor(null, null)
// then
assertEquals(result.size, 12)
}
@Test
fun `제목과 작가를 입력하여 조회합니다`() {
//given //when
val result = sut.findByTitleOrAuthor("1", "lyn")
//then
assertEquals(result.size, 1)
}
@Test
fun `제목만 조회합니다`() {
//given //when
val result = sut.findByTitleOrAuthor("1", null)
// then
assertEquals(result.size, 2)
}
@Test
fun `작가만 조회합니다`() {
//given //when
val result = sut.findByTitleOrAuthor(null, "gon")
//then
assertEquals(result.size, 7)
}
위에서 부터 차례로 실행되는 query를 확인하여보겠습니다
네 보시면 query가 예상대로 나가는걸 확인 할수 있습니다.
and를 제외한 or, between또한 확장함수를 응용하면 충분히 작성 하실수 있습니다.
예제코드는 해당 링크에서 study-kotlin-jsdl 확인하실수 있습니다.