Skip to content

Commit d11ddf6

Browse files
committed
feat(analysis): Repository 조회 관련 메서드 개선
1 parent cf4340c commit d11ddf6

File tree

7 files changed

+326
-138
lines changed

7 files changed

+326
-138
lines changed
Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.backend.domain.analysis.controller;
22

3+
import com.backend.domain.analysis.dto.request.AnalysisRequest;
34
import com.backend.domain.analysis.dto.response.AnalysisResultResponseDto;
45
import com.backend.domain.analysis.dto.response.HistoryResponseDto;
5-
import com.backend.domain.analysis.dto.request.AnalysisRequest;
66
import com.backend.domain.analysis.entity.AnalysisResult;
7-
import com.backend.domain.analysis.entity.Score;
87
import com.backend.domain.analysis.service.AnalysisService;
8+
import com.backend.domain.repository.dto.response.RepositoryResponse;
99
import com.backend.domain.repository.entity.Repositories;
1010
import com.backend.domain.repository.service.RepositoryService;
1111
import com.backend.global.exception.BusinessException;
@@ -18,7 +18,6 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.List;
21-
import java.util.Optional;
2221

2322
@RestController
2423
@RequiredArgsConstructor
@@ -38,59 +37,79 @@ public ResponseEntity<ApiResponse<Void>> analyzeRepository(@RequestBody Analysis
3837
return ResponseEntity.ok(ApiResponse.success());
3938
}
4039

41-
// GET: 사용자 히스토리 전체 목록 조회
42-
@GetMapping("/{memberId}")
40+
// GET: 사용자의 모든 Repository 목록 조회
41+
@GetMapping("/{memberId}/repositories")
4342
@Transactional(readOnly = true)
44-
public ResponseEntity<List<HistoryResponseDto>> getMemberHistory(@PathVariable Long memberId){
43+
public ResponseEntity<List<RepositoryResponse>> getMemberHistory(
44+
@PathVariable Long memberId
45+
){
4546
if (memberId == null) {
4647
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
4748
}
4849

49-
List<Repositories> repositories = repositoryService.findRepositoryByMember(memberId);
50-
List<HistoryResponseDto> historyList = new ArrayList<>();
50+
List<RepositoryResponse> repositories = repositoryService
51+
.findRepositoryByMember(memberId)
52+
.stream()
53+
.map(RepositoryResponse::new)
54+
.toList();
5155

52-
for (Repositories repo : repositories) {
53-
Optional<AnalysisResult> optionalAnalysis = analysisService.findByRepositoryId(repo.getId());
56+
return ResponseEntity.ok(repositories);
57+
}
5458

55-
if (optionalAnalysis.isEmpty()) {
56-
continue;
57-
}
59+
// GET: 특정 Repository의 분석 히스토리 조회, 모든 분석 결과 조회
60+
@GetMapping("/{memberId}/repositories/{repositoriesId}")
61+
@Transactional(readOnly = true)
62+
public ResponseEntity<HistoryResponseDto> getAnalysisByRepositoriesId(
63+
@PathVariable("memberId") Long memberId,
64+
@PathVariable("repositoriesId") Long repoId
65+
){
66+
// TODO: 추후 인증/인가 기능 완성 후 소유권 검증 로직 추가
5867

59-
AnalysisResult analysisResult = optionalAnalysis.get();
60-
Score score = analysisResult.getScore();
68+
// 1. Repository 정보 조회
69+
Repositories repository = repositoryService.findById(repoId)
70+
.orElseThrow(() -> new BusinessException(ErrorCode.GITHUB_REPO_NOT_FOUND));
6171

62-
List<String> languages = repositoryService.findLanguagesByRepisotryId(repo.getId())
63-
.stream()
64-
.map(Enum::name) // RepositoryLanguage -> Language enum
65-
.toList();
72+
RepositoryResponse repositoryResponse = new RepositoryResponse(repository);
6673

67-
HistoryResponseDto dto = new HistoryResponseDto(repo, analysisResult, score, languages);
68-
historyList.add(dto);
74+
// 2. 분석 결과 목록 조회 (최신순 정렬)
75+
List<AnalysisResult> analysisResults =
76+
analysisService.getAnalysisResultList(repoId);
77+
78+
// 3. 버전 DTO 생성 (최신이 가장 큰 번호)
79+
List<HistoryResponseDto.AnalysisVersionDto> versions = new ArrayList<>();
80+
int versionNumber = analysisResults.size();
81+
82+
for (AnalysisResult analysis : analysisResults) {
83+
versions.add(HistoryResponseDto.AnalysisVersionDto.from(analysis, versionNumber));
84+
versionNumber--;
6985
}
7086

71-
// 최신순 정렬
72-
historyList.sort((a, b) -> b.createDate().compareTo(a.createDate()));
87+
// 4. 응답 조합
88+
HistoryResponseDto response = HistoryResponseDto.of(repositoryResponse, versions);
7389

74-
return ResponseEntity.ok(historyList);
90+
return ResponseEntity.ok(response);
7591
}
7692

77-
// GET: 사용자 분석 결과 조회
78-
@GetMapping("/{memberId}/{repositoriesId}")
93+
// GET: 특정 분석 결과 상세 조회
94+
@GetMapping("/{memberId}/repositories/{repositoryId}/results/{analysisId}")
7995
@Transactional(readOnly = true)
80-
public ResponseEntity<List<AnalysisResultResponseDto>> getAnalysisByRepositoriesId(
81-
@PathVariable("memberId") Long memberId,
82-
@PathVariable("repositoriesId") Long repoId
83-
){
84-
List<AnalysisResult> optionalResult = analysisService.getAnalysisResultList(repoId);
85-
List<AnalysisResultResponseDto> resultList = new ArrayList<>();
96+
public ResponseEntity<AnalysisResultResponseDto> getAnalysisDetail(
97+
@PathVariable Long memberId,
98+
@PathVariable Long repositoryId,
99+
@PathVariable Long analysisId
100+
) {
101+
// TODO: 추후 인증/인가 검증
86102

103+
// 분석 결과 조회
104+
AnalysisResult analysisResult = analysisService.getAnalysisById(analysisId);
87105

88-
for(AnalysisResult result : optionalResult){
89-
Score score = result.getScore();
90-
AnalysisResultResponseDto dto = new AnalysisResultResponseDto(result, score);
91-
resultList.add(dto);
106+
if (!analysisResult.getRepositories().getId().equals(repositoryId)) {
107+
throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
92108
}
93109

94-
return ResponseEntity.ok(resultList);
110+
AnalysisResultResponseDto response =
111+
new AnalysisResultResponseDto(analysisResult, analysisResult.getScore());
112+
113+
return ResponseEntity.ok(response);
95114
}
96115
}

backend/src/main/java/com/backend/domain/analysis/dto/response/AnalysisResultResponseDto.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import com.backend.domain.analysis.entity.AnalysisResult;
44
import com.backend.domain.analysis.entity.Score;
55

6+
/**
7+
* 특정 분석 결과의 상세 정보 응답 DTO
8+
* 분석 점수, 피드백 등을 포함
9+
*/
610
public record AnalysisResultResponseDto(
711
int totalScore,
812
int readmeScore,
Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,44 @@
11
package com.backend.domain.analysis.dto.response;
22

33
import com.backend.domain.analysis.entity.AnalysisResult;
4-
import com.backend.domain.analysis.entity.Score;
5-
import com.backend.domain.repository.entity.Repositories;
4+
import com.backend.domain.repository.dto.response.RepositoryResponse;
65

76
import java.time.LocalDateTime;
87
import java.util.List;
98

9+
/**
10+
* Repository 상세 정보 + 분석 버전 목록 응답 DTO
11+
* 특정 Repository의 모든 분석 버전을 조회할 때 사용
12+
*/
1013
public record HistoryResponseDto(
11-
String repositoryName,
12-
LocalDateTime createDate,
13-
List<String> languages,
14-
int totalScore,
15-
boolean publicStatus
14+
RepositoryResponse repository, // Repository 기본 정보
15+
List<AnalysisVersionDto> analysisVersions
1616
) {
17-
public HistoryResponseDto(Repositories repositories, AnalysisResult analysisResult, Score score, List<String> languages){
18-
this(
19-
repositories.getName(),
20-
analysisResult.getCreateDate(),
21-
languages,
22-
score.getTotalScore(),
23-
repositories.isPublicRepository()
24-
);
25-
}
17+
public static HistoryResponseDto of(
18+
RepositoryResponse repository,
19+
List<AnalysisVersionDto> versions
20+
) {
21+
return new HistoryResponseDto(repository, versions);
22+
}
23+
24+
public record AnalysisVersionDto(
25+
Long analysisId,
26+
LocalDateTime analysisDate,
27+
Integer totalScore,
28+
String versionLabel
29+
) {
30+
public static AnalysisVersionDto from(
31+
AnalysisResult analysis,
32+
int versionNumber
33+
) {
34+
return new AnalysisVersionDto(
35+
analysis.getId(),
36+
analysis.getCreateDate(),
37+
analysis.getScore().getTotalScore(),
38+
String.format("v%d (%s)",
39+
versionNumber,
40+
analysis.getCreateDate().toLocalDate())
41+
);
42+
}
43+
}
2644
}

backend/src/main/java/com/backend/domain/analysis/service/AnalysisService.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.backend.domain.analysis.service;
22

3-
import com.backend.domain.repository.dto.response.RepositoryData;
43
import com.backend.domain.analysis.entity.AnalysisResult;
54
import com.backend.domain.analysis.repository.AnalysisResultRepository;
5+
import com.backend.domain.repository.dto.response.RepositoryData;
66
import com.backend.domain.repository.service.RepositoryService;
77
import com.backend.global.exception.BusinessException;
88
import com.backend.global.exception.ErrorCode;
@@ -12,7 +12,6 @@
1212
import org.springframework.transaction.annotation.Transactional;
1313

1414
import java.util.List;
15-
import java.util.Optional;
1615

1716
@Slf4j
1817
@Service
@@ -21,6 +20,12 @@ public class AnalysisService {
2120
private final RepositoryService repositoryService;
2221
private final AnalysisResultRepository analysisResultRepository;
2322

23+
/* Analysis 분석 프로세스 오케스트레이션 담당
24+
* 1. GitHub URL 파싱 및 검증
25+
* 2. Repository 도메인을 통한 데이터 수집
26+
* 3. Evaluation 도메인을 통한 AI 평가
27+
* 4. 분석 결과 저장
28+
* */
2429
@Transactional
2530
public void analyze(String githubUrl) {
2631
String[] repoInfo = parseGitHubUrl(githubUrl);
@@ -44,6 +49,7 @@ public void analyze(String githubUrl) {
4449
// TODO: AI 평가 저장
4550
}
4651

52+
// GitHub URL 파싱하여 owner와 repo 이름 추출
4753
private String[] parseGitHubUrl(String githubUrl) {
4854
log.info("🚩 분석 요청 url: {}", githubUrl);
4955

@@ -69,6 +75,7 @@ private String[] parseGitHubUrl(String githubUrl) {
6975
return new String[]{parts[0].trim(), parts[1].trim()};
7076
}
7177

78+
// Repository 데이터 수집 중 발생한 예외 처리
7279
private BusinessException handleRepositoryFetchError(BusinessException e, String owner, String repo) {
7380
return switch (e.getErrorCode()) {
7481
case GITHUB_REPO_NOT_FOUND ->
@@ -79,13 +86,14 @@ private BusinessException handleRepositoryFetchError(BusinessException e, String
7986
};
8087
}
8188

82-
// AnalysisRresult에서 repository id로 분석 결과 찾기
83-
public Optional<AnalysisResult> findByRepositoryId(Long RepositoryId) {
84-
return analysisResultRepository.findByRepositoriesId(RepositoryId);
89+
// 특정 Repository의 모든 분석 결과 조회 (최신순)
90+
public List<AnalysisResult> getAnalysisResultList(Long repositoryId){
91+
return analysisResultRepository.findAnalysisResultByRepositoriesId(repositoryId);
8592
}
8693

87-
// AnalysisResult를 list로 반환
88-
public List<AnalysisResult> getAnalysisResultList(Long RepositoryId){
89-
return analysisResultRepository.findAnalysisResultByRepositoriesId(RepositoryId);
94+
// 분석 결과 ID로 단건 조회
95+
public AnalysisResult getAnalysisById(Long analysisId) {
96+
return analysisResultRepository.findById(analysisId)
97+
.orElseThrow(() -> new BusinessException(ErrorCode.ANALYSIS_NOT_FOUND));
9098
}
9199
}

backend/src/main/java/com/backend/domain/repository/dto/response/RepositoryResponse.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
import java.util.List;
66
import java.util.stream.Collectors;
77

8+
/**
9+
* Repository 기본 정보 응답 DTO
10+
* 사용자의 Repository 목록 조회 시 사용
11+
*/
812
public record RepositoryResponse(
913
Long id,
1014
String name,

backend/src/main/java/com/backend/domain/repository/service/RepositoryService.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.backend.domain.repository.dto.response.RepositoryData;
44
import com.backend.domain.repository.dto.response.github.*;
5-
import com.backend.domain.repository.entity.Language;
65
import com.backend.domain.repository.entity.Repositories;
76
import com.backend.domain.repository.repository.RepositoryJpaRepository;
87
import com.backend.domain.repository.service.fetcher.GitHubDataFetcher;
@@ -21,12 +20,13 @@
2120
import java.time.temporal.ChronoUnit;
2221
import java.util.List;
2322
import java.util.Map;
23+
import java.util.Optional;
2424

2525
@Service
2626
@RequiredArgsConstructor
2727
public class RepositoryService {
2828

29-
// 임시
29+
// TODO: 임시 - 인증/인가 기능 구현 후 실제 로그인한 사용자로 대체 필요
3030
private final UserRepository userRepository;
3131

3232
private final GitHubDataFetcher gitHubDataFetcher;
@@ -46,13 +46,13 @@ public RepositoryData fetchAndSaveRepository(String owner, String repo) {
4646
try {
4747
return fetchCompleteRepositoryData(owner, repo);
4848
} catch (BusinessException e) {
49-
String errorCode = (e.getErrorCode() != null) ? e.getErrorCode().getCode() : "UNKNOWN";
5049
throw e;
5150
} catch (Exception e) {
5251
throw new BusinessException(ErrorCode.INTERNAL_ERROR);
5352
}
5453
}
5554

55+
// Github 저장소 데이터를 수집하고 DB에 저장 및 RepositoryData로 매핑
5656
@Transactional
5757
public RepositoryData fetchCompleteRepositoryData(String owner, String repo) {
5858
RepositoryData data = new RepositoryData();
@@ -97,6 +97,8 @@ public RepositoryData fetchCompleteRepositoryData(String owner, String repo) {
9797
return data;
9898
}
9999

100+
/* Repository Entity를 DB에 저장하거나 기존 데이터 업데이트
101+
* 같은 htmlUrl이 존재하면 업데이트, 없으면 신규 데이터 저장 */
100102
private Repositories saveOrUpdateRepository(RepoResponse repoInfo, String owner, String repo) {
101103
User defaultUser = userRepository.findAll().stream()
102104
.findFirst()
@@ -117,17 +119,17 @@ private Repositories saveOrUpdateRepository(RepoResponse repoInfo, String owner,
117119
});
118120
}
119121

120-
// Repository에서 member로 리포지토리 찾기
122+
// 특정 사용자의 모든 Repository 조회
121123
public List<Repositories> findRepositoryByMember(Long userId){
122124
return repositoryJpaRepository.findByUserId(userId);
123125
}
124126

125-
// Repository ID로 언어 조회
126-
public List<Language> findLanguagesByRepisotryId(Long gitRepositoryId){
127-
return repositoryJpaRepository.findLanguagesByRepositoryId(gitRepositoryId);
127+
// Repository ID로 단건 조회
128+
public Optional<Repositories> findById(Long repositoriesId) {
129+
return repositoryJpaRepository.findById(repositoriesId);
128130
}
129131

130-
// repository 삭제
132+
// Repository 삭제
131133
@Transactional
132134
public void delete(Long repositoriesId){
133135
if (repositoriesId == null) {

0 commit comments

Comments
 (0)