// 1. 검색어 조건
    if (query != null && !query.isEmpty()) {
        builder.and(tree.title.containsIgnoreCase(query.trim())
            .or(tree.book.title.containsIgnoreCase(query.trim())));
    }

위의 코드에서 문제는 뭘까? and().or() 형태로 체이닝이 되면 의도하지 않은 결과 일어난다. 위 코드에서는 or()을 우선적으로 처리해야 하기 때문에, 먼저 수행하도록 해야함. 논리학에서 괄호를 치는 행위가 필요하다.

따라서 다음과 같이 or을 먼저 적용하고, 적용된 내용을 and() 로 묶어주는 것이 타당하다.

// 1. 검색어 조건
    if (query != null && !query.isEmpty()) {
        BooleanExpression titleOrBookTitle = tree.title.containsIgnoreCase(query.trim())
            .or(tree.book.title.containsIgnoreCase(query.trim()));
        builder.and(titleOrBookTitle);
    }

con