From 1d0f1b40a5114c724c36db08aeeef8d52c2a6cbf Mon Sep 17 00:00:00 2001 From: dev-ant Date: Tue, 24 Feb 2026 19:20:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EA=B2=BD=EB=A7=A4=EC=9E=A5=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20API=20=EC=84=B8=EA=B3=B5=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuctionHistoryQueryDslRepository.java | 27 +++++++++++++++++++ .../request/AuctionHistorySearchRequest.java | 7 ++++- .../dto/request/MetalwareSearchRequest.java | 19 +++++++++++++ .../AuctionRealtimeQueryDslRepository.java | 27 +++++++++++++++++++ .../request/AuctionRealtimeSearchRequest.java | 8 +++++- 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/MetalwareSearchRequest.java diff --git a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java index 88f4d4a..8f3a621 100644 --- a/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java +++ b/src/main/java/until/the/eternity/auctionhistory/infrastructure/persistence/AuctionHistoryQueryDslRepository.java @@ -25,6 +25,7 @@ import until.the.eternity.auctionhistory.interfaces.rest.dto.request.AuctionHistorySearchRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.DateAuctionBuyRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.ItemOptionSearchRequest; +import until.the.eternity.auctionhistory.interfaces.rest.dto.request.MetalwareSearchRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.PriceSearchRequest; import until.the.eternity.auctionitemoption.domain.entity.QAuctionHistoryItemOption; @@ -193,6 +194,32 @@ private BooleanBuilder buildHistoryPredicate( } } + // 세공 검색 조건 (각 세공 이름마다 별도 서브쿼리, AND 조건) + if (c.metalwareSearchRequests() != null && !c.metalwareSearchRequests().isEmpty()) { + for (int i = 0; i < c.metalwareSearchRequests().size(); i++) { + MetalwareSearchRequest mw = c.metalwareSearchRequests().get(i); + if (mw.metalware() == null || mw.metalware().isBlank()) continue; + + QAuctionHistoryItemOption mwOpt = new QAuctionHistoryItemOption("mw" + i); + NumberTemplate mwLevel = + Expressions.numberTemplate( + Integer.class, "CAST({0} AS UNSIGNED)", mwOpt.optionValue2); + + var mwSubQuery = + JPAExpressions.select(mwOpt.auctionHistory.auctionBuyId) + .from(mwOpt) + .where( + mwOpt.optionType + .eq("세공 옵션") + .and(mwOpt.optionValue.eq(mw.metalware())) + .and( + mwLevel.between( + mw.resolvedLevelFrom(), + mw.resolvedLevelTo()))); + builder.and(ah.auctionBuyId.in(mwSubQuery)); + } + } + return builder; } diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/AuctionHistorySearchRequest.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/AuctionHistorySearchRequest.java index 02dd616..601de45 100644 --- a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/AuctionHistorySearchRequest.java +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/AuctionHistorySearchRequest.java @@ -1,6 +1,7 @@ package until.the.eternity.auctionhistory.interfaces.rest.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; /** 경매 히스토리 검색 조건 DTO - 페이지네이션 포함 */ @Schema(description = "경매 거래내역 검색 조건") @@ -17,4 +18,8 @@ public record AuctionHistorySearchRequest( @Schema(description = "거래 일자 조건") DateAuctionBuyRequest dateAuctionBuyRequest, @Schema(description = "가격 검색 조건") PriceSearchRequest priceSearchRequest, @Schema(description = "아이템 옵션 검색 조건") ItemOptionSearchRequest itemOptionSearchRequest, - @Schema(description = "인챈트 검색 조건") EnchantSearchRequest enchantSearchRequest) {} + @Schema(description = "인챈트 검색 조건") EnchantSearchRequest enchantSearchRequest, + @Schema( + description = "세공 검색 조건 목록 (최대 3개, AND 조건으로 검색)", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) + List metalwareSearchRequests) {} diff --git a/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/MetalwareSearchRequest.java b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/MetalwareSearchRequest.java new file mode 100644 index 0000000..d0b3c64 --- /dev/null +++ b/src/main/java/until/the/eternity/auctionhistory/interfaces/rest/dto/request/MetalwareSearchRequest.java @@ -0,0 +1,19 @@ +package until.the.eternity.auctionhistory.interfaces.rest.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "세공 검색 조건") +public record MetalwareSearchRequest( + @Schema(description = "세공 이름 (완전 일치)", example = "불의 연성술") String metalware, + @Schema(description = "세공 레벨 시작값 (null이면 1로 처리)", example = "1") Integer levelFrom, + @Schema(description = "세공 레벨 종료값 (null이면 30으로 처리)", example = "30") + Integer levelTo) { + + public int resolvedLevelFrom() { + return levelFrom != null ? levelFrom : 1; + } + + public int resolvedLevelTo() { + return levelTo != null ? levelTo : 30; + } +} diff --git a/src/main/java/until/the/eternity/auctionrealtime/infrastructure/persistence/AuctionRealtimeQueryDslRepository.java b/src/main/java/until/the/eternity/auctionrealtime/infrastructure/persistence/AuctionRealtimeQueryDslRepository.java index a60f726..764c131 100644 --- a/src/main/java/until/the/eternity/auctionrealtime/infrastructure/persistence/AuctionRealtimeQueryDslRepository.java +++ b/src/main/java/until/the/eternity/auctionrealtime/infrastructure/persistence/AuctionRealtimeQueryDslRepository.java @@ -18,6 +18,7 @@ import org.springframework.stereotype.Component; import until.the.eternity.auctionhistory.interfaces.rest.dto.enums.SearchStandard; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.ItemOptionSearchRequest; +import until.the.eternity.auctionhistory.interfaces.rest.dto.request.MetalwareSearchRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.PriceSearchRequest; import until.the.eternity.auctionitem.domain.entity.AuctionRealtimeItem; import until.the.eternity.auctionitem.domain.entity.QAuctionRealtimeItem; @@ -161,6 +162,32 @@ private BooleanBuilder buildItemPredicate( } } + // 세공 검색 조건 (각 세공 이름마다 별도 서브쿼리, AND 조건) + if (c.metalwareSearchRequests() != null && !c.metalwareSearchRequests().isEmpty()) { + for (int i = 0; i < c.metalwareSearchRequests().size(); i++) { + MetalwareSearchRequest mw = c.metalwareSearchRequests().get(i); + if (mw.metalware() == null || mw.metalware().isBlank()) continue; + + QAuctionRealtimeItemOption mwOpt = new QAuctionRealtimeItemOption("mw" + i); + NumberTemplate mwLevel = + Expressions.numberTemplate( + Integer.class, "CAST({0} AS UNSIGNED)", mwOpt.optionValue2); + + var mwSubQuery = + JPAExpressions.select(mwOpt.auctionRealtimeItem.id) + .from(mwOpt) + .where( + mwOpt.optionType + .eq("세공 옵션") + .and(mwOpt.optionValue.eq(mw.metalware())) + .and( + mwLevel.between( + mw.resolvedLevelFrom(), + mw.resolvedLevelTo()))); + builder.and(ar.id.in(mwSubQuery)); + } + } + return builder; } diff --git a/src/main/java/until/the/eternity/auctionrealtime/interfaces/rest/dto/request/AuctionRealtimeSearchRequest.java b/src/main/java/until/the/eternity/auctionrealtime/interfaces/rest/dto/request/AuctionRealtimeSearchRequest.java index 258ca1e..4ae5bdb 100644 --- a/src/main/java/until/the/eternity/auctionrealtime/interfaces/rest/dto/request/AuctionRealtimeSearchRequest.java +++ b/src/main/java/until/the/eternity/auctionrealtime/interfaces/rest/dto/request/AuctionRealtimeSearchRequest.java @@ -1,8 +1,10 @@ package until.the.eternity.auctionrealtime.interfaces.rest.dto.request; import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.EnchantSearchRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.ItemOptionSearchRequest; +import until.the.eternity.auctionhistory.interfaces.rest.dto.request.MetalwareSearchRequest; import until.the.eternity.auctionhistory.interfaces.rest.dto.request.PriceSearchRequest; /** 실시간 경매장 검색 조건 DTO */ @@ -19,4 +21,8 @@ public record AuctionRealtimeSearchRequest( @Schema(description = "소분류 카테고리", example = "검") String itemSubCategory, @Schema(description = "가격 검색 조건") PriceSearchRequest priceSearchRequest, @Schema(description = "아이템 옵션 검색 조건") ItemOptionSearchRequest itemOptionSearchRequest, - @Schema(description = "인챈트 검색 조건") EnchantSearchRequest enchantSearchRequest) {} + @Schema(description = "인챈트 검색 조건") EnchantSearchRequest enchantSearchRequest, + @Schema( + description = "세공 검색 조건 목록 (최대 3개, AND 조건으로 검색)", + requiredMode = Schema.RequiredMode.NOT_REQUIRED) + List metalwareSearchRequests) {} From 764bc09368a1546765a77c5318a650157fb9e23a Mon Sep 17 00:00:00 2001 From: dev-ant Date: Tue, 24 Feb 2026 19:48:14 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20auction=20history=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EC=84=B8=EA=B3=B5=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/AuctionHistoryServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java b/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java index df502fd..b9ea3a5 100644 --- a/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java +++ b/src/test/java/until/the/eternity/auctionhistory/application/service/AuctionHistoryServiceTest.java @@ -42,7 +42,7 @@ class AuctionHistoryServiceTest { void search_should_return_paged_response() { // given AuctionHistorySearchRequest searchRequest = - new AuctionHistorySearchRequest(null, null, null, null, null, null, null, null); + new AuctionHistorySearchRequest(null, null, null, null, null, null, null, null, null); PageRequestDto pageRequestDto = mock(PageRequestDto.class); Pageable pageable = PageRequest.of(0, 10); when(pageRequestDto.toPageable()).thenReturn(pageable);