Skip to content
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

[Feat/#31] 경험 기록 리스트 조회 기능 구현 #33

Merged
merged 4 commits into from
Oct 31, 2024
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 @@ -32,7 +32,7 @@ public class Ability extends BaseEntity {
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "analysis_id", nullable = false)
private Analysis analysis;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.BatchSize;

import java.util.List;

Expand All @@ -29,6 +30,7 @@ public class Analysis extends BaseEntity {
@JoinColumn(name = "record_id", nullable = false)
private Record record;

@BatchSize(size = 3)
@OneToMany(mappedBy = "analysis", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Ability> abilityList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface FolderRepository extends JpaRepository<Folder, Long> {
Expand All @@ -19,5 +20,12 @@ public interface FolderRepository extends JpaRepository<Folder, Long> {
"ORDER BY f.createdAt desc ")
List<FolderResponse.FolderDto> findFolderDtoList(@Param(value = "user") User user);

@Query("SELECT f " +
"FROM Folder f " +
"WHERE f.title = :title AND f.user = :user ")
Optional<Folder> findFolderByTitle(
@Param(value = "title") String title,
@Param(value = "user") User user);

boolean existsByTitle(String title);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public enum RecordSuccessStatus implements BaseSuccessStatus {
MEMO_RECORD_CREATE_SUCCESS(HttpStatus.CREATED, "S404", "메모 경험 기록이 성공적으로 완료되었습니다."),
MEMO_RECORD_DETAIL_GET_SUCCESS(HttpStatus.OK, "S401", "메모 경험 기록 세부 조회가 성공적으로 완료되었습니다."),
MEMO_RECORD_TMP_CREATE_SUCCESS(HttpStatus.OK, "S403", "메모 경험 기록 임시 저장이 성공적으로 완료되었습니다."),
MEMO_RECORD_TMP_GET_SUCCESS(HttpStatus.OK, "S402", "메모 경험 기록 임시 저장 내역 조회가 성공적으로 완료되었습니다.")
MEMO_RECORD_TMP_GET_SUCCESS(HttpStatus.OK, "S402", "메모 경험 기록 임시 저장 내역 조회가 성공적으로 완료되었습니다."),
RECORD_LIST_GET_SUCCESS(HttpStatus.OK, "S602", "폴더별 경험 기록 리스트 조회가 성공적으로 완료되었습니다."),
KEYWORD_RECORD_LIST_GET_SUCCESS(HttpStatus.OK, "S503", "역량 키워드별 경험 기록 리스트 조회가 성공적으로 완료되었습니다.")
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,22 @@ public ResponseEntity<ApiResponse<RecordResponse.TmpMemoRecordDto>> getTmpMemoRe
return ApiResponse.success(RecordSuccessStatus.MEMO_RECORD_TMP_GET_SUCCESS, recordResponse);
}

@GetMapping("")
public ResponseEntity<ApiResponse<RecordResponse.RecordListDto>> getRecordListByFolder(
@UserId Long userId,
@RequestParam(name = "folder", defaultValue = "all") String folder
) {
RecordResponse.RecordListDto recordResponse = recordService.getRecordList(userId, folder);
return ApiResponse.success(RecordSuccessStatus.RECORD_LIST_GET_SUCCESS, recordResponse);
}

@GetMapping("/keyword")
public ResponseEntity<ApiResponse<RecordResponse.KeywordRecordListDto>> getRecordListByKeyword(
@UserId Long userId,
@RequestParam(name = "keyword") String keyword
) {
RecordResponse.KeywordRecordListDto recordResponse = recordService.getKeywordRecordList(userId, keyword);
return ApiResponse.success(RecordSuccessStatus.KEYWORD_RECORD_LIST_GET_SUCCESS, recordResponse);
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package corecord.dev.domain.record.converter;

import corecord.dev.domain.analysis.constant.Keyword;
import corecord.dev.domain.analysis.entity.Ability;
import corecord.dev.domain.folder.entity.Folder;
import corecord.dev.domain.record.constant.RecordType;
import corecord.dev.domain.record.dto.response.RecordResponse;
import corecord.dev.domain.record.entity.Record;
import corecord.dev.domain.user.entity.User;

import java.util.List;

public class RecordConverter {
public static Record toMemoRecordEntity(String title, String content, User user, Folder folder) {
return Record.builder()
Expand Down Expand Up @@ -42,4 +46,53 @@ public static RecordResponse.TmpMemoRecordDto toNotExistingTmpMemoRecordDto() {
.content(null)
.build();
}

public static RecordResponse.RecordDto toRecordDto(Record record) {
List<String> keywordList = record.getAnalysis().getAbilityList().stream()
.map(Ability::getKeyword)
.map(Keyword::getValue)
.toList();

return RecordResponse.RecordDto.builder()
.analysisId(record.getAnalysis().getAnalysisId())
.folder(record.getFolder().getTitle())
.title(record.getTitle())
.keywordList(keywordList)
.createdAt(record.getCreatedAtFormatted())
.build();
}

public static RecordResponse.RecordListDto toRecordListDto(String folder, List<Record> recordList) {
List<RecordResponse.RecordDto> recordDtoList = recordList.stream()
.map(RecordConverter::toRecordDto)
.toList();

return RecordResponse.RecordListDto.builder()
.folder(folder)
.recordDtoList(recordDtoList)
.build();
}

public static RecordResponse.KeywordRecordDto toKeywordRecordDto(Record record) {
String content = record.getContent();
String truncatedContent = content.length() > 30 ? content.substring(0, 30) : content;

return RecordResponse.KeywordRecordDto.builder()
.analysisId(record.getAnalysis().getAnalysisId())
.folder(record.getFolder().getTitle())
.title(record.getTitle())
.content(truncatedContent)
.createdAt(record.getCreatedAtFormatted())
.build();
}

public static RecordResponse.KeywordRecordListDto toKeywordRecordListDto(List<Record> recordList) {
List<RecordResponse.KeywordRecordDto> keywordRecordDtoList = recordList.stream()
.map(RecordConverter::toKeywordRecordDto)
.toList();

return RecordResponse.KeywordRecordListDto.builder()
.recordDtoList(keywordRecordDtoList)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import lombok.Data;
import lombok.Getter;

import java.util.List;

public class RecordResponse {
@Builder
@Getter
Expand All @@ -27,4 +29,45 @@ public static class TmpMemoRecordDto {
private String title;
private String content;
}

@Builder
@Getter
@AllArgsConstructor
@Data
public static class RecordDto {
private Long analysisId;
private String folder;
private String title;
private List<String> keywordList;
private String createdAt;
}

@Builder
@Getter
@AllArgsConstructor
@Data
public static class RecordListDto {
private String folder;
private List<RecordDto> recordDtoList;
}

@Builder
@Getter
@AllArgsConstructor
@Data
public static class KeywordRecordDto {
private Long analysisId;
private String folder;
private String title;
private String content;
private String createdAt;
}

@Builder
@Getter
@AllArgsConstructor
@Data
public static class KeywordRecordListDto {
private List<KeywordRecordDto> recordDtoList;
}
}
4 changes: 2 additions & 2 deletions src/main/java/corecord/dev/domain/record/entity/Record.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ public class Record extends BaseEntity {
@JoinColumn(name = "chat_room_id", nullable = true)
private ChatRoom chatRoom;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "folder_id", nullable = true)
private Folder folder;

@OneToOne(mappedBy = "record", cascade = CascadeType.ALL, orphanRemoval = true)
@OneToOne(mappedBy = "record", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Analysis analysis;

public void updateContent(String content) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,50 @@
package corecord.dev.domain.record.repository;

import corecord.dev.domain.analysis.constant.Keyword;
import corecord.dev.domain.folder.entity.Folder;
import corecord.dev.domain.record.entity.Record;
import corecord.dev.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface RecordRepository extends JpaRepository<Record, Long> {

@Query("SELECT r " +
"FROM Record r " +
"JOIN FETCH r.analysis a " +
"JOIN FETCH r.folder f " +
"JOIN FETCH a.abilityList al " +
"WHERE r.user = :user " +
"AND r.folder is not null AND r.folder = :folder "+ // 임시 저장 기록 제외
"ORDER BY r.createdAt desc ") // 최근 생성 순 정렬
List<Record> findRecordsByFolder(
@Param(value = "folder") Folder folder,
@Param(value = "user") User user);

@Query("SELECT r FROM Record r " +
"JOIN FETCH r.analysis a " +
"JOIN FETCH r.folder f " +
"JOIN FETCH a.abilityList al " +
"WHERE r.user = :user " +
"AND r.folder is not null " + // 임시 저장 기록 제외
"ORDER BY r.createdAt DESC") // 최근 생성 순 정렬
List<Record> findRecords(@Param(value = "user") User user);


@Query("SELECT r FROM Ability a " +
"JOIN a.analysis an " +
"JOIN an.record r " +
"JOIN FETCH r.folder f " +
"WHERE a.user = :user " +
"AND a.keyword = :keyword " +
"AND r.folder is not null " + // 임시 저장 기록 제외
"ORDER BY r.createdAt DESC") // 최근 생성 순 정렬
List<Record> findRecordByKeyword(
@Param(value = "keyword")Keyword keyword,
@Param(value = "user") User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import corecord.dev.common.exception.GeneralException;
import corecord.dev.common.status.ErrorStatus;
import corecord.dev.domain.analysis.constant.Keyword;
import corecord.dev.domain.analysis.exception.enums.AnalysisErrorStatus;
import corecord.dev.domain.analysis.exception.model.AnalysisException;
import corecord.dev.domain.analysis.service.AnalysisService;
import corecord.dev.domain.folder.entity.Folder;
import corecord.dev.domain.folder.exception.enums.FolderErrorStatus;
Expand All @@ -21,6 +24,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
Expand Down Expand Up @@ -118,6 +123,43 @@ public RecordResponse.TmpMemoRecordDto getTmpMemoRecord(Long userId) {
return RecordConverter.toExistingTmpMemoRecordDto(tmpMemoRecord);
}

/*
* 폴더별 경험 기록 리스트를 반환합니다. folder의 default value는 'all'입니다.
* @param userId, folderName
* @return
*/
@Transactional(readOnly = true)
public RecordResponse.RecordListDto getRecordList(Long userId, String folderName) {
User user = findUserById(userId);
List<Record> recordList;

// 임시 저장 기록 제외 Record List 최신 생성 순 조회
if (folderName.equals("all")) {
recordList = getRecordList(user);
} else {
Folder folder = findFolderByTitle(user, folderName);
recordList = getRecordListByFolder(user, folder);
}

return RecordConverter.toRecordListDto(folderName, recordList);
}

/*
* keyword를 받아 해당 키워드를 가진 역량 분석 정보와 경험 기록 정보를 반환
* @param userId, keywordValue
* @return
*/
@Transactional(readOnly = true)
public RecordResponse.KeywordRecordListDto getKeywordRecordList(Long userId, String keywordValue) {
User user = findUserById(userId);

// 해당 keyword를 가진 ability 객체 조회 후 맵핑된 Record 객체 리스트 조회
Keyword keyword = getKeyword(keywordValue);
List<Record> recordList = getRecordListByKeyword(user, keyword);

return RecordConverter.toKeywordRecordListDto(recordList);
}

private void validHasUserTmpMemo(User user) {
if (user.getTmpMemo() != null)
throw new RecordException(RecordErrorStatus.ALREADY_TMP_MEMO);
Expand All @@ -143,6 +185,11 @@ private Folder findFolderById(Long folderId) {
.orElseThrow(() -> new FolderException(FolderErrorStatus.FOLDER_NOT_FOUND));
}

private Folder findFolderByTitle(User user, String title) {
return folderRepository.findFolderByTitle(title, user)
.orElseThrow(() -> new FolderException(FolderErrorStatus.FOLDER_NOT_FOUND));
}

private User findUserById(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new GeneralException(ErrorStatus.UNAUTHORIZED));
Expand All @@ -152,4 +199,23 @@ private Record findRecordById(Long recordId) {
return recordRepository.findById(recordId)
.orElseThrow(() -> new RecordException(RecordErrorStatus.RECORD_NOT_FOUND));
}

private List<Record> getRecordListByFolder(User user, Folder folder) {
return recordRepository.findRecordsByFolder(folder, user);
}

private List<Record> getRecordList(User user) {
return recordRepository.findRecords(user);
}

private List<Record> getRecordListByKeyword(User user, Keyword keyword) {
return recordRepository.findRecordByKeyword(keyword, user);
}

private Keyword getKeyword(String keywordValue) {
Keyword keyword = Keyword.getName(keywordValue);
if (keyword == null)
throw new AnalysisException(AnalysisErrorStatus.INVALID_KEYWORD);
return keyword;
}
}