-
Notifications
You must be signed in to change notification settings - Fork 2
MOSU-287 refactor: 내 질문 조회 시 답변도 같이 전달 #290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,9 @@ | |
| import life.mosu.mosuserver.domain.inquiry.entity.InquiryStatus; | ||
| import life.mosu.mosuserver.domain.inquiry.entity.QInquiryJpaEntity; | ||
| import life.mosu.mosuserver.domain.inquiry.repository.InquiryQueryRepository; | ||
| import life.mosu.mosuserver.domain.inquiryAnswer.entity.QInquiryAnswerJpaEntity; | ||
| import life.mosu.mosuserver.presentation.inquiry.dto.InquiryAnswerResponse; | ||
| import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; | ||
| import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.data.domain.Page; | ||
|
|
@@ -29,6 +32,7 @@ public class InquiryJpaRepositoryImpl implements InquiryQueryRepository { | |
| private final JPAQueryFactory queryFactory; | ||
| private final EntityManager entityManager; | ||
| private final QInquiryJpaEntity inquiry = QInquiryJpaEntity.inquiryJpaEntity; | ||
| private final QInquiryAnswerJpaEntity inquiryAnswer = QInquiryAnswerJpaEntity.inquiryAnswerJpaEntity; | ||
|
|
||
| @Override | ||
| public Page<InquiryResponse> searchInquiries( | ||
|
|
@@ -38,40 +42,42 @@ public Page<InquiryResponse> searchInquiries( | |
| Pageable pageable | ||
| ) { | ||
|
|
||
| JPAQuery<Tuple> query = baseQuery(inquiry) | ||
| .where(buildStatusCondition(inquiry, status)) | ||
| .orderBy(buildOrderByCondition(sortField, asc)) | ||
| .offset(pageable.getOffset()) | ||
| .limit(pageable.getPageSize()); | ||
| JPAQuery<Tuple> query = baseQuery() | ||
| .where(buildStatusCondition(inquiry, status)); | ||
|
|
||
| long total = getTotalCount(query, inquiry.count()); | ||
|
|
||
| List<InquiryResponse> content = query.fetch().stream() | ||
| .map(this::mapToResponse) | ||
| List<InquiryResponse> content = query | ||
| .orderBy(buildOrderByCondition(sortField, asc)) | ||
| .offset(pageable.getOffset()) | ||
| .limit(pageable.getPageSize()) | ||
| .fetch().stream() | ||
| .map(this::mapToInquiryResponse) | ||
| .toList(); | ||
|
|
||
| return new PageImpl<>(content, pageable, total); | ||
| } | ||
|
|
||
| @Override | ||
| public Page<InquiryResponse> searchMyInquiry(Long userId, Pageable pageable) { | ||
| JPAQuery<Tuple> query = baseQuery(inquiry) | ||
| public Page<InquiryListResponse> searchMyInquiry(Long userId, Pageable pageable) { | ||
| JPAQuery<Tuple> query = baseQueryWithAnswer() | ||
| .where(inquiry.userId.eq(userId)); | ||
|
|
||
| long total = getTotalCount(query, inquiry.count()); | ||
| long total = getTotalCount(query, inquiry.countDistinct()); | ||
|
|
||
| List<InquiryResponse> content = query | ||
| List<InquiryListResponse> content = query | ||
| .orderBy(inquiry.createdAt.desc()) | ||
| .offset(pageable.getOffset()) | ||
| .limit(pageable.getPageSize()) | ||
| .fetch().stream() | ||
| .map(this::mapToResponse) | ||
| .map(this::mapToInquiryListResponse) | ||
| .toList(); | ||
|
|
||
| return new PageImpl<>(content, pageable, total); | ||
| } | ||
|
Comment on lines
61
to
77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainUse id-based distinct count and validate 1:1 assumption to avoid paging errors
- long total = getTotalCount(query, inquiry.countDistinct());
+ long total = getTotalCount(query, inquiry.id.countDistinct());
Script to verify relationship and constraints, and confirm service/docs alignment: 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect InquiryAnswer entity for 1:1 mapping or uniqueness
fd -a "InquiryAnswerJpaEntity.java" | xargs -r -I{} rg -n --no-heading -A3 -B3 "@OneToOne|@ManyToOne|unique|UniqueConstraint|inquiryId|inquiry" {}
# Check BaseTimeEntity.formatDate implementation for null-safety
fd -a "BaseTimeEntity.java" | xargs -r -I{} rg -n --no-heading -A2 -B2 "static .*formatDate|DateTimeFormatter|null" {}
# Confirm service method return type
rg -n "interface\\s+InquiryQueryRepository|class\\s+InquiryService" -A 50 -S | rg -n "searchMyInquiry\\(|getMyInquiry\\(" -n -SLength of output: 2736 Use id-based distinct count and prevent duplicate paging issues In - long total = getTotalCount(query, inquiry.countDistinct());
+ long total = getTotalCount(query, inquiry.id.countDistinct());Currently,
Either approach will ensure unique items per page and consistent paging. 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| private JPAQuery<Tuple> baseQuery(QInquiryJpaEntity inquiry) { | ||
| private JPAQuery<Tuple> baseQuery() { | ||
| return queryFactory | ||
| .select( | ||
| inquiry.id, | ||
|
|
@@ -85,6 +91,27 @@ private JPAQuery<Tuple> baseQuery(QInquiryJpaEntity inquiry) { | |
|
|
||
| } | ||
|
|
||
| private JPAQuery<Tuple> baseQueryWithAnswer() { | ||
| return queryFactory | ||
| .select( | ||
| inquiry.id, | ||
| inquiry.title, | ||
| inquiry.content, | ||
| inquiry.author, | ||
| inquiry.status, | ||
| inquiry.createdAt, | ||
| inquiryAnswer.id, | ||
| inquiryAnswer.title, | ||
| inquiryAnswer.content, | ||
| inquiryAnswer.author, | ||
| inquiryAnswer.createdAt, | ||
| inquiryAnswer.updatedAt | ||
| ) | ||
| .from(inquiry) | ||
| .leftJoin(inquiryAnswer) | ||
| .on(inquiryAnswer.inquiryId.eq(inquiry.id)); | ||
| } | ||
|
|
||
| private BooleanExpression buildStatusCondition(QInquiryJpaEntity inquiry, | ||
| InquiryStatus status) { | ||
| return status != null ? inquiry.status.eq(status) : null; | ||
|
|
@@ -108,7 +135,7 @@ private <T> long getTotalCount(JPAQuery<T> query, Expression<Long> countExpressi | |
| ).orElse(0L); | ||
| } | ||
|
|
||
| private InquiryResponse mapToResponse(Tuple tuple) { | ||
| private InquiryResponse mapToInquiryResponse(Tuple tuple) { | ||
| InquiryStatus status = tuple.get(inquiry.status); | ||
| return new InquiryResponse( | ||
| tuple.get(inquiry.id), | ||
|
|
@@ -119,4 +146,22 @@ private InquiryResponse mapToResponse(Tuple tuple) { | |
| formatDate(tuple.get(inquiry.createdAt)) | ||
| ); | ||
| } | ||
|
|
||
|
|
||
| private InquiryListResponse mapToInquiryListResponse(Tuple tuple) { | ||
| InquiryResponse inquiryDto = mapToInquiryResponse(tuple); | ||
| InquiryAnswerResponse answerDto = null; | ||
|
|
||
| if (tuple.get(inquiryAnswer.id) != null) { | ||
| answerDto = new InquiryAnswerResponse( | ||
| tuple.get(inquiryAnswer.title), | ||
| tuple.get(inquiryAnswer.content), | ||
| tuple.get(inquiryAnswer.author), | ||
| formatDate(tuple.get(inquiryAnswer.createdAt)), | ||
| formatDate(tuple.get(inquiryAnswer.updatedAt)) | ||
| ); | ||
| } | ||
|
|
||
| return InquiryListResponse.of(inquiryDto, answerDto); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package life.mosu.mosuserver.presentation.inquiry.dto; | ||
|
|
||
| public record InquiryAnswerResponse( | ||
| String title, | ||
| String content, | ||
| String author, | ||
| String createdAt, | ||
| String updatedAt | ||
| ) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package life.mosu.mosuserver.presentation.inquiry.dto; | ||
|
|
||
| public record InquiryListResponse( | ||
| InquiryResponse inquiry, | ||
| InquiryAnswerResponse reply | ||
| ) { | ||
|
|
||
| public static InquiryListResponse of( | ||
| InquiryResponse inquiry, | ||
| InquiryAnswerResponse reply | ||
| ) { | ||
| return new InquiryListResponse(inquiry, reply); | ||
| } | ||
jbh010204 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
baseQuerymethod was refactored to use the class fieldinquiryinstead of taking it as a parameter, which is a good change. For consistency, thebuildStatusConditionmethod should also be updated to not take theQInquiryJpaEntity inquiryparameter and instead use the class field. This would align it with the implementation ofbuildOrderByConditionand improve code clarity.