-
Notifications
You must be signed in to change notification settings - Fork 0
임박한 수정 및 스크랩 검색 구현 #49
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 |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { ApiProperty } from '@nestjs/swagger'; | ||
| import { IsNotEmpty, IsString } from 'class-validator'; | ||
|
|
||
| export class GetScrapSearchRequestDto { | ||
| @ApiProperty({ | ||
| description: '검색어', | ||
| example: '대동제', | ||
| required: true, | ||
| }) | ||
| @IsString() | ||
| @IsNotEmpty() | ||
| keyword: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { Inject, Injectable } from '@nestjs/common'; | ||
| import { SCRAP_QUERY_REPOSITORY, ScrapQueryRepository } from '../../domain/scrap.query.repository'; | ||
| import { ScrapModel } from '../../domain/scrap.model'; | ||
| import { GetScrapSearchRequestDto } from './dto/get-scrap-search.request.dto'; | ||
|
|
||
| @Injectable() | ||
| export class GetScrapSearchUseCase { | ||
| constructor( | ||
| @Inject(SCRAP_QUERY_REPOSITORY) | ||
| private readonly scrapQueryRepository: ScrapQueryRepository, | ||
| ) {} | ||
|
|
||
| async execute(userId: string, reqDto: GetScrapSearchRequestDto): Promise<ScrapModel[]> { | ||
| const { keyword } = reqDto; | ||
| return await this.scrapQueryRepository.searchByKeyword(userId, keyword); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { EntityRepository } from '@mikro-orm/mysql'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { EntityRepository, sql } from '@mikro-orm/mysql'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { InjectRepository } from '@mikro-orm/nestjs'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ScrapQueryRepository } from '../domain/scrap.query.repository'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ScrapModel } from '../domain/scrap.model'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -58,6 +58,45 @@ export class ScrapQueryRepositoryImpl implements ScrapQueryRepository { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async searchByKeyword(userId: string, keyword: string): Promise<ScrapModel[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const qb = this.scrapOrmRepository.createQueryBuilder('s'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| qb.where({ userId }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 검색어 조건: 제목에서 검색 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| qb.andWhere(`s.title LIKE ?`, [`%${keyword}%`]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 정렬: 현재 시간에 가장 가까운 순서 (미래 우선) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 정렬: 현재 시간에 가장 가까운 순서 (미래 우선) | |
| // 정렬: 모집/행사 시작 시각(등록 시작일 또는 시작일)을 기준으로 현재 시간과 가장 가까운 순서 (미래 우선) |
Copilot
AI
Dec 20, 2025
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 sorting logic for scrap search does not match the PR description. According to the PR description, ongoing events should be sorted by their end dates (종료일 기준), but this implementation sorts by start dates (registration_start_at or start_at). This is inconsistent with the article query sorting logic which was updated to sort by end dates for active events.
Consider updating the sorting to match the article query logic in lines 142-194 of article.query.repository.impl.ts, which properly handles:
- Currently active events sorted by closest end date
- Future events sorted by closest start date
- Past events sorted by closest start date
| // 정렬: 현재 시간에 가장 가까운 순서 (미래 우선) | |
| qb.orderBy([ | |
| { | |
| [sql`CASE WHEN COALESCE(s.registration_start_at, s.start_at) >= NOW() THEN 0 ELSE 1 END` as unknown as string]: | |
| 'asc', | |
| }, | |
| { | |
| [sql`ABS(TIMESTAMPDIFF(SECOND, COALESCE(s.registration_start_at, s.start_at), NOW()))` as unknown as string]: | |
| 'asc', | |
| // 정렬: 진행중(종료일 기준) > 예정(시작일 기준) > 종료(시작일 기준) | |
| qb.orderBy([ | |
| { | |
| [ | |
| sql` | |
| CASE | |
| WHEN COALESCE(s.registration_start_at, s.start_at) <= NOW() | |
| AND COALESCE(s.registration_end_at, s.end_at) >= NOW() | |
| THEN 0 -- 진행중 | |
| WHEN COALESCE(s.registration_start_at, s.start_at) > NOW() | |
| THEN 1 -- 예정 | |
| ELSE 2 -- 종료 | |
| END | |
| ` as unknown as string | |
| ]: 'asc', | |
| }, | |
| { | |
| [ | |
| sql` | |
| CASE | |
| WHEN COALESCE(s.registration_start_at, s.start_at) <= NOW() | |
| AND COALESCE(s.registration_end_at, s.end_at) >= NOW() | |
| THEN COALESCE(s.registration_end_at, s.end_at) -- 진행중: 종료일 오름차순 | |
| ELSE COALESCE(s.registration_start_at, s.start_at) -- 예정/종료: 시작일 오름차순 | |
| END | |
| ` as unknown as string | |
| ]: 'asc', |
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 complex CASE statement has duplicated logic that checks the same conditions multiple times. The conditions for determining if registration or event is in progress appear in lines 151-155 and again in lines 164-168, and once more in lines 171-180. This duplication makes the query harder to maintain and more error-prone.
Consider using CTEs (Common Table Expressions) or simplifying the logic to avoid repetition of the same conditional checks.