Skip to content
Open
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
implementation 'com.auth0:java-jwt:4.2.1'

// QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api:3.1.0'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api:2.1.1'
Comment on lines +44 to +48
Copy link

@coderabbitai coderabbitai bot Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

QueryDSL 버전 확인 필요

QueryDSL 5.0.0을 사용 중이지만, 이 버전이 최신 안정 버전인지 확인이 필요합니다. 보안 패치와 버그 수정이 포함된 최신 버전을 사용하는 것이 좋습니다.


🌐 Web query:

What is the latest stable version of QueryDSL for Jakarta EE?

💡 Result:

The latest stable QueryDSL release for Jakarta EE is 5.1.0 (checked Nov 11, 2025). [1][2]

Sources:

  • QueryDSL releases/notes. [1]
  • QueryDSL 5.1.0 Javadoc / Maven artifact listing. [2]

QueryDSL을 5.1.0으로 업그레이드하세요

현재 QueryDSL 5.0.0을 사용 중이지만, 최신 안정 버전은 5.1.0입니다. 보안 패치와 버그 수정을 위해 build.gradle의 44-45번 줄을 다음과 같이 업데이트하세요:

implementation 'com.querydsl:querydsl-jpa:5.1.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.1.0:jakarta'
🤖 Prompt for AI Agents
In build.gradle around lines 44 to 48, the QueryDSL dependency and its
annotation processor are pinned to 5.0.0; update the QueryDSL coordinates on
lines 44-45 to use version 5.1.0 by changing both the implementation and the
querydsl-apt annotationProcessor entries to use ':5.1.0:jakarta' while leaving
the other annotationProcessor entries unchanged.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://mvnrepository.com/artifact/com.querydsl/querydsl-jpa/5.1.0

확인해보니 쿼리 DSL 전 버전에 취약점이 있네요. 지원 중단돼서 그런가...?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🌐 Web query:

QueryDSL 5.0.0 security vulnerabilities CVE

💡 Result:

Short answer: Yes — Querydsl has a reported HQL/SQL injection vulnerability identified as CVE-2024-49203 that affects Querydsl 5.x (including 5.0.0/<=5.1.0 in multiple advisories). The issue concerns injection via JPAQuery.orderBy when untrusted input is used. Recommend not passing untrusted input into orderBy and upgrading to a patched/non-vulnerable release or forked build where the fix is available. [1][2][3][4]

Sources

  • CSIRT.SK advisory describing CVE-2024-49203 and affected Querydsl versions. [1]
  • GitHub Advisory / OpenFeign querydsl security advisory for the same issue (GHSA-6q3q-6v5j-h6vg). [2]
  • Snyk vulnerability page for CVE-2024-49203. [3]
  • Maven / mvnrepository listing for querydsl-apt 5.0.0 that flags CVE-2024-49203. [4]

If you want, I can: (a) check the current latest Querydsl release and which exact versions include the fix, or (b) show concrete mitigations/workarounds and sample code to safely handle ordering parameters.


🌐 Web query:

QueryDSL maintenance status 2025 CVE-2024-49203 fix

💡 Result:

Short answer: Querydsl is actively maintained in 2025 and the CVE-2024-49203 HQL/SQL‑injection issue was fixed — upgrade to the patched releases (Querydsl 5.6.1, 6.10.1; OpenFeign Querydsl 7.0 also lists fixes). Apply the update or validate/whitelist any user-controlled orderBy input if you cannot upgrade immediately. [1][2][3]

Sources:

  • Querydsl release notes showing fixes for CVE-2024-49203 (releases including 5.6.1 and 6.10.1). [1]
  • GitHub security advisory for the issue (GHSA-6q3q-6v5j-h6vg / CVE-2024-49203) with patched versions listed. [2]
  • CSIRT.SK advisory and disclosure details with mitigation guidance. [3]

@hyxklee 좋은 지적 감사합니다! 취약점 확인 결과를 공유드립니다:

취약점 정보 (CVE-2024-49203)

  • QueryDSL 5.0.0과 5.1.0 모두 HQL/SQL 인젝션 취약점이 존재합니다
  • JPAQuery.orderBy()에 검증되지 않은 사용자 입력이 전달될 때 발생합니다

유지보수 상태
QueryDSL은 여전히 활발히 유지보수되고 있습니다. 지원 중단이 아니며, 해당 취약점은 이미 패치되었습니다.

권장사항
build.gradle의 QueryDSL 버전을 5.6.1 이상으로 업그레이드하세요:

// QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.6.1:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.6.1:jakarta'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api:3.1.0'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api:2.1.1'

이 PR에서 QueryDSL로 전환하는 시점에 보안 패치가 적용된 버전을 사용하는 것이 중요합니다. 현재 코드를 확인한 결과 orderBy(post.id.desc())처럼 정적 표현식을 사용하고 있어 직접적인 위험은 낮지만, 예방 차원에서 패치된 버전 사용을 강력히 권장합니다.


// mapStruct
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.springframework.data.repository.query.Param;


public interface PostRepository extends JpaRepository<Post, Long> {
public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryCustom {

@Query("""
SELECT p FROM Post p
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package leets.weeth.domain.board.domain.repository;

import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.repository.query.Param;

import leets.weeth.domain.board.domain.entity.Post;
import leets.weeth.domain.board.domain.entity.enums.Category;
import leets.weeth.domain.board.domain.entity.enums.Part;

public interface PostRepositoryCustom {

Slice<Post> findRecentPart(Pageable pageable);
Slice<Post> findRecentEducation(Pageable pageable);
Slice<Post> searchPart(String kw,Pageable pageable);
Slice<Post> searchEducation(String kw, Pageable pageable);
List<String> findDistinctStudyNamesByPart(Part part);
Slice<Post> findByPartAndOptionalFilters(Part part, Category category, Integer cardinal, String studyName, Integer week, Pageable pageable);
Slice<Post> findByCategoryAndOptionalCardinalWithPart(String partName, Category category, Integer cardinal, Pageable pageable);
Slice<Post> findByCategoryAndCardinalNumberWithPart(String partName, Category category, Integer cardinal, Pageable pageable);
Slice<Post> findByCategoryAndCardinalInWithPart(String partName, Category category, Collection<Integer> cardinals, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
package leets.weeth.domain.board.domain.repository;

import java.beans.Expression;
import java.util.Collection;
import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.repository.query.Param;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Repository;

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;

import jakarta.persistence.EntityManager;
import leets.weeth.domain.board.domain.entity.Post;
import leets.weeth.domain.board.domain.entity.QPost;
import leets.weeth.domain.board.domain.entity.enums.Category;
import leets.weeth.domain.board.domain.entity.enums.Part;
import lombok.RequiredArgsConstructor;


public class PostRepositoryImpl implements PostRepositoryCustom {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

@repository 어노테이션이 누락되었습니다.

클래스에 @Repository 어노테이션이 없습니다. Spring의 컴포넌트 스캔 및 예외 변환을 위해 필요하며, JPA repository 구현체의 표준 패턴입니다.

다음 diff를 적용하세요:

+@Repository
 public class PostRepositoryImpl implements PostRepositoryCustom {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class PostRepositoryImpl implements PostRepositoryCustom {
@Repository
public class PostRepositoryImpl implements PostRepositoryCustom {
🤖 Prompt for AI Agents
In
src/main/java/leets/weeth/domain/board/domain/repository/PostRepositoryImpl.java
around line 19, the class PostRepositoryImpl is missing the Spring @Repository
annotation; add the @Repository annotation to the class declaration and import
org.springframework.stereotype.Repository so Spring can component-scan and apply
exception translation for this JPA repository implementation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 방식의 구현법은 공식문서를 기반으로 구현해주신 걸까요?? 단순 궁금

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://sjh9708.tistory.com/174#google_vignette
위 블로그들 포함하여 여러 구현 블로그 따라 했습니당


private final JPAQueryFactory queryFactory;
private final QPost post = QPost.post;

public PostRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}

@Override
public Slice<Post> findRecentPart(Pageable pageable) {
List<Post> result = queryFactory
.selectFrom(post)
.where(post.category.in(Category.StudyLog, Category.Article))
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();

if (hasNext) {
result.remove(pageable.getPageSize());
}

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public Slice<Post> searchPart(String kw, Pageable pageable) {
List<Post> result = queryFactory
.selectFrom(post)
.where(post.category.in(Category.StudyLog, Category.Article)
.and(post.title.containsIgnoreCase(kw)
.or(post.content.containsIgnoreCase(kw))
Comment on lines +60 to +61
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kw가 null일 경우 NPE이 발생하지는 않나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 해보았는데 아무것도 입력하지 않는 경우 호출이 불가합니다! 따라서 npe발생이 안될거라 예상됩니당

Controller 확인 결과 , RequestParam이 붙여져있어서 괜찮을 것 같습니다!

))
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();

if (hasNext) {
result.remove(pageable.getPageSize());
}

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public Slice<Post> findRecentEducation(Pageable pageable) {
List<Post> result = queryFactory
.selectFrom(post)
.where(post.category.eq(Category.Education))
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();

if (hasNext) {
result.remove(pageable.getPageSize());
}

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public Slice<Post> searchEducation(String kw, Pageable pageable) {
List<Post> result = queryFactory
.selectFrom(post)
.where(
post.category.eq(Category.Education)
.and(
post.title.containsIgnoreCase(kw)
.or(post.content.containsIgnoreCase(kw))
)
)
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();

if (hasNext) {
result.remove(pageable.getPageSize());
}

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public List<String> findDistinctStudyNamesByPart(Part part) {

return queryFactory
.select(post.studyName)
.distinct()
.from(post)
.where(
part == Part.ALL
? post.studyName.isNotNull()
: post.part.eq(part).and(post.studyName.isNotNull())
)
.orderBy(post.studyName.asc())
.fetch();
}

@Override //조건이 많은 쿼리라 BooleanBuilder 사용
public Slice<Post> findByPartAndOptionalFilters(Part part, Category category, Integer cardinal, String studyName, Integer week, Pageable pageable) {

BooleanBuilder builder = new BooleanBuilder();

if (part == Part.ALL) {
builder.and(post.part.eq(Part.ALL).or(post.part.ne(Part.ALL)));
}else {
builder.and(post.part.eq(part).or(post.part.eq(Part.ALL)));
}

if (category != null) {
builder.and(post.category.eq(category));
}

if (cardinal != null) {
builder.and(post.cardinalNumber.eq(cardinal));
}

if (studyName != null) {
builder.and(post.studyName.eq(studyName));
}

if (week != null) {
builder.and(post.week.eq(week));
}

List<Post> result = queryFactory
.selectFrom(post)
.where(builder)
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();

if (hasNext) {
result.remove(pageable.getPageSize());
}
return new SliceImpl<>(result, pageable, hasNext);

}

@Override
public Slice<Post> findByCategoryAndOptionalCardinalWithPart(String partName, Category category, Integer cardinal, Pageable pageable) {

BooleanBuilder builder = new BooleanBuilder();

builder.and(post.category.eq(category));

if (cardinal != null) {
builder.and(post.cardinalNumber.eq(cardinal));
}

if (!"ALL".equals(partName)) { //partName 조건
builder.and(
Expressions.numberTemplate(Integer.class,
"FIND_IN_SET({0}, {1})", partName, post.parts).gt(0)
.or(Expressions.numberTemplate(Integer.class,
"FIND_IN_SET('ALL', {0})", post.parts).gt(0))
);
Comment on lines +194 to +198
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

데이터베이스 종속적인 SQL 함수 사용에 대한 검토가 필요합니다.

FIND_IN_SET 함수는 MySQL/MariaDB 전용 함수로, 데이터베이스 이식성(portability) 문제를 야기합니다. 또한 동일한 로직이 세 개의 메소드에서 반복되고 있습니다.

영향:

  • PostgreSQL, Oracle 등 다른 데이터베이스로 마이그레이션 시 코드 수정 필요
  • FIND_IN_SET은 인덱스를 사용하지 못해 성능 저하 가능
  • 중복 코드로 인한 유지보수 부담

권장 사항:

  1. 단기 해결책: 중복된 FIND_IN_SET 로직을 private helper 메소드로 추출하여 재사용하세요:
private BooleanExpression createPartFilter(String partName) {
    if ("ALL".equals(partName)) {
        return null;
    }
    
    BooleanExpression containsPart = 
        Expressions.numberTemplate(Integer.class, 
            "FIND_IN_SET({0}, {1})", partName, post.parts).gt(0);
    
    BooleanExpression containsAll = 
        Expressions.numberTemplate(Integer.class, 
            "FIND_IN_SET('ALL', {0})", post.parts).gt(0);
    
    return containsPart.or(containsAll);
}
  1. 장기 해결책: parts 필드를 별도의 연관 테이블로 정규화하는 것을 고려하세요. 이는 데이터베이스 독립성과 쿼리 성능을 개선합니다.

현재 구현을 유지할지, 데이터 모델 변경을 고려할지 팀 내에서 논의가 필요합니다.

Also applies to: 224-228, 256-261


🏁 Script executed:

#!/bin/bash
# Verify FIND_IN_SET usage at specified lines
echo "=== Checking lines 194-198, 224-228, 256-261 in PostRepositoryImpl.java ==="
fd PostRepositoryImpl.java --type f --exec cat {} \; | head -300 | tail -120

Length of output: 3497


🏁 Script executed:

#!/bin/bash
# Get full method context around the specified lines
echo "=== Getting full method implementations ==="
fd PostRepositoryImpl.java --type f --exec sed -n '170,210p;220,235p;245,270p' {} \;

Length of output: 2425


🏁 Script executed:

#!/bin/bash
# Search for all FIND_IN_SET occurrences in the repository
echo "=== Searching for all FIND_IN_SET usage ==="
rg -n "FIND_IN_SET" -C 5 --type java

Length of output: 9274


🏁 Script executed:

#!/bin/bash
# Check for database configuration files
echo "=== Looking for database/persistence configuration ==="
fd -e yml -e yaml -e properties -e xml | xargs rg -l "database|persistence|jpa|hibernate|datasource" 2>/dev/null | head -10

Length of output: 214


🏁 Script executed:

#!/bin/bash
# Check if there's a query abstraction or utility layer
echo "=== Searching for query helper or expression builder classes ==="
rg -n "class.*Expression|class.*Query|interface.*Builder" --type java | grep -i "helper\|util\|builder" | head -20

Length of output: 202


🏁 Script executed:

#!/bin/bash
# Check database configuration in properties files
echo "=== Checking database configuration ==="
fd application-prod.yml application-dev.yml application-local.yml --type f --exec cat {} \;

Length of output: 214


🏁 Script executed:

#!/bin/bash
# Search for any comments or documentation about database choice
echo "=== Searching for database-related comments or docs ==="
rg -i "mysql|postgres|oracle|database.*driver|h2" --type yml --type yaml --type properties -B 2 -A 2

Length of output: 83


🏁 Script executed:

#!/bin/bash
# Check if there are any GitHub issues or documentation about database portability
echo "=== Looking for README or documentation files ==="
fd -e md -e txt | xargs grep -l -i "database\|mysql\|postgres" 2>/dev/null | head -5

Length of output: 59


🏁 Script executed:

#!/bin/bash
# Check the exact state: compare all three FIND_IN_SET implementations
echo "=== Comparing all three FIND_IN_SET implementations ==="
echo "=== Method 1: findByCategoryAndOptionalCardinalWithPart (lines 193-199) ==="
rg -A 7 "findByCategoryAndOptionalCardinalWithPart" src/main/java/leets/weeth/domain/board/domain/repository/PostRepositoryImpl.java | head -20
echo ""
echo "=== Method 2: findByCategoryAndCardinalNumberWithPart (lines 222-231) ==="
rg -A 10 "findByCategoryAndCardinalNumberWithPart" src/main/java/leets/weeth/domain/board/domain/repository/PostRepositoryImpl.java | grep -A 10 "if.*ALL"
echo ""
echo "=== Method 3: findByCategoryAndCardinalInWithPart (lines 254-264) ==="
rg -A 10 "findByCategoryAndCardinalInWithPart" src/main/java/leets/weeth/domain/board/domain/repository/PostRepositoryImpl.java | grep -A 10 "if.*ALL"

Length of output: 930


🏁 Script executed:

#!/bin/bash
# Check README for database information
echo "=== Checking README.md for database information ==="
cat README.md | head -100

Length of output: 2247


🏁 Script executed:

#!/bin/bash
# Verify database config files with correct fd syntax
echo "=== Checking database configuration files ==="
fd application.*\.y -e yml

Length of output: 240


🏁 Script executed:

#!/bin/bash
# Extract database info from config
echo "=== Database configuration details ==="
find . -name "application*.y*ml" 2>/dev/null | xargs cat 2>/dev/null | grep -A 5 -B 5 -i "database\|datasource\|jpa\|hibernate" | head -50

Length of output: 1030


메서드 1만 리팩토링이 필요합니다. 코드 패턴 일관성을 맞추세요.

세 메서드 중 첫 번째 메서드만 인라인 표현식을 사용하고 있고, 두 번째와 세 번째 메서드는 이미 변수로 추출되어 있습니다. MySQL은 의도적으로 설정되어 있으므로 데이터베이스 이식성은 현재 주요 우려사항이 아닙니다.

조치 사항:
findByCategoryAndOptionalCardinalWithPart (194-198줄)에서 두 번째, 세 번째 메서드처럼 변수로 추출하여 패턴을 일관되게 유지하세요:

if (!"ALL".equals(partName)) {
    BooleanExpression containsPart =
        Expressions.numberTemplate(Integer.class,
            "FIND_IN_SET({0}, {1})", partName, post.parts).gt(0);
    
    BooleanExpression containsAll =
        Expressions.numberTemplate(Integer.class,
            "FIND_IN_SET('ALL', {0})", post.parts).gt(0);
    
    builder.and(containsPart.or(containsAll));
}
🤖 Prompt for AI Agents
In
src/main/java/leets/weeth/domain/board/domain/repository/PostRepositoryImpl.java
around lines 194-198, the first method uses inline Expressions.numberTemplate
calls while the other two methods extract those expressions into variables;
refactor this block to extract the FIND_IN_SET expressions into two
BooleanExpression variables (e.g., containsPart and containsAll) and then use
builder.and(containsPart.or(containsAll)) inside the existing if
(!"ALL".equals(partName)) check so the code pattern matches the other methods.

}

List<Post> result = queryFactory
.selectFrom(post)
.where(builder)
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();
boolean hasNext = result.size() > pageable.getPageSize();
if (hasNext) result.remove(pageable.getPageSize());

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public Slice<Post> findByCategoryAndCardinalNumberWithPart(String partName, Category category, Integer cardinal, Pageable pageable) {

BooleanBuilder builder = new BooleanBuilder();

builder.and(post.category.eq(category));
builder.and(post.cardinalNumber.eq(cardinal));

if (!"ALL".equals(partName)) {
BooleanExpression containsPart =
Expressions.numberTemplate(Integer.class, "FIND_IN_SET({0}, {1})", partName, post.parts).gt(0);

BooleanExpression containsAll =
Expressions.numberTemplate(Integer.class,
"FIND_IN_SET('ALL', {0})", post.parts).gt(0);

builder.and(containsPart.or(containsAll));
}

List<Post> result = queryFactory
.selectFrom(post)
.where(builder)
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();
if (hasNext) result.remove(pageable.getPageSize());

return new SliceImpl<>(result, pageable, hasNext);
}

@Override
public Slice<Post> findByCategoryAndCardinalInWithPart(String partName, Category category, Collection<Integer> cardinals, Pageable pageable) {
BooleanBuilder builder = new BooleanBuilder();

builder.and(post.category.eq(category));
builder.and(post.cardinalNumber.in(cardinals));

if (!"ALL".equals(partName)) {
BooleanExpression containsPart =
Expressions.numberTemplate(Integer.class,
"FIND_IN_SET({0}, {1})", partName, post.parts).gt(0);

BooleanExpression containsAll =
Expressions.numberTemplate(Integer.class,
"FIND_IN_SET('ALL', {0})", post.parts).gt(0);

builder.and(containsPart.or(containsAll));
}

List<Post> result = queryFactory
.selectFrom(post)
.where(builder)
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = result.size() > pageable.getPageSize();
if (hasNext) result.remove(pageable.getPageSize());

return new SliceImpl<>(result, pageable, hasNext);
}
}
17 changes: 17 additions & 0 deletions src/main/java/leets/weeth/global/config/QuerydslConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package leets.weeth.global.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.querydsl.jpa.impl.JPAQueryFactory;

import jakarta.persistence.EntityManager;

@Configuration
public class QuerydslConfig {

@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
Loading