Conversation
Walkthrough엔티티 매핑과 상속 전략을 변경했습니다. Post의 JPA 상속 전략을 JOINED → SINGLE_TABLE로 전환했고, Record/Vote에 page 필드 추가 및 isOverview의 primitive→wrapper/nullable 제약 완화, Feed의 일부 컬럼 nullable 허용 및 @table 주석 처리, RecordQueryRepositoryImpl에서 post를 treat(...)로 처리하도록 쿼리 변경이 포함됩니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Repository as RecordQueryRepositoryImpl
participant QueryDSL
participant DB
Client->>Repository: findMyRecords(...)
Repository->>QueryDSL: build query using from(post) + treat(post, QRecord/ QVote) for page/isOverview
QueryDSL->>DB: execute SQL (single-table posts with dtype discriminator)
DB-->>QueryDSL: rows
QueryDSL-->>Repository: mapped results
Repository-->>Client: paged domain DTOs
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Test Results407 tests 407 ✅ 31s ⏱️ Results for commit 322ddd8. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (4)
src/main/java/konkuk/thip/roompost/adapter/out/mapper/RecordMapper.java (1)
24-31: Boolean → boolean 매핑 시 NPE 위험: null-safe 변환 필요RecordJpaEntity.isOverview가 Boolean로 변경되어 null일 수 있습니다. 현 코드에서 auto-unboxing이 일어나면 NPE 발생 가능. 안전 변환을 권장합니다.
- .isOverview(recordJpaEntity.getIsOverview()) + .isOverview(Boolean.TRUE.equals(recordJpaEntity.getIsOverview()))도메인 Record가 Boolean를 받도록 허용한다면(정책 변경 시) DTO/빌더 시그니처도 Boolean로 바꾸는 방법이 있습니다.
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java (2)
96-124: isOverview 필터 Boolean null 처리 및 페이지 범위 파라미터 안전성 보강isOverview 파라미터가 Boolean인데 null 케이스 처리가 없습니다. 또한 pageStart/pageEnd가 null일 경우 between 사용 시 NPE 위험이 있습니다.
- if (isOverview) { - voteCondition.and(vote.isOverview.isTrue()); - } else { - voteCondition.and(vote.isOverview.isFalse()) - .and(vote.page.between(pageStart, pageEnd)); - } + if (Boolean.TRUE.equals(isOverview)) { + voteCondition.and(vote.isOverview.isTrue()); + } else if (Boolean.FALSE.equals(isOverview)) { + voteCondition.and(vote.isOverview.isFalse()); + if (pageStart != null && pageEnd != null) { + voteCondition.and(vote.page.between(pageStart, pageEnd)); + } else if (pageStart != null) { + voteCondition.and(vote.page.goe(pageStart)); + } else if (pageEnd != null) { + voteCondition.and(vote.page.loe(pageEnd)); + } + } ... - if (isOverview) { - recordCondition.and(record.isOverview.isTrue()); - } else { - recordCondition.and(record.isOverview.isFalse()) - .and(record.page.between(pageStart, pageEnd)); - } + if (Boolean.TRUE.equals(isOverview)) { + recordCondition.and(record.isOverview.isTrue()); + } else if (Boolean.FALSE.equals(isOverview)) { + recordCondition.and(record.isOverview.isFalse()); + if (pageStart != null && pageEnd != null) { + recordCondition.and(record.page.between(pageStart, pageEnd)); + } else if (pageStart != null) { + recordCondition.and(record.page.goe(pageStart)); + } else if (pageEnd != null) { + recordCondition.and(record.page.loe(pageEnd)); + } + }비즈니스 상 isOverview 필수 파라미터라면 컨트롤러/서비스 단 유효성 검증을 추가해 주세요.
126-141: CASE 표현식 null 안전성: 정렬/투영 일관성을 위해 coalesce 추가dtype 일치 시 서브타입 컬럼 값이 null이면 CASE 결과가 null이 됩니다. 정렬(특히 desc)과 select 투영 시 데이터베이스마다 null 정렬 규칙이 달라 예측성이 떨어집니다. coalesce로 기본값(0)을 보장하세요.
private NumberExpression<Integer> pageExpr() { - return new CaseBuilder() + return new CaseBuilder() .when(post.dtype.eq(RECORD.getType())).then(record.page) .when(post.dtype.eq(VOTE.getType())).then(vote.page) - .otherwise(0); + .otherwise(0) + .coalesce(0); } ... private NumberExpression<Integer> isOverviewExpr() { - return new CaseBuilder() + return new CaseBuilder() .when(post.dtype.eq(RECORD.getType())).then(record.isOverview.castToNum(Integer.class)) .when(post.dtype.eq(VOTE.getType())).then(vote.isOverview.castToNum(Integer.class)) - .otherwise(0); + .otherwise(0) + .coalesce(0); }이렇게 하면 MINE 정렬과 select 시 Boolean 변환(
eq(1)) 모두 안정적으로 동작합니다.src/main/java/konkuk/thip/roompost/adapter/out/jpa/RecordJpaEntity.java (1)
31-37: Builder가 primitive boolean을 받아 null 표현 불가 — PR의 “nullable 위임” 의도와 충돌Builder에서 boolean(primitive)을 받으면 null을 표현할 수 없고, 값 미지정 시 false가 흘러들어가 데이터가 의도치 않게 채워질 수 있습니다. nullable 전략에 맞추어 Boolean으로 받는 것이 안전합니다.
- public RecordJpaEntity(String content, Integer likeCount, Integer commentCount, UserJpaEntity userJpaEntity, Integer page, boolean isOverview, RoomJpaEntity roomJpaEntity) { + public RecordJpaEntity(String content, Integer likeCount, Integer commentCount, UserJpaEntity userJpaEntity, Integer page, Boolean isOverview, RoomJpaEntity roomJpaEntity) { super(content, likeCount, commentCount, userJpaEntity); this.page = page; this.isOverview = isOverview; this.roomJpaEntity = roomJpaEntity; }
🧹 Nitpick comments (4)
src/main/java/konkuk/thip/post/adapter/out/jpa/PostJpaEntity.java (1)
21-23: SINGLE_TABLE 전환 방향성은 타당. dtype/room_id 인덱스 고려 권장단일 테이블 전략으로 조회 부하를 줄이려는 의도는 명확하고 적절합니다. 다만 이후 조회 조건에서 dtype과 room_id, status, created_at 등을 자주 사용할 것으로 보여, 운영 DB 마이그레이션 시 아래 인덱스를 함께 고려해 주세요.
- posts(dtype)
- posts(room_id)
- posts(status)
- posts(created_at desc, post_id desc) 또는 필요한 정렬 조합
데이터 규모가 커질수록 효과가 큽니다.
src/main/java/konkuk/thip/roompost/adapter/out/jpa/VoteJpaEntity.java (1)
21-26: 서브타입 컬럼 nullable 정책과 타입 일관성: isOverview를 Boolean으로 전환 제안PR 설명대로 하위 엔티티 필드를 nullable 허용으로 가져가려면 primitive boolean보다는 wrapper(Boolean)가 일관됩니다. 현재 VoteJpaEntity만 boolean이라, RecordJpaEntity(Boolean)와 불일치합니다. 쿼리/정렬 시 null 안전성도 좋아집니다.
적용 예시:
- @Column(name = "is_overview") - private boolean isOverview; + @Column(name = "is_overview") + private Boolean isOverview; - public VoteJpaEntity(String content, Integer likeCount, Integer commentCount, UserJpaEntity userJpaEntity, Integer page, boolean isOverview, RoomJpaEntity roomJpaEntity) { + public VoteJpaEntity(String content, Integer likeCount, Integer commentCount, UserJpaEntity userJpaEntity, Integer page, Boolean isOverview, RoomJpaEntity roomJpaEntity) { - this.isOverview = isOverview; + this.isOverview = isOverview;도메인 Vote가 primitive를 유지한다면(예: vote.isOverview()), 오토박싱이 적용되므로 빌더 인자는 Boolean 유지해도 무방합니다. 반대로 도메인이 Boolean이면
vote.getIsOverview()로 맞춰 주세요.Also applies to: 31-37, 39-46
src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java (1)
25-30: reportCount 타입 일관성(도메인 Integer) 맞추기도메인 Feed.reportCount는 Integer인데 JPA는 int입니다. SINGLE_TABLE에서 컬럼이 null일 수 있음을 고려하면 Integer가 더 안전합니다. 타입을 맞추면 마이그레이션/데이터 일관성 면에서도 유리합니다.
- @Column(name = "report_count") - private int reportCount = 0; + @Column(name = "report_count") + private Integer reportCount;빌더/업데이트 메서드 시그니처도 Integer로 맞추면 이상적입니다.
src/main/java/konkuk/thip/roompost/adapter/out/jpa/RecordJpaEntity.java (1)
15-15: SINGLE_TABLE 전환에 따른 하위 엔티티 @table 제거는 맞습니다 — 주석 보관 대신 완전 삭제 권장주석으로 남겨두면 혼란을 줄 수 있습니다. 상위(PostJpaEntity)의 테이블에만 매핑되므로 이 라인은 제거해도 무방합니다.
-//@Table(name = "records")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java(1 hunks)src/main/java/konkuk/thip/post/adapter/out/jpa/PostJpaEntity.java(1 hunks)src/main/java/konkuk/thip/roompost/adapter/out/jpa/RecordJpaEntity.java(1 hunks)src/main/java/konkuk/thip/roompost/adapter/out/jpa/VoteJpaEntity.java(1 hunks)src/main/java/konkuk/thip/roompost/adapter/out/mapper/RecordMapper.java(1 hunks)src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: buzz0331
PR: THIP-TextHip/THIP-Server#75
File: src/main/java/konkuk/thip/vote/adapter/out/persistence/VoteQueryRepositoryImpl.java:50-83
Timestamp: 2025-07-14T14:19:38.796Z
Learning: Vote와 VoteItem 엔티티는 자주 함께 사용되므로, N+1 문제를 방지하기 위해 양방향 매핑과 fetch join을 고려하는 것이 좋습니다. 특히 기록장 조회 API 등에서도 함께 사용될 가능성이 높습니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (5)
src/main/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntity.java (1)
18-21: @table 주석 처리 OKSINGLE_TABLE 하위 엔티티에서 @table 제거(또는 주석 처리)는 올바른 설정입니다. 상위(PostJpaEntity)의 posts 테이블 하나만 사용하게 됩니다.
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java (1)
179-186: 정렬 키 null 처리 일관성 유지위 coalesce 적용 후에는 MINE 정렬의
isOverviewExpr().desc(), pageExpr().desc()가 안정적으로 동작합니다. 추가 변경은 불필요하나, page에 null이 많다면 필요에 따라 asc/desc 정책을 도메인 규칙으로 명시해 주세요.src/main/java/konkuk/thip/roompost/adapter/out/jpa/RecordJpaEntity.java (3)
21-23: page 컬럼 추가 및 nullable 처리 적절SINGLE_TABLE에서는 서브타입 전용 컬럼이 공용 테이블에 NULL 허용으로 들어가는 것이 자연스럽습니다. 마이그레이션에서 상위 테이블(Posts 등)에 page 컬럼 추가만 확인하면 됩니다.
39-46: null 보존 우려 불필요
Record.isOverview필드는 primitiveboolean으로 정의되어 있어 null이 존재하지 않습니다. 따라서updateFrom에서record.isOverview()를 사용하는 현재 구현은 올바르며,getIsOverview()로 변경할 필요가 없습니다.Likely an incorrect or invalid review comment.
24-26: RecordJpaEntity Boolean 필드 Lombok getter 변경 영향 없음 확인– RecordJpaEntity의
private Boolean isOverview;에 대해 Lombok이getIsOverview()를 생성하는 점을 검토했습니다.
– 전체 코드베이스에서recordJpaEntity.isOverview()호출은 없으며, RecordMapper 등 접근부는 모두getIsOverview()로 작성되어 있습니다.
– VoteJpaEntity는 primitiveboolean isOverview이기 때문에 기존대로isOverview()가 제공됩니다.따라서 컴파일 오류나 런타임 이슈는 발생하지 않습니다.
...onkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java (1)
94-116: isOverview/page의 null 처리 정책 명확화 필요 (where 절 필터링 누락 가능성)nullable 전환 이후, 아래 분기에서:
isOverview가 null인 레코드는isTrue()/isFalse()어느 쪽에도 매칭되지 않습니다.page가 null이면between(pageStart, pageEnd)에서 제외됩니다.이게 의도(미완성/비정상 데이터는 제외)라면 OK입니다. 만약 null을 각각 false/0으로 취급하고 포함시키려면 다음처럼 보완을 고려해 주세요.
- voteCondition.and(treat(post, QVoteJpaEntity.class).isOverview.isFalse()) - .and(treat(post, QVoteJpaEntity.class).page.between(pageStart, pageEnd)); + voteCondition.and( + treat(post, QVoteJpaEntity.class).isOverview.isFalse() + .or(treat(post, QVoteJpaEntity.class).isOverview.isNull()) + ).and( + treat(post, QVoteJpaEntity.class).page.coalesce(0).between(pageStart, pageEnd) + )- recordCondition.and(treat(post, QRecordJpaEntity.class).isOverview.isFalse()) - .and(treat(post, QRecordJpaEntity.class).page.between(pageStart, pageEnd)); + recordCondition.and( + treat(post, QRecordJpaEntity.class).isOverview.isFalse() + .or(treat(post, QRecordJpaEntity.class).isOverview.isNull()) + ).and( + treat(post, QRecordJpaEntity.class).page.coalesce(0).between(pageStart, pageEnd) + )추가로, 해당 컬럼들(dtype, room_id, is_overview, page)을 중심으로 복합/보조 인덱스를 점검하면 SINGLE_TABLE 전환 후 조회 성능 안정화에 도움이 됩니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: buzz0331
PR: THIP-TextHip/THIP-Server#75
File: src/main/java/konkuk/thip/vote/adapter/out/persistence/VoteQueryRepositoryImpl.java:50-83
Timestamp: 2025-07-14T14:19:38.796Z
Learning: Vote와 VoteItem 엔티티는 자주 함께 사용되므로, N+1 문제를 방지하기 위해 양방향 매핑과 fetch join을 고려하는 것이 좋습니다. 특히 기록장 조회 API 등에서도 함께 사용될 가능성이 높습니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (3)
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java (3)
23-23: treat 정적 임포트 사용 호환성 확인 (Querydsl/JPA 버전)
com.querydsl.jpa.JPAExpressions.treat사용은 버전 의존적입니다. 현재 의존성(Querydsl JPA, Hibernate/JPA 2.1+)이 해당 API를 지원하는지 확인해 주세요. 만약 호환 이슈가 있다면, 대안으로 alias 공유 방식(new QRecordJpaEntity(post.getMetadata()))도 고려 가능합니다.
59-66: SINGLE_TABLE + treat 다운캐스트 접근 방식 적절함JOIN 없이 단일 테이블에서 하위 타입 필드 접근을 위해
treat(post, QVoteJpaEntity.class)/treat(post, QRecordJpaEntity.class)를 사용하는 접근은 의도에 부합합니다. dtype 가드(post.dtype.eq(...))도 함께 있어 안전합니다.
166-173: 키셋 커서 비교식과 정렬 기준의 방향성이 일치합니다 (desc 정렬 기준).
MINE의 정렬 키가isOverview desc, page desc, postId desc인 상황에서, 커서 비교식이 모두lt를 사용해 다음 페이지를 잘라내는 형태로 정합적입니다. 위에서 제안한 coalesce(0) 적용을 전제하면 안정적으로 동작할 것으로 보입니다.
| // Case: pageExpr (Record, Vote 분기) | ||
| private NumberExpression<Integer> pageExpr() { | ||
| return new CaseBuilder() | ||
| .when(post.dtype.eq(RECORD.getType())).then(record.page) | ||
| .when(post.dtype.eq(VOTE.getType())).then(vote.page) | ||
| .when(post.dtype.eq(RECORD.getType())) | ||
| .then(treat(post, QRecordJpaEntity.class).page) | ||
| .when(post.dtype.eq(VOTE.getType())) | ||
| .then(treat(post, QVoteJpaEntity.class).page) | ||
| .otherwise(0); | ||
| } |
There was a problem hiding this comment.
pageExpr가 null을 반환할 수 있어 정렬/커서 비교가 깨집니다 — coalesce(0) 적용 권장
page가 Integer(Nullable)로 변경되었기 때문에 현재 구현은 null을 그대로 반환합니다. ORDER BY와 키셋 커서 비교(lt/eq)에서 null은 3값 논리로 처리되어 페이지네이션이 불안정해질 수 있습니다. 0으로 정규화(coalesce)해 주세요.
return new CaseBuilder()
- .when(post.dtype.eq(RECORD.getType()))
- .then(treat(post, QRecordJpaEntity.class).page)
- .when(post.dtype.eq(VOTE.getType()))
- .then(treat(post, QVoteJpaEntity.class).page)
+ .when(post.dtype.eq(RECORD.getType()))
+ .then(treat(post, QRecordJpaEntity.class).page.coalesce(0))
+ .when(post.dtype.eq(VOTE.getType()))
+ .then(treat(post, QVoteJpaEntity.class).page.coalesce(0))
.otherwise(0);이 개선은 select DTO의 page 값과 Cursor.getInteger(…) 처리에서도 NPE/불일치 위험을 줄여줍니다.
📝 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.
| // Case: pageExpr (Record, Vote 분기) | |
| private NumberExpression<Integer> pageExpr() { | |
| return new CaseBuilder() | |
| .when(post.dtype.eq(RECORD.getType())).then(record.page) | |
| .when(post.dtype.eq(VOTE.getType())).then(vote.page) | |
| .when(post.dtype.eq(RECORD.getType())) | |
| .then(treat(post, QRecordJpaEntity.class).page) | |
| .when(post.dtype.eq(VOTE.getType())) | |
| .then(treat(post, QVoteJpaEntity.class).page) | |
| .otherwise(0); | |
| } | |
| // Case: pageExpr (Record, Vote 분기) | |
| private NumberExpression<Integer> pageExpr() { | |
| return new CaseBuilder() | |
| .when(post.dtype.eq(RECORD.getType())) | |
| .then(treat(post, QRecordJpaEntity.class).page.coalesce(0)) | |
| .when(post.dtype.eq(VOTE.getType())) | |
| .then(treat(post, QVoteJpaEntity.class).page.coalesce(0)) | |
| .otherwise(0); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java
around lines 123 to 131, the CaseBuilder can yield null for page (since page is
now nullable) which breaks ORDER BY and keyset cursor comparisons; wrap the case
expression with a coalesce returning 0 so nulls are normalized. Concretely:
build the CaseBuilder as you have, assign it to a NumberExpression<Integer>
variable, then return a coalesced expression that returns 0 when the case result
is null (e.g., use QueryDSL/Expressions.coalesce(caseExpr, 0) or equivalent API
in your codebase) so pagination comparisons never see null.
| // Case: isOverviewExpr (총평 여부를 정렬 기준으로 사용) | ||
| private NumberExpression<Integer> isOverviewExpr() { | ||
| return new CaseBuilder() | ||
| .when(post.dtype.eq(RECORD.getType())).then(record.isOverview.castToNum(Integer.class)) | ||
| .when(post.dtype.eq(VOTE.getType())).then(vote.isOverview.castToNum(Integer.class)) | ||
| .when(post.dtype.eq(RECORD.getType())) | ||
| .then(treat(post, QRecordJpaEntity.class).isOverview.castToNum(Integer.class)) | ||
| .when(post.dtype.eq(VOTE.getType())) | ||
| .then(treat(post, QVoteJpaEntity.class).isOverview.castToNum(Integer.class)) | ||
| .otherwise(0); | ||
| } |
There was a problem hiding this comment.
isOverviewExpr도 null 가능성이 있어 비교/정렬이 불안정합니다 — coalesce(0) 적용
Boolean(Nullable) → Number로 cast한 뒤 null이 그대로 유지됩니다. eq/lt 비교와 ORDER BY에서 3값 논리로 변질되므로 0으로 coalesce 하는 편이 안전합니다.
return new CaseBuilder()
- .when(post.dtype.eq(RECORD.getType()))
- .then(treat(post, QRecordJpaEntity.class).isOverview.castToNum(Integer.class))
- .when(post.dtype.eq(VOTE.getType()))
- .then(treat(post, QVoteJpaEntity.class).isOverview.castToNum(Integer.class))
+ .when(post.dtype.eq(RECORD.getType()))
+ .then(treat(post, QRecordJpaEntity.class).isOverview.castToNum(Integer.class).coalesce(0))
+ .when(post.dtype.eq(VOTE.getType()))
+ .then(treat(post, QVoteJpaEntity.class).isOverview.castToNum(Integer.class).coalesce(0))
.otherwise(0);이 변경은 selectPostQueryDto의 isOverviewExpr().eq(1)에서도 null 비교를 피하게 되어 투영 시 Boolean/boolean 매핑 문제를 예방합니다.
📝 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.
| // Case: isOverviewExpr (총평 여부를 정렬 기준으로 사용) | |
| private NumberExpression<Integer> isOverviewExpr() { | |
| return new CaseBuilder() | |
| .when(post.dtype.eq(RECORD.getType())).then(record.isOverview.castToNum(Integer.class)) | |
| .when(post.dtype.eq(VOTE.getType())).then(vote.isOverview.castToNum(Integer.class)) | |
| .when(post.dtype.eq(RECORD.getType())) | |
| .then(treat(post, QRecordJpaEntity.class).isOverview.castToNum(Integer.class)) | |
| .when(post.dtype.eq(VOTE.getType())) | |
| .then(treat(post, QVoteJpaEntity.class).isOverview.castToNum(Integer.class)) | |
| .otherwise(0); | |
| } | |
| // Case: isOverviewExpr (총평 여부를 정렬 기준으로 사용) | |
| private NumberExpression<Integer> isOverviewExpr() { | |
| return new CaseBuilder() | |
| .when(post.dtype.eq(RECORD.getType())) | |
| .then(treat(post, QRecordJpaEntity.class) | |
| .isOverview | |
| .castToNum(Integer.class) | |
| .coalesce(0)) | |
| .when(post.dtype.eq(VOTE.getType())) | |
| .then(treat(post, QVoteJpaEntity.class) | |
| .isOverview | |
| .castToNum(Integer.class) | |
| .coalesce(0)) | |
| .otherwise(0); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/konkuk/thip/roompost/adapter/out/persistence/repository/record/RecordQueryRepositoryImpl.java
around lines 133 to 141, the CaseBuilder expression returns nullable Integer
(from casting Boolean) which leaves nulls in comparisons and ORDER BY; update
the expression to wrap the cast result with a coalesce(0) so any null becomes 0
(apply coalesce to each then-branch result or to the whole case result) to
ensure stable eq/lt checks and ordering and to avoid null projection when
calling isOverviewExpr().eq(1).
seongjunnoh
left a comment
There was a problem hiding this comment.
굳굳 좋습니다!! 생각보다 수월하게 마무리된 것 같네요!!
| @Table(name = "posts") | ||
| @Getter | ||
| @Inheritance(strategy = InheritanceType.JOINED) | ||
| @Inheritance(strategy = InheritanceType.SINGLE_TABLE) |
| @Column(name = "is_public", nullable = false) | ||
| @Column(name = "is_public") | ||
| private Boolean isPublic; | ||
|
|
||
| @Column(name = "report_count", nullable = false) | ||
| @Column(name = "report_count") | ||
| private int reportCount = 0; | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "book_id", nullable = false) | ||
| @JoinColumn(name = "book_id") |
| BooleanBuilder voteCondition = new BooleanBuilder(); | ||
| voteCondition.and(post.dtype.eq(VOTE.getType())) | ||
| .and(vote.roomJpaEntity.roomId.eq(roomId)); | ||
| BooleanBuilder voteCondition = new BooleanBuilder() | ||
| .and(post.dtype.eq(VOTE.getType())) | ||
| .and(treat(post, QVoteJpaEntity.class).roomJpaEntity.roomId.eq(roomId)); |
There was a problem hiding this comment.
오호 이렇게 jpa treat 로 post, record, vote jpa entity 간의 명시적인 left join을 없앨 수 있군요!! 좋습니다!
성능이 한층 개선될 것 같네요!!
| @Table(name = "posts") | ||
| @Getter | ||
| @Inheritance(strategy = InheritanceType.JOINED) | ||
| @Inheritance(strategy = InheritanceType.SINGLE_TABLE) |
#️⃣ 연관된 이슈
📝 작업 내용
기존 Post <-> Vote, Record, Feed 간의 상속 전략을 JOINED에서 SINGLE_TABLE로 변경하였습니다.
상속 전략을 변경하는 이유는 다음과 같습니다.
구체적인 내용은 노션 참고해주세요~
전략 변경을 위해, 다음과 같은 작업을 수행했습니다.
추가적으로 현재 운영서버에 있는 DB를 모두 drop 시키지 않고 DB 마이그레이션을 통해 데이터를 옮길 생각입니다!
📸 스크린샷
💬 리뷰 요구사항
📌 PR 진행 시 이러한 점들을 참고해 주세요
Summary by CodeRabbit
New Features
Refactor
Bug Fixes