Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ private BooleanBuilder buildHistoryPredicate(
builder.and(ah.itemSubCategory.eq(c.itemSubCategory()));
}
if (c.itemName() != null && !c.itemName().isBlank()) {
builder.and(ah.itemName.containsIgnoreCase(c.itemName()));
if (Boolean.TRUE.equals(c.isExactItemName())) {
builder.and(ah.itemName.eq(c.itemName()));
} else {
builder.and(ah.itemName.containsIgnoreCase(c.itemName()));
}
Comment on lines +123 to +127
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The new isExactItemName parameter lacks test coverage. While the test correctly adds a seventh null parameter to match the new record signature, there are no tests verifying the behavior when isExactItemName is true vs false vs null.

Consider adding test cases that verify:

  1. When isExactItemName=true, only exact matches are returned
  2. When isExactItemName=false or null, partial matches (LIKE) are returned
  3. The query correctly handles the parameter in combination with other search criteria

Copilot uses AI. Check for mistakes.
}

// 가격 조건 (PriceSearchRequest가 있으면)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
@Schema(description = "경매 거래내역 검색 조건")
public record AuctionHistorySearchRequest(
@Schema(description = "아이템 이름 (like 검색)", example = "페러시우스 타이탄 블레이드") String itemName,
@Schema(
description = "아이템 이름 완전 일치 검색 여부 (true: eq, false: like)",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "false",
example = "false")
Boolean isExactItemName,
@Schema(description = "대분류 카테고리", example = "근거리 장비") String itemTopCategory,
@Schema(description = "소분류 카테고리", example = "검") String itemSubCategory,
@Schema(description = "거래 일자 조건") DateAuctionBuyRequest dateAuctionBuyRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

@Schema(description = "거래 일자 조건")
public record DateAuctionBuyRequest(
@Schema(description = "거래 일자 시작 범위", example = "2025-01-01") String dateAuctionBuyFrom,
@Schema(description = "거래 일자 종료 범위", example = "2025-12-31") String dateAuctionBuyTo) {}
@Schema(description = "거래 일자 시작 범위", example = "2026-02-01") String dateAuctionBuyFrom,
@Schema(description = "거래 일자 종료 범위", example = "2026-02-11") String dateAuctionBuyTo) {}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ private BooleanBuilder buildItemPredicate(
builder.and(ar.itemSubCategory.eq(c.itemSubCategory()));
}
if (c.itemName() != null && !c.itemName().isBlank()) {
builder.and(ar.itemName.containsIgnoreCase(c.itemName()));
if (Boolean.TRUE.equals(c.isExactItemName())) {
builder.and(ar.itemName.eq(c.itemName()));
} else {
builder.and(ar.itemName.containsIgnoreCase(c.itemName()));
}
Comment on lines +112 to +116
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The new isExactItemName parameter lacks test coverage. There are no tests verifying the behavior when isExactItemName is true vs false vs null.

Consider adding test cases that verify:

  1. When isExactItemName=true, only exact matches are returned
  2. When isExactItemName=false or null, partial matches (LIKE) are returned
  3. The query correctly handles the parameter in combination with other search criteria

Copilot uses AI. Check for mistakes.
}

if (c.priceSearchRequest() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
@Schema(description = "실시간 경매장 검색 조건")
public record AuctionRealtimeSearchRequest(
@Schema(description = "아이템 이름 (like 검색)", example = "페러시우스 타이탄 블레이드") String itemName,
@Schema(
description = "아이템 이름 완전 일치 검색 여부 (true: eq, false: like)",
requiredMode = Schema.RequiredMode.NOT_REQUIRED,
defaultValue = "false",
example = "false")
Boolean isExactItemName,
@Schema(description = "대분류 카테고리", example = "근거리 장비") String itemTopCategory,
@Schema(description = "소분류 카테고리", example = "검") String itemSubCategory,
@Schema(description = "가격 검색 조건") PriceSearchRequest priceSearchRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- Optimize auction history search indexes for fixed filters:
-- item_top_category, item_sub_category, date_auction_buy

-- Replace legacy index that does not align with date-range + date sort pattern
DROP INDEX idx_top_sub_item ON auction_history;

-- Main search index:
-- Equality filters first, range/sort column last
-- date_auction_buy는 where 조건에 무조건 포함 및 높은 확률로 정렬 조건
CREATE INDEX idx_ah_top_sub_name_date
ON auction_history (item_top_category, item_sub_category, item_name, date_auction_buy DESC);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The index includes item_name as an equality filter column, but the query logic uses containsIgnoreCase (LIKE search) when isExactItemName is false or null. This means the index may not be effective for the common case of LIKE searches.

Consider either:

  1. Creating separate indexes for exact vs LIKE searches
  2. Moving item_name after date_auction_buy in the index so it doesn't break the index effectiveness for range/sort operations
  3. Adding a covering index without item_name for LIKE searches

The current index will only be fully effective when isExactItemName=true, but may have reduced effectiveness for LIKE searches since MySQL/PostgreSQL cannot use the full index when a prefix column uses LIKE patterns.

Suggested change
ON auction_history (item_top_category, item_sub_category, item_name, date_auction_buy DESC);
ON auction_history (item_top_category, item_sub_category, date_auction_buy DESC, item_name);

Copilot uses AI. Check for mistakes.

-- Item option subquery index:
-- Supports option_type filtering + grouping by auction_history_id
-- 옵션 검색 서브 쿼리를 위한 인덱스
CREATE INDEX idx_ahio_type_history
ON auction_history_item_option (option_type, auction_history_id);
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class AuctionHistoryServiceTest {
void search_should_return_paged_response() {
// given
AuctionHistorySearchRequest searchRequest =
new AuctionHistorySearchRequest(null, null, null, null, null, null);
new AuctionHistorySearchRequest(null, null, null, null, null, null, null);
PageRequestDto pageRequestDto = mock(PageRequestDto.class);
Pageable pageable = PageRequest.of(0, 10);
when(pageRequestDto.toPageable()).thenReturn(pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ void findAllDetail_should_allow_null_topCategory() {
ItemInfoSearchRequest searchRequest = new ItemInfoSearchRequest(null, null, null);
Pageable pageable = PageRequest.of(0, 20);
Page<ItemInfo> emptyPage = new PageImpl<>(List.of(), pageable, 0);
when(itemInfoRepository.searchWithPagination(searchRequest, pageable)).thenReturn(emptyPage);
when(itemInfoRepository.searchWithPagination(searchRequest, pageable))
.thenReturn(emptyPage);

// when
Page<ItemInfoResponse> result = itemInfoService.findAllDetail(searchRequest, pageable);
Expand All @@ -138,7 +139,8 @@ void findAllDetail_should_allow_blank_topCategory() {
ItemInfoSearchRequest searchRequest = new ItemInfoSearchRequest(null, null, "");
Pageable pageable = PageRequest.of(0, 20);
Page<ItemInfo> emptyPage = new PageImpl<>(List.of(), pageable, 0);
when(itemInfoRepository.searchWithPagination(searchRequest, pageable)).thenReturn(emptyPage);
when(itemInfoRepository.searchWithPagination(searchRequest, pageable))
.thenReturn(emptyPage);

// when
Page<ItemInfoResponse> result = itemInfoService.findAllDetail(searchRequest, pageable);
Expand Down Expand Up @@ -200,7 +202,8 @@ void findAllDetail_should_return_filtered_items_with_all_conditions() {
void findAllSummary_should_allow_null_topCategory() {
// given
ItemInfoSearchRequest searchRequest = new ItemInfoSearchRequest(null, null, null);
when(itemInfoRepository.search(eq(searchRequest), any(Pageable.class))).thenReturn(List.of());
when(itemInfoRepository.search(eq(searchRequest), any(Pageable.class)))
.thenReturn(List.of());

// when
List<ItemInfoSummaryResponse> result =
Expand Down Expand Up @@ -332,7 +335,8 @@ void findBySubCategory_should_return_empty_list_when_no_results() {
void findAllSummary_should_allow_blank_topCategory() {
// given
ItemInfoSearchRequest searchRequest = new ItemInfoSearchRequest(null, null, "");
when(itemInfoRepository.search(eq(searchRequest), any(Pageable.class))).thenReturn(List.of());
when(itemInfoRepository.search(eq(searchRequest), any(Pageable.class)))
.thenReturn(List.of());

// when
List<ItemInfoSummaryResponse> result =
Expand Down