From 677adfa06233dea1795ce12e861240bad4836d3b Mon Sep 17 00:00:00 2001 From: oTAETAEo Date: Sat, 31 Oct 2026 14:57:29 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=ED=9C=B4=EC=A7=80=ED=86=B5=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=EC=99=80=20=EC=BB=A4?= =?UTF-8?q?=EC=84=9C=20=EA=B5=AC=ED=98=84=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/exception/TrashErrorCode.java | 21 +++ .../repository/TemplateRepository.java | 27 ++++ .../template/service/TrashQueryService.java | 54 +++++++ .../service/dto/query/TrashListQuery.java | 4 + .../service/dto/result/TrashListResult.java | 12 ++ .../dto/result/TrashTemplateResult.java | 29 ++++ .../domain/template/support/TrashCursor.java | 45 ++++++ .../exception/TrashErrorCodeTest.java | 19 +++ .../TrashTemplateRepositoryTest.java | 135 +++++++++++++++++ .../service/TrashQueryServiceTest.java | 142 ++++++++++++++++++ .../template/support/TrashCursorTest.java | 73 +++++++++ .../com/sniptext/fixture/TemplateFixture.java | 9 ++ 12 files changed, 570 insertions(+) create mode 100644 src/main/java/com/sniptext/domain/template/exception/TrashErrorCode.java create mode 100644 src/main/java/com/sniptext/domain/template/service/TrashQueryService.java create mode 100644 src/main/java/com/sniptext/domain/template/service/dto/query/TrashListQuery.java create mode 100644 src/main/java/com/sniptext/domain/template/service/dto/result/TrashListResult.java create mode 100644 src/main/java/com/sniptext/domain/template/service/dto/result/TrashTemplateResult.java create mode 100644 src/main/java/com/sniptext/domain/template/support/TrashCursor.java create mode 100644 src/test/java/com/sniptext/domain/template/exception/TrashErrorCodeTest.java create mode 100644 src/test/java/com/sniptext/domain/template/repository/TrashTemplateRepositoryTest.java create mode 100644 src/test/java/com/sniptext/domain/template/service/TrashQueryServiceTest.java create mode 100644 src/test/java/com/sniptext/domain/template/support/TrashCursorTest.java diff --git a/src/main/java/com/sniptext/domain/template/exception/TrashErrorCode.java b/src/main/java/com/sniptext/domain/template/exception/TrashErrorCode.java new file mode 100644 index 0000000..2e91d14 --- /dev/null +++ b/src/main/java/com/sniptext/domain/template/exception/TrashErrorCode.java @@ -0,0 +1,21 @@ +package com.sniptext.domain.template.exception; + +import org.springframework.http.HttpStatus; + +import com.sniptext.global.response.ResultCode; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum TrashErrorCode implements ResultCode { + + /** 커서를 해석할 수 없거나 size가 1~50 밖 */ + INVALID_PAGE_REQUEST(HttpStatus.BAD_REQUEST, "TRASH400_1", "잘못된 페이지 요청이에요."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + +} diff --git a/src/main/java/com/sniptext/domain/template/repository/TemplateRepository.java b/src/main/java/com/sniptext/domain/template/repository/TemplateRepository.java index f751467..7280086 100644 --- a/src/main/java/com/sniptext/domain/template/repository/TemplateRepository.java +++ b/src/main/java/com/sniptext/domain/template/repository/TemplateRepository.java @@ -1,8 +1,11 @@ package com.sniptext.domain.template.repository; +import java.time.LocalDateTime; import java.util.Collection; +import java.util.List; import java.util.Set; +import org.springframework.data.domain.Limit; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -27,4 +30,28 @@ public interface TemplateRepository extends JpaRepository { @Query("select t.activeShortcutKey from Template t where t.userId = :userId and t.activeShortcutKey in :keys") Set findActiveShortcutKeys(@Param("userId") Long userId, @Param("keys") Collection keys); + /** 휴지통 개수. idx_templates_user_deleted (user_id, deleted_at)를 탄다 */ + long countByUserIdAndDeletedAtIsNotNull(Long userId); + + /** + * 휴지통 첫 페이지. 최근 삭제순, 같은 시각이면 ID가 큰 것부터. + * idx_templates_user_deleted는 뒤에 기본 키가 붙어 있어 이 정렬을 인덱스 역방향 스캔으로 처리한다 + */ + @Query(""" + select t from Template t + where t.userId = :userId and t.deletedAt is not null + order by t.deletedAt desc, t.id desc + """) + List