Kotlin QueryDsl dynamic search

정명진·2023년 6월 10일

이번 사이드 프로젝트를 하며 다이나믹 옵션에 따라 검색이 가능한 화면을 만들어야 했다.

기본 JPA 에서 제공하는 정렬이나, 필터링 기능으로는 보기에 좋지 않아 방법이 없을까 하다가 QueryDsl로 해결을 했다.

@GetMapping("/view")
    fun view(authentication: Authentication, @RequestParam(name = "tag", required = false, defaultValue = "") tag: String, @RequestParam(name = "sort", required = false, defaultValue = "") sort: List<String>): ResponseEntity<ResponseDto>{
        val hashTagMainView = hashTagViewUseCase.getHashTagMainView(authentication.toUserId(), tag, sort)
        return ResponseEntity<ResponseDto>(DataResponseDto(hashTagMainView), HttpStatus.OK)
    }

검색 조건이 없으면 전체 결과를 보내줘야 했다. QueryDsl의 BooleanExpression을 활용하면 검색 조건이 만족하는게 없을 때 null을 주면 전체 검색을 하는 점과 다이나믹 정렬 조건을 쉽게 추가 할 수 있어서 바로 적용을 해봤다.

fun tagEq(tag: String): BooleanExpression? {
        return if (StringUtils.hasText(tag))  userHashTagJpaEntity.hashTag.text.eq(tag) else null
    }

    fun getSort(sort: List<String>): Array<OrderSpecifier<*>>{
        val sortSpecifications = mutableListOf<OrderSpecifier<*>>()

        for (value in sort) {
            if (value == "createdDate") {
                sortSpecifications.add(OrderSpecifier(Order.ASC, userHashTagJpaEntity.hashTag.createdDate))
            }else if (value == "-createdDate") {
                sortSpecifications.add(OrderSpecifier(Order.DESC, userHashTagJpaEntity.hashTag.createdDate))
            }
        }

        if (sortSpecifications.isEmpty()) {
            // 기본 옵션은 생성일 기준 오름차순
            sortSpecifications.add(OrderSpecifier(Order.ASC, userHashTagJpaEntity.hashTag.createdDate))
        }

        return sortSpecifications.toTypedArray()
    }

여기서 Array로 return한 이유는 QueryDsl의 orderBy 에 파라미터가 varargs로 전달해야 하기때문이다. 실제로 해당 옵션에 가보면

    /**
     * Add order expressions
     *
     * @param o order
     * @return the current object
     */
    Q orderBy(OrderSpecifier<?>... o);

위와 같이 설명되어있다. kotlin에서는 Array에 *을 붙여주면 varargs와 같이 넘겨줄 수 있기 때문에 List 대신 사용하게 되었다.

profile
개발자로 입사했지만 정체성을 잃어가는중... 다시 준비 시작이다..

0개의 댓글