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-be: Dashboard 관련 API 쿼리 최적화 #718

Merged
merged 8 commits into from
Sep 25, 2024
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.cruru.applicant.domain.repository;

import com.cruru.applicant.domain.Applicant;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.process.domain.Process;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface ApplicantRepository extends JpaRepository<Applicant, Long> {

List<Applicant> findAllByProcess(Process process);

long countByProcess(Process process);

Optional<Applicant> findByEmail(String email);
@Query("SELECT a FROM Applicant a JOIN FETCH a.process p JOIN FETCH p.dashboard d WHERE d = :dashboard")
List<Applicant> findAllByDashboard(@Param("dashboard") Dashboard dashboard);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

import com.cruru.applyform.domain.ApplyForm;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.DashboardApplyFormDto;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface ApplyFormRepository extends JpaRepository<ApplyForm, Long> {

Optional<ApplyForm> findByDashboard(Dashboard dashboardId);

@Query("""
SELECT new com.cruru.dashboard.domain.DashboardApplyFormDto(d, a)
FROM ApplyForm a
JOIN FETCH a.dashboard d
JOIN FETCH d.club c
WHERE c.id = :clubId
""")
List<DashboardApplyFormDto> findAllByClub(@Param("clubId") Long clubId);
Comment on lines +23 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏿

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cruru.dashboard.domain;

import com.cruru.applyform.domain.ApplyForm;

public record DashboardApplyFormDto(Dashboard dashboard, ApplyForm applyForm) {

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package com.cruru.dashboard.domain.repository;

import com.cruru.club.domain.Club;
import com.cruru.dashboard.domain.Dashboard;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DashboardRepository extends JpaRepository<Dashboard, Long> {

List<Dashboard> findAllByClub(Club club);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.cruru.dashboard.facade;

import com.cruru.applicant.domain.Applicant;
import com.cruru.applicant.service.ApplicantService;
import com.cruru.applyform.controller.request.ApplyFormWriteRequest;
import com.cruru.applyform.domain.ApplyForm;
import com.cruru.applyform.service.ApplyFormService;
Expand All @@ -13,10 +12,8 @@
import com.cruru.dashboard.controller.response.DashboardsOfClubResponse;
import com.cruru.dashboard.controller.response.StatsResponse;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.DashboardApplyFormDto;
import com.cruru.dashboard.service.DashboardService;
import com.cruru.member.service.MemberService;
import com.cruru.process.domain.Process;
import com.cruru.process.service.ProcessService;
import com.cruru.question.controller.request.QuestionCreateRequest;
import com.cruru.question.service.QuestionService;
import java.time.Clock;
Expand All @@ -33,13 +30,10 @@
@RequiredArgsConstructor
public class DashboardFacade {

private final MemberService memberService;
private final ClubService clubService;
private final DashboardService dashboardService;
private final ApplyFormService applyFormService;
private final QuestionService questionService;
private final ProcessService processService;
private final ApplicantService applicantService;
private final Clock clock;

@Transactional
Expand All @@ -64,9 +58,7 @@ private ApplyFormWriteRequest toApplyFormWriteRequest(DashboardCreateRequest req
}

public DashboardsOfClubResponse findAllDashboardsByClubId(long clubId) {
Club club = clubService.findById(clubId);

List<Dashboard> dashboards = dashboardService.findAllByClub(club);
List<DashboardApplyFormDto> dashboards = dashboardService.findAllByClub(clubId);

String clubName = clubService.findById(clubId).getName();
LocalDateTime now = LocalDateTime.now(clock);
Expand All @@ -79,10 +71,12 @@ public DashboardsOfClubResponse findAllDashboardsByClubId(long clubId) {
return new DashboardsOfClubResponse(clubName, sortedDashboardPreviews);
}

private DashboardPreviewResponse createDashboardPreviewResponse(Dashboard dashboard) {
ApplyForm applyForm = applyFormService.findByDashboard(dashboard);
List<Applicant> allApplicants = getAllApplicantsByDashboardId(dashboard);
StatsResponse stats = calculateStats(allApplicants);
private DashboardPreviewResponse createDashboardPreviewResponse(DashboardApplyFormDto dashboardApplyformDto) {
Dashboard dashboard = dashboardApplyformDto.dashboard();
ApplyForm applyForm = dashboardApplyformDto.applyForm();

List<Applicant> applicants = dashboardService.findAllApplicants(dashboard);
StatsResponse stats = calculateStats(applicants);
return new DashboardPreviewResponse(
dashboard.getId(),
applyForm.getId(),
Expand Down Expand Up @@ -115,14 +109,6 @@ private List<DashboardPreviewResponse> sortDashboardPreviews(
return sortedDashboards;
}

private List<Applicant> getAllApplicantsByDashboardId(Dashboard dashboard) {
List<Process> processes = processService.findAllByDashboard(dashboard);
return processes.stream()
.flatMap(process -> applicantService.findAllByProcess(process)
.stream())
.toList();
}

private StatsResponse calculateStats(List<Applicant> allApplicants) {
int totalApplicants = allApplicants.size();
int totalFails = (int) allApplicants.stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.cruru.dashboard.service;

import com.cruru.applicant.domain.Applicant;
import com.cruru.applicant.domain.repository.ApplicantRepository;
import com.cruru.applyform.domain.repository.ApplyFormRepository;
import com.cruru.club.domain.Club;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.DashboardApplyFormDto;
import com.cruru.dashboard.domain.repository.DashboardRepository;
import com.cruru.dashboard.exception.DashboardNotFoundException;
import com.cruru.process.domain.Process;
Expand All @@ -19,6 +23,8 @@ public class DashboardService {

private final DashboardRepository dashboardRepository;
private final ProcessRepository processRepository;
private final ApplicantRepository applicantRepository;
private final ApplyFormRepository applyFormRepository;

@Transactional
public Dashboard create(Club club) {
Expand All @@ -35,7 +41,11 @@ public Dashboard findById(Long id) {
.orElseThrow(DashboardNotFoundException::new);
}

public List<Dashboard> findAllByClub(Club club) {
return dashboardRepository.findAllByClub(club);
public List<DashboardApplyFormDto> findAllByClub(long clubId) {
return applyFormRepository.findAllByClub(clubId);
}

public List<Applicant> findAllApplicants(Dashboard dashboard) {
return applicantRepository.findAllByDashboard(dashboard);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
import static org.assertj.core.api.Assertions.assertThat;

import com.cruru.applicant.domain.Applicant;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.repository.DashboardRepository;
import com.cruru.process.domain.Process;
import com.cruru.process.domain.repository.ProcessRepository;
import com.cruru.util.RepositoryTest;
import com.cruru.util.fixture.ApplicantFixture;
import com.cruru.util.fixture.DashboardFixture;
import com.cruru.util.fixture.ProcessFixture;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -16,6 +23,12 @@ class ApplicantRepositoryTest extends RepositoryTest {
@Autowired
private ApplicantRepository applicantRepository;

@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private ProcessRepository processRepository;

@BeforeEach
void setUp() {
applicantRepository.deleteAllInBatch();
Expand Down Expand Up @@ -53,4 +66,25 @@ void saveNoId() {
//then
assertThat(savedApplicant1.getId() + 1).isEqualTo(savedApplicant2.getId());
}

@DisplayName("특정 대시보드에 해당하는 지원자 목록을 반환한다.")
@Test
void findAllByDashboard() {
// given
Dashboard dashboard = dashboardRepository.save(DashboardFixture.backend());

Process process1 = processRepository.save(ProcessFixture.applyType(dashboard));
Process process2 = processRepository.save(ProcessFixture.approveType(dashboard));

Applicant applicant1 = applicantRepository.save(ApplicantFixture.pendingDobby(process1));
Applicant applicant2 = applicantRepository.save(ApplicantFixture.pendingDobby(process1));
Applicant applicant3 = applicantRepository.save(ApplicantFixture.pendingDobby(process2));

// when
List<Applicant> applicants = applicantRepository.findAllByDashboard(dashboard);

// then
assertThat(applicants).hasSize(3);
assertThat(applicants).containsExactlyInAnyOrder(applicant1, applicant2, applicant3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
import static org.junit.jupiter.api.Assertions.assertAll;

import com.cruru.applyform.domain.ApplyForm;
import com.cruru.club.domain.Club;
import com.cruru.club.domain.repository.ClubRepository;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.DashboardApplyFormDto;
import com.cruru.dashboard.domain.repository.DashboardRepository;
import com.cruru.util.RepositoryTest;
import com.cruru.util.fixture.ApplyFormFixture;
import com.cruru.util.fixture.ClubFixture;
import com.cruru.util.fixture.DashboardFixture;
import com.cruru.util.fixture.LocalDateFixture;
import java.time.LocalDateTime;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -25,6 +30,9 @@ class ApplyFormRepositoryTest extends RepositoryTest {
@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private ClubRepository clubRepository;

@BeforeEach
void setUp() {
applyFormRepository.deleteAllInBatch();
Expand Down Expand Up @@ -80,4 +88,32 @@ void save_NotSavedId() {
//then
assertThat(savedApplyForm1.getId() + 1).isEqualTo(savedApplyForm2.getId());
}

@DisplayName("특정 동아리에 속하는 DashboardApplyForm 목록을 반환한다.")
@Test
void findAllByClub() {
// given
Club club = clubRepository.save(ClubFixture.create());
Dashboard dashboard1 = dashboardRepository.save(DashboardFixture.frontend(club));
Dashboard dashboard2 = dashboardRepository.save(DashboardFixture.backend(club));

ApplyForm applyForm1 = applyFormRepository.save(ApplyFormFixture.frontend(dashboard1));
ApplyForm applyForm2 = applyFormRepository.save(ApplyFormFixture.backend(dashboard2));

// when
List<DashboardApplyFormDto> dashboardApplyFormDtos = applyFormRepository.findAllByClub(club.getId());

// then
assertThat(dashboardApplyFormDtos).hasSize(2);

DashboardApplyFormDto dto1 = dashboardApplyFormDtos.get(0);
DashboardApplyFormDto dto2 = dashboardApplyFormDtos.get(1);

assertAll(
() -> assertThat(dto1.dashboard().getId()).isEqualTo(dashboard1.getId()),
() -> assertThat(dto1.applyForm().getId()).isEqualTo(applyForm1.getId()),
() -> assertThat(dto2.dashboard().getId()).isEqualTo(dashboard2.getId()),
() -> assertThat(dto2.applyForm().getId()).isEqualTo(applyForm2.getId())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ void update() {
String toChangeDescription = "# 모집 공고 설명 #";
LocalDateTime toChangeStartDate = LocalDateFixture.oneDayLater();
LocalDateTime toChangeEndDate = LocalDateFixture.oneWeekLater();

ApplyForm applyForm = applyFormRepository.save(ApplyFormFixture.backend(dashboard));
ApplyFormWriteRequest request = new ApplyFormWriteRequest(
toChangeTitle, toChangeDescription, toChangeStartDate, toChangeEndDate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ void create() {
void findAllDashboardsByClubId() {
// given
Dashboard dashboard = dashboardRepository.save(DashboardFixture.backend(club));
Dashboard dashboard1 = dashboardRepository.save(DashboardFixture.backend(club));
ApplyForm applyForm = applyFormRepository.save(ApplyFormFixture.backend(dashboard));
ApplyForm applyForm1 = applyFormRepository.save(ApplyFormFixture.backend(dashboard1));
Process firstProcess = processRepository.save(ProcessFixture.applyType(dashboard));
Process lastProcess = processRepository.save(ProcessFixture.approveType(dashboard));
Process firstProcess1 = processRepository.save(ProcessFixture.applyType(dashboard1));
Process lastProcess1 = processRepository.save(ProcessFixture.approveType(dashboard1));

List<Applicant> applicants = List.of(
// 마지막 프로세스에 있으면서 불합격 상태인 경우, 불합격
Expand All @@ -108,6 +112,16 @@ void findAllDashboardsByClubId() {
);
applicantRepository.saveAll(applicants);

List<Applicant> applicants1 = List.of(
ApplicantFixture.rejectedRush(lastProcess1),
ApplicantFixture.rejectedRush(firstProcess1),
ApplicantFixture.pendingDobby(lastProcess1),
ApplicantFixture.pendingDobby(firstProcess1),
ApplicantFixture.pendingDobby(firstProcess1),
ApplicantFixture.pendingDobby(firstProcess1)
);
applicantRepository.saveAll(applicants1);

// when
DashboardsOfClubResponse dashboardsOfClubResponse =
dashboardFacade.findAllDashboardsByClubId(club.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import com.cruru.applyform.domain.ApplyForm;
import com.cruru.applyform.domain.repository.ApplyFormRepository;
import com.cruru.club.domain.Club;
import com.cruru.club.domain.repository.ClubRepository;
import com.cruru.dashboard.domain.Dashboard;
import com.cruru.dashboard.domain.DashboardApplyFormDto;
import com.cruru.dashboard.domain.repository.DashboardRepository;
import com.cruru.process.domain.Process;
import com.cruru.process.domain.repository.ProcessRepository;
import com.cruru.util.ServiceTest;
import com.cruru.util.fixture.ApplyFormFixture;
import com.cruru.util.fixture.ClubFixture;
import com.cruru.util.fixture.DashboardFixture;
import java.util.Comparator;
Expand All @@ -34,6 +38,9 @@ class DashboardServiceTest extends ServiceTest {
@Autowired
private DashboardRepository dashboardRepository;

@Autowired
private ApplyFormRepository applyFormRepository;

@DisplayName("새로운 대시보드를 생성시, 기본 프로세스 2개가 생성된다.")
@Test
void create_createDefaultProcess() {
Expand Down Expand Up @@ -75,11 +82,13 @@ void findAllByClub() {
Club club = clubRepository.save(ClubFixture.create());
Dashboard backendDashboard = dashboardRepository.save(DashboardFixture.backend(club));
Dashboard frontendDashboard = dashboardRepository.save(DashboardFixture.frontend(club));
ApplyForm backendApplyform = applyFormRepository.save(ApplyFormFixture.backend(backendDashboard));
ApplyForm frontendApplyform = applyFormRepository.save(ApplyFormFixture.frontend(frontendDashboard));

// when & then
assertThat(dashboardService.findAllByClub(club)).containsExactlyInAnyOrder(
backendDashboard,
frontendDashboard
// when&then
assertThat(dashboardService.findAllByClub(club.getId())).containsExactlyInAnyOrder(
new DashboardApplyFormDto(backendDashboard, backendApplyform),
new DashboardApplyFormDto(frontendDashboard, frontendApplyform)
);
}
}