From 12494f1a3b43f60a1c9f76386c7b62c7d2767483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=99=A9=EC=A0=95=EB=B9=88?= Date: Mon, 6 Apr 2026 17:15:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9D=B4=EB=B2=8C=20=EC=8B=A0?= =?UTF-8?q?=EC=B2=AD=20=EA=B0=80=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=8B=A0=EC=B2=AD=20=EB=B6=88=EA=B0=80=20=EB=8C=80?= =?UTF-8?q?=EC=83=81=20=EC=A0=9C=EC=99=B8=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/GetAllAbleRivalsService.java | 29 ++++++++++++++-- .../service/SearchRivalByKeywordService.java | 33 +++++++++++++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/process/clash/application/compete/rival/rival/service/GetAllAbleRivalsService.java b/src/main/java/com/process/clash/application/compete/rival/rival/service/GetAllAbleRivalsService.java index 554d78e30..a800aa74d 100644 --- a/src/main/java/com/process/clash/application/compete/rival/rival/service/GetAllAbleRivalsService.java +++ b/src/main/java/com/process/clash/application/compete/rival/rival/service/GetAllAbleRivalsService.java @@ -12,6 +12,8 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.Stream; @Service @@ -19,16 +21,22 @@ @Transactional(readOnly = true) public class GetAllAbleRivalsService implements GetAllAbleRivalsUseCase { + private static final int MAX_RIVAL_COUNT = 4; + private final RivalRepositoryPort rivalRepositoryPort; private final UserRepositoryPort userRepositoryPort; @Override public GetAllAbleRivalsData.Result execute(GetAllAbleRivalsData.Command command) { - List rivals = rivalRepositoryPort.findAllRivalsByUserId(command.actor().id()); - Long myId = command.actor().id(); + if (rivalRepositoryPort.countAcceptedByUserId(myId) >= MAX_RIVAL_COUNT) { + return GetAllAbleRivalsData.Result.from(List.of()); + } + + List rivals = rivalRepositoryPort.findAllRivalsByUserId(myId); + List excludedUserIds = Stream.concat( rivals.stream() .filter(rival -> rival.rivalLinkingStatus() == RivalLinkingStatus.PENDING @@ -42,8 +50,23 @@ public GetAllAbleRivalsData.Result execute(GetAllAbleRivalsData.Command command) Stream.of(myId) ).distinct().toList(); + List candidates = userRepositoryPort.findAbleRivalsWithUserInfo(excludedUserIds); + + if (candidates.isEmpty()) { + return GetAllAbleRivalsData.Result.from(List.of()); + } + + List candidateIds = candidates.stream().map(AbleRivalInfoForRival::id).toList(); + Map acceptedCounts = rivalRepositoryPort.countAcceptedByUserIdsGrouped(candidateIds) + .stream() + .collect(Collectors.toMap( + map -> ((Number) map.get("user_id")).longValue(), + map -> ((Number) map.get("count")).intValue() + )); - List ableRivalInfoForRivals = userRepositoryPort.findAbleRivalsWithUserInfo(excludedUserIds); + List ableRivalInfoForRivals = candidates.stream() + .filter(user -> acceptedCounts.getOrDefault(user.id(), 0) < MAX_RIVAL_COUNT) + .toList(); return GetAllAbleRivalsData.Result.from(ableRivalInfoForRivals); } diff --git a/src/main/java/com/process/clash/application/compete/rival/rival/service/SearchRivalByKeywordService.java b/src/main/java/com/process/clash/application/compete/rival/rival/service/SearchRivalByKeywordService.java index 50911c2af..0b6ec11ec 100644 --- a/src/main/java/com/process/clash/application/compete/rival/rival/service/SearchRivalByKeywordService.java +++ b/src/main/java/com/process/clash/application/compete/rival/rival/service/SearchRivalByKeywordService.java @@ -6,11 +6,14 @@ import com.process.clash.application.compete.rival.rival.port.out.RivalRepositoryPort; import com.process.clash.application.user.usergithub.port.out.UserGitHubRepositoryPort; import com.process.clash.domain.rival.rival.entity.Rival; +import com.process.clash.domain.rival.rival.enums.RivalLinkingStatus; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.Stream; @Service @@ -18,6 +21,8 @@ @Transactional(readOnly = true) public class SearchRivalByKeywordService implements SearchRivalByKeywordUseCase { + private static final int MAX_RIVAL_COUNT = 4; + private final RivalRepositoryPort rivalRepositoryPort; private final UserGitHubRepositoryPort userGitHubRepositoryPort; @@ -26,10 +31,16 @@ public SearchRivalByKeywordData.Result execute(SearchRivalByKeywordData.Command Long myId = command.actor().id(); - List rivals = rivalRepositoryPort.findAllByUserId(myId); + if (rivalRepositoryPort.countAcceptedByUserId(myId) >= MAX_RIVAL_COUNT) { + return SearchRivalByKeywordData.Result.from(List.of()); + } + + List rivals = rivalRepositoryPort.findAllRivalsByUserId(myId); List excludedUserIds = Stream.concat( rivals.stream() + .filter(rival -> rival.rivalLinkingStatus() == RivalLinkingStatus.PENDING + || rival.rivalLinkingStatus() == RivalLinkingStatus.ACCEPTED) .map(rival -> { if (rival.firstUserId().equals(myId)) { return rival.secondUserId(); @@ -38,14 +49,30 @@ public SearchRivalByKeywordData.Result execute(SearchRivalByKeywordData.Command } }), Stream.of(myId) - ).toList(); + ).distinct().toList(); - List ableRivalInfoForRivals = + List candidates = userGitHubRepositoryPort.findAbleRivalsWithUserInfoByKeyword( excludedUserIds, command.keyword() ); + if (candidates.isEmpty()) { + return SearchRivalByKeywordData.Result.from(List.of()); + } + + List candidateIds = candidates.stream().map(AbleRivalInfoForRival::id).toList(); + Map acceptedCounts = rivalRepositoryPort.countAcceptedByUserIdsGrouped(candidateIds) + .stream() + .collect(Collectors.toMap( + map -> ((Number) map.get("user_id")).longValue(), + map -> ((Number) map.get("count")).intValue() + )); + + List ableRivalInfoForRivals = candidates.stream() + .filter(user -> acceptedCounts.getOrDefault(user.id(), 0) < MAX_RIVAL_COUNT) + .toList(); + return SearchRivalByKeywordData.Result.from(ableRivalInfoForRivals); }