|
17 | 17 | import org.tuna.zoopzoop.backend.domain.archive.folder.entity.QFolder; |
18 | 18 | import org.tuna.zoopzoop.backend.domain.datasource.dto.DataSourceSearchCondition; |
19 | 19 | import org.tuna.zoopzoop.backend.domain.datasource.dto.DataSourceSearchItem; |
| 20 | +import org.tuna.zoopzoop.backend.domain.datasource.entity.Category; |
20 | 21 | import org.tuna.zoopzoop.backend.domain.datasource.entity.QDataSource; |
21 | 22 | import org.tuna.zoopzoop.backend.domain.datasource.entity.QTag; |
22 | 23 |
|
@@ -51,19 +52,28 @@ public Page<DataSourceSearchItem> search(Integer memberId, DataSourceSearchCondi |
51 | 52 |
|
52 | 53 | if (hasText(cond.getTitle())) where.and(ds.title.containsIgnoreCase(cond.getTitle())); |
53 | 54 | if (hasText(cond.getSummary())) where.and(ds.summary.containsIgnoreCase(cond.getSummary())); |
54 | | - if (hasText(cond.getCategory())) where.and(ds.category.stringValue().containsIgnoreCase(cond.getCategory())); |
55 | | - if (hasText(cond.getSource())) where.and(ds.source.containsIgnoreCase(cond.getSource())); |
| 55 | + if (cond.getCategory() != null) where.and(ds.category.eq(cond.getCategory())); |
56 | 56 |
|
| 57 | + // 키워드 검색 (카테고리는 "한글 라벨 정확 일치" + IT 예외만 허용) |
57 | 58 | if (hasText(cond.getKeyword())) { |
58 | 59 | String kw = cond.getKeyword(); |
| 60 | + |
| 61 | + BooleanBuilder categoryMatch = new BooleanBuilder(); |
| 62 | + Category cat = resolveCategoryFromKoreanOrIT(kw); // 한글 또는 IT만 매칭 |
| 63 | + if (cat != null) { |
| 64 | + categoryMatch.or(ds.category.eq(cat)); |
| 65 | + } |
| 66 | + // 영어 ENUM 문자열로의 비교는 제거 (ds.category.stringValue().containsIgnoreCase(kw) 금지) |
| 67 | + |
59 | 68 | where.and( |
60 | 69 | ds.title.containsIgnoreCase(kw) |
61 | 70 | .or(ds.summary.containsIgnoreCase(kw)) |
62 | 71 | .or(ds.source.containsIgnoreCase(kw)) |
63 | | - .or(ds.category.stringValue().containsIgnoreCase(kw)) |
| 72 | + .or(categoryMatch) |
64 | 73 | ); |
65 | 74 | } |
66 | 75 |
|
| 76 | + // 폴더 조건 |
67 | 77 | if (hasText(cond.getFolderName())) where.and(ds.folder.name.eq(cond.getFolderName())); |
68 | 78 | if (cond.getFolderId() != null) where.and(ds.folder.id.eq(cond.getFolderId())); |
69 | 79 |
|
@@ -156,33 +166,46 @@ public Page<DataSourceSearchItem> searchInArchive(Integer archiveId, DataSourceS |
156 | 166 | QTag tag = QTag.tag; |
157 | 167 |
|
158 | 168 | BooleanBuilder where = new BooleanBuilder(); |
| 169 | + |
| 170 | + // 활성/비활성 |
159 | 171 | if (cond.getIsActive() == null || Boolean.TRUE.equals(cond.getIsActive())) where.and(ds.isActive.isTrue()); |
160 | 172 | else where.and(ds.isActive.isFalse()); |
161 | 173 |
|
| 174 | + // 개별 필드 필터 |
162 | 175 | if (hasText(cond.getTitle())) where.and(ds.title.containsIgnoreCase(cond.getTitle())); |
163 | 176 | if (hasText(cond.getSummary())) where.and(ds.summary.containsIgnoreCase(cond.getSummary())); |
164 | | - if (hasText(cond.getCategory())) where.and(ds.category.stringValue().containsIgnoreCase(cond.getCategory())); |
165 | | - if (hasText(cond.getSource())) where.and(ds.source.containsIgnoreCase(cond.getSource())); |
| 177 | + if (cond.getCategory() != null) where.and(ds.category.eq(cond.getCategory())); |
| 178 | + |
| 179 | + // 키워드 검색 (카테고리는 "한글 라벨 정확 일치" + IT 예외만 허용) |
166 | 180 | if (hasText(cond.getKeyword())) { |
167 | 181 | String kw = cond.getKeyword(); |
| 182 | + |
| 183 | + BooleanBuilder categoryMatch = new BooleanBuilder(); |
| 184 | + Category cat = resolveCategoryFromKoreanOrIT(kw); |
| 185 | + if (cat != null) { |
| 186 | + categoryMatch.or(ds.category.eq(cat)); |
| 187 | + } |
| 188 | + // 영어 ENUM 문자열 비교 제거 |
| 189 | + |
168 | 190 | where.and( |
169 | 191 | ds.title.containsIgnoreCase(kw) |
170 | 192 | .or(ds.summary.containsIgnoreCase(kw)) |
171 | 193 | .or(ds.source.containsIgnoreCase(kw)) |
172 | | - .or(ds.category.stringValue().containsIgnoreCase(kw)) |
| 194 | + .or(categoryMatch) |
173 | 195 | ); |
174 | 196 | } |
175 | | - if (hasText(cond.getFolderName())) where.and(ds.folder.name.eq(cond.getFolderName())); |
176 | | - if (cond.getFolderId() != null) where.and(ds.folder.id.eq(cond.getFolderId())); |
177 | 197 |
|
| 198 | + // 아카이브 스코프 |
178 | 199 | BooleanBuilder scope = new BooleanBuilder().and(folder.archive.id.eq(archiveId)); |
179 | 200 |
|
| 201 | + // count |
180 | 202 | JPAQuery<Long> countQuery = queryFactory |
181 | 203 | .select(ds.id.countDistinct()) |
182 | 204 | .from(ds) |
183 | 205 | .join(ds.folder, folder) |
184 | 206 | .where(where.and(scope)); |
185 | 207 |
|
| 208 | + // content |
186 | 209 | JPAQuery<Tuple> contentQuery = queryFactory |
187 | 210 | .select(ds.id, ds.title, ds.dataCreatedDate, ds.summary, ds.source, ds.sourceUrl, ds.imageUrl, ds.category) |
188 | 211 | .from(ds) |
@@ -220,10 +243,26 @@ public Page<DataSourceSearchItem> searchInArchive(Integer archiveId, DataSourceS |
220 | 243 | row.get(ds.sourceUrl), |
221 | 244 | row.get(ds.imageUrl), |
222 | 245 | tagsById.getOrDefault(row.get(ds.id), List.of()), |
223 | | - row.get(ds.category).name() |
| 246 | + row.get(ds.category).name() // 응답은 영문 코드 유지 |
224 | 247 | )) |
225 | 248 | .toList(); |
226 | 249 |
|
227 | 250 | return new PageImpl<>(content, pageable, total); |
228 | 251 | } |
| 252 | + |
| 253 | + /** |
| 254 | + * 키워드가 "IT"(대소문자 무시)이면 IT를, 그 외에는 |
| 255 | + * 카테고리의 한글 라벨과 "정확 일치"할 때만 해당 Enum을 반환. |
| 256 | + * (예: "스포츠" -> SPORTS, "SPORTS" -> null) |
| 257 | + */ |
| 258 | + private Category resolveCategoryFromKoreanOrIT(String kw) { |
| 259 | + if (kw == null || kw.isBlank()) return null; |
| 260 | + if ("IT".equalsIgnoreCase(kw)) return Category.IT; // 유일한 영문 예외 |
| 261 | + for (Category c : Category.values()) { |
| 262 | + if (c != Category.IT && c.getName().equalsIgnoreCase(kw)) { |
| 263 | + return c; // 한글 라벨 정확 일치 |
| 264 | + } |
| 265 | + } |
| 266 | + return null; // 영문 코드 등은 매칭하지 않음 |
| 267 | + } |
229 | 268 | } |
0 commit comments