< 기존 인기순 쿼리 >
@Query("""
SELECT p FROM TherapyPost p
WHERE p.deletedAt IS NULL
AND (:cursorScore IS NULL OR
p.popularityScore < :cursorScore OR
(p.popularityScore = :cursorScore AND p.id < :cursorId))
ORDER BY p.popularityScore DESC, p.id DESC
""")
List<TherapyPost> findFeedPopular(
@Param("cursorScore") Long cursorScore,
@Param("cursorId") Long cursorId,
Pageable pageable
);
cursorScore이 없으면 바로 true 되는거로 생각되었는데 첫 페이지에 제대로 반영 못함.
< Hibernate가 PostgreSQL에 보내는 실제 SQL >
SELECT * FROM therapy_posts
WHERE ($1 IS NULL OR popularity_score < $1)
:cursorScore 같은 이름 있는 파라미터가 $1, $2 같은 위치 기반 바인딩 변수로 바뀜. 만약 여기에 150 이 들어가게 된다면 $1은 Int네? 라고 판단하게됨. 근데 null을 보면 이게 어떤 타입인지 PostgreSQL은 판단할 수 없는거임
그래서 여기서 500 에러를 내는거임
그래서 아래와 같이 수정
// null을 아예 안 넘김
if (popCursor == null) {
// 첫 페이지 → WHERE절에 커서 조건 자체가 없는 쿼리 호출
repo.findFeedPopular(limit);
} else {
// 다음 페이지 → non-null 값만 넘김, PostgreSQL이 타입 추론 가능
repo.findFeedPopular(popCursor.score(), popCursor.id(), limit);
}
즉, null을 넘기지 않도록 쿼리를 다시 작성. 기존 4개의 쿼리였다면 지금은 분기처리로 인해 8개 쿼리이긴함.