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

[Academy schedules] 학원 Location 관련 목록 조회 쿼리 개선 #121

Merged
merged 11 commits into from
Dec 9, 2023
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
package org.guzzing.studayserver.domain.academy.controller;

import jakarta.validation.Valid;
import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademiesByLocationRequest;
import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademiesByNameRequest;
import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademyByLocationWithScrollRequest;
import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademyFilterRequest;
import org.guzzing.studayserver.domain.academy.controller.dto.request.AcademyFilterWithScrollRequest;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesByLocationResponses;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesByLocationWithScrollResponses;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesByNameResponses;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademiesFilterWithScrollResponses;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademyFilterResponses;
import org.guzzing.studayserver.domain.academy.controller.dto.response.AcademyGetResponse;
import org.guzzing.studayserver.domain.academy.controller.dto.response.LessonInfoToCreateDashboardResponses;
import org.guzzing.studayserver.domain.academy.facade.AcademyFacade;
import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationFacadeResult;
import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationWithScrollFacadeResult;
import org.guzzing.studayserver.domain.academy.service.AcademyService;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesFilterWithScrollResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.LessonInfoToCreateDashboardResults;
import org.guzzing.studayserver.domain.auth.memberId.MemberId;
import org.springframework.http.HttpStatus;
@@ -54,20 +48,6 @@ public ResponseEntity<AcademyGetResponse> getAcademy(
.body(AcademyGetResponse.from(academyService.getAcademy(academyId, memberId)));
}

@GetMapping(
path = "/complexes",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AcademiesByLocationResponses> findByLocation(
@ModelAttribute @Valid AcademiesByLocationRequest request,
@MemberId Long memberId
) {
AcademiesByLocationFacadeResult response = academyFacade.findByLocation(
AcademiesByLocationRequest.to(request, memberId));

return ResponseEntity.status(HttpStatus.OK)
.body(AcademiesByLocationResponses.from(response));
}

@GetMapping(
path = "/complexes-scroll",
produces = MediaType.APPLICATION_JSON_VALUE)
@@ -95,20 +75,6 @@ public ResponseEntity<AcademiesByNameResponses> findByName(
.body(AcademiesByNameResponses.from(academiesByNameResults));
}

@GetMapping(
path = "/filter",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AcademyFilterResponses> filterAcademies(
@ModelAttribute @Valid AcademyFilterRequest request,
@MemberId Long memberId
) {
AcademyFilterResults academyFilterResults = academyService.filterAcademies(
AcademyFilterRequest.to(request), memberId);

return ResponseEntity.status(HttpStatus.OK)
.body(AcademyFilterResponses.from(academyFilterResults));
}

@GetMapping(
path = "/filter-scroll",
produces = MediaType.APPLICATION_JSON_VALUE)

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -16,9 +16,7 @@ public static AcademiesByLocationWithScrollResponses from(
return new AcademiesByLocationWithScrollResponses(
academiesByLocationResult.academiesByLocationResults()
.stream()
.map(academiesByLocationFacadeResult ->
AcademyByLocationWithScrollResponse.from(
academiesByLocationFacadeResult))
.map(AcademyByLocationWithScrollResponse::from)
.toList(),
academiesByLocationResult.sido(),
academiesByLocationResult.sigungu(),

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package org.guzzing.studayserver.domain.academy.facade;

import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationFacadeParam;
import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationFacadeResult;
import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationWithScrollFacadeParam;
import org.guzzing.studayserver.domain.academy.facade.dto.AcademiesByLocationWithScrollFacadeResult;
import org.guzzing.studayserver.domain.academy.service.AcademyService;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationWithScrollResults;
import org.guzzing.studayserver.domain.academy.util.GeometryUtil;
import org.guzzing.studayserver.domain.region.service.RegionService;
@@ -23,21 +20,7 @@ public AcademyFacade(RegionService regionService, AcademyService academyService)
this.academyService = academyService;
}

public AcademiesByLocationFacadeResult findByLocation(AcademiesByLocationFacadeParam param) {
AcademiesByLocationResults academiesByLocation = academyService.findAcademiesByLocation(
AcademiesByLocationFacadeParam.to(param));

RegionResult regionContainingPoint = regionService.findRegionContainingPoint(
GeometryUtil.createPoint(
param.lat(),
param.lng()));

return AcademiesByLocationFacadeResult.from(academiesByLocation, regionContainingPoint);
}


public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll(
AcademiesByLocationWithScrollFacadeParam param) {
public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll(AcademiesByLocationWithScrollFacadeParam param) {
AcademiesByLocationWithScrollResults academiesByLocationWithScroll = academyService.findAcademiesByLocationWithScroll(
AcademiesByLocationWithScrollFacadeParam.to(param));

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
package org.guzzing.studayserver.domain.academy.repository.academy;

import java.util.List;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocation;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFiltering;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyFilterCondition;

public interface AcademyQueryRepository {

List<AcademiesByLocation> findAcademiesByLocation(String pointFormat, Long memberId);

List<AcademyByFiltering> filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId);

AcademiesByLocationWithScroll findAcademiesByLocation(
String pointFormat,
Long memberId,
Original file line number Diff line number Diff line change
@@ -2,12 +2,12 @@

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;

import java.util.List;

import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocation;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFiltering;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyFilterCondition;
import org.hibernate.query.NativeQuery;
@@ -16,139 +16,13 @@

public class AcademyQueryRepositoryImpl implements AcademyQueryRepository {

private static final String BLANK_QUERY = "";
private final EntityManager em;

public AcademyQueryRepositoryImpl(EntityManager em) {
this.em = em;
}

public List<AcademiesByLocation> findAcademiesByLocation(String pointFormat, Long memberId) {

String nativeQuery = """
SELECT
a.id AS academyId,
a.academy_name AS academyName,
a.phone_number AS phoneNumber,
a.full_address AS fullAddress,
a.latitude AS latitude ,
a.longitude AS longitude,
a.shuttle AS shuttleAvailable,
(CASE WHEN l.academy_id IS NOT NULL THEN true ELSE false END) AS isLiked,
ac.category_id as categoryId
FROM
academies AS a
LEFT JOIN
academy_categories as ac ON a.id = ac.academy_id
LEFT JOIN
likes AS l ON a.id = l.academy_id AND l.member_id = %s
WHERE
MBRContains(ST_LINESTRINGFROMTEXT(%s), a.point)""";

String formattedQuery = String.format(nativeQuery, memberId, pointFormat);

Query emNativeQuery = em.createNativeQuery(
formattedQuery);

List<AcademiesByLocation> academies = emNativeQuery.unwrap(org.hibernate.query.NativeQuery.class)
.addScalar("academyId", StandardBasicTypes.LONG)
.addScalar("academyName", StandardBasicTypes.STRING)
.addScalar("fullAddress", StandardBasicTypes.STRING)
.addScalar("phoneNumber", StandardBasicTypes.STRING)
.addScalar("latitude", StandardBasicTypes.DOUBLE)
.addScalar("longitude", StandardBasicTypes.DOUBLE)
.addScalar("shuttleAvailable", StandardBasicTypes.STRING)
.addScalar("isLiked", StandardBasicTypes.BOOLEAN)
.addScalar("categoryId", StandardBasicTypes.LONG)
.setResultTransformer(
new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return new AcademiesByLocation(
(Long) tuple[0],
(String) tuple[1],
(String) tuple[2],
(String) tuple[3],
(Double) tuple[4],
(Double) tuple[5],
(String) tuple[6],
(boolean) tuple[7],
(Long) tuple[8]
);
}

@Override
public List transformList(List collection) {
return collection;
}
}
)
.getResultList();

return academies;
}

public List<AcademyByFiltering> filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId) {
String nativeQuery = """
SELECT
a.id AS academyId,
a.academy_name AS academyName,
a.full_address AS fullAddress,
a.phone_number AS phoneNumber,
a.latitude,
a.longitude,
a.shuttle AS shuttleAvailable,
ac.category_id as categoryId,
(CASE WHEN l.academy_id IS NOT NULL THEN true ELSE false END) AS isLiked
FROM
academy_categories as ac
LEFT JOIN
academies AS a ON ac.academy_id = a.id
LEFT JOIN
likes AS l ON a.id = l.academy_id AND l.member_id = %s
WHERE
MBRContains(ST_LINESTRINGFROMTEXT(%s), a.point)""";

String formattedQuery = String.format(nativeQuery, memberId, academyFilterCondition.pointFormat());
formattedQuery = addWhereConditionsWithFilter(formattedQuery, academyFilterCondition);

Query query = em.createNativeQuery(formattedQuery);

return query.unwrap(org.hibernate.query.NativeQuery.class)
.addScalar("academyId", StandardBasicTypes.LONG)
.addScalar("academyName", StandardBasicTypes.STRING)
.addScalar("fullAddress", StandardBasicTypes.STRING)
.addScalar("phoneNumber", StandardBasicTypes.STRING)
.addScalar("categoryId", StandardBasicTypes.LONG)
.addScalar("latitude", StandardBasicTypes.DOUBLE)
.addScalar("longitude", StandardBasicTypes.DOUBLE)
.addScalar("shuttleAvailable", StandardBasicTypes.STRING)
.addScalar("isLiked", StandardBasicTypes.BOOLEAN)
.setResultTransformer(
new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return new AcademyByFiltering(
(Long) tuple[0],
(String) tuple[1],
(String) tuple[2],
(String) tuple[3],
(Long) tuple[4],
(Double) tuple[5],
(Double) tuple[6],
(String) tuple[7],
(boolean) tuple[8]
);
}

@Override
public List transformList(List collection) {
return collection;
}
}
)
.getResultList();
}

public AcademiesByLocationWithScroll findAcademiesByLocation(
String pointFormat,
Long memberId,
@@ -168,12 +42,13 @@ public AcademiesByLocationWithScroll findAcademiesByLocation(
FROM
academies AS a
LEFT JOIN
likes AS l ON a.id = l.academy_id AND l.member_id = %s
WHERE
MBRContains(ST_LINESTRINGFROMTEXT(%s), a.point) """;
likes AS l ON a.id = l.academy_id AND l.member_id = %s """;

String formattedQuery = String.format(nativeQuery, memberId);

String formattedQuery = String.format(nativeQuery, memberId, pointFormat);
formattedQuery += orderBy("a.academy_name");
formattedQuery += builderWhere();

formattedQuery += whereWithinDistance(pointFormat);
formattedQuery = makeScroll(pageNumber, pageSize, formattedQuery);

Query emNativeQuery = em.createNativeQuery(
@@ -201,6 +76,7 @@ public AcademiesByLocationWithScroll findAcademiesByLocation(
))
.getResultList();


return AcademiesByLocationWithScroll.of(
academiesByLocation,
isHasNest(academiesByLocation.size(), pageSize)
@@ -235,8 +111,8 @@ public AcademiesByFilterWithScroll filterAcademies(
nativeQuery,
memberId,
academyFilterCondition.pointFormat());
formattedQuery = addWhereConditionsWithFilter(formattedQuery, academyFilterCondition);
formattedQuery += orderBy("a.academy_name");
formattedQuery = whereFilters(formattedQuery, academyFilterCondition);
formattedQuery += orderByDesc("a.id");
formattedQuery = makeScroll(pageNumber, pageSize, formattedQuery);

Query query = em.createNativeQuery(formattedQuery);
@@ -280,39 +156,54 @@ public List transformList(List collection) {
);
}

private String builderWhere() {
return " where ";

}

private boolean isHasNest(int resultSize, int pageSize) {
return resultSize == pageSize;
}

private String addWhereConditionsWithFilter(String formattedQuery, AcademyFilterCondition academyFilterCondition) {
private String whereFilters(String formattedQuery, AcademyFilterCondition academyFilterCondition) {
formattedQuery += whereInCategories(academyFilterCondition);
formattedQuery += whereBetweenEducationFee(academyFilterCondition);
return formattedQuery;
}

private String whereWithinDistance(String pointFormat) {
return String.format(" MBRContains(ST_LINESTRINGFROMTEXT(%s), a.point) ", pointFormat);
}

private String whereInCategories(AcademyFilterCondition academyFilterCondition) {
if (academyFilterCondition.categories() != null && !academyFilterCondition.categories().isEmpty()) {
return " AND ac.category_id IN " + academyFilterCondition.categories();
}
return "";
return BLANK_QUERY;
}

private String whereBetweenEducationFee(AcademyFilterCondition academyFilterCondition) {
if (academyFilterCondition.desiredMinAmount() != null && academyFilterCondition.desiredMaxAmount() != null) {
return " AND max_education_fee BETWEEN " + academyFilterCondition.desiredMinAmount() + " AND "
+ academyFilterCondition.desiredMaxAmount();
}
return "";
return BLANK_QUERY;
}

private String makeScroll(int pageNumber, int pageSize, String formattedQuery) {
int offset = pageNumber * pageSize;
formattedQuery += " LIMIT " + pageSize + " OFFSET " + offset;
formattedQuery += " LIMIT " + pageSize + " OFFSET " + pageNumber * pageSize;
return formattedQuery;
}

private String orderBy(String columnName) {
return " ORDER BY " + columnName;
private String orderByDesc(String columnName) {
return String.format(" ORDER BY %s %s ", columnName, " DESC ");
}

private Long getBeforeLastId(List<AcademyByLocationWithScroll> academiesByLocation) {
if (academiesByLocation != null && !academiesByLocation.isEmpty()) {
return academiesByLocation.get(academiesByLocation.size() - 1).academyId();
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package org.guzzing.studayserver.domain.academy.repository.academy;

import java.util.List;
import java.util.Optional;
import org.guzzing.studayserver.domain.academy.model.Academy;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocation;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByName;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFiltering;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyFee;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyFilterCondition;
import org.springframework.data.domain.Pageable;
@@ -21,10 +18,6 @@ public interface AcademyRepository {

Slice<AcademiesByName> findAcademiesByName(String academyName, Pageable pageable);

List<AcademiesByLocation> findAcademiesByLocation(String pointFormat, Long memberId);

List<AcademyByFiltering> filterAcademies(AcademyFilterCondition academyFilterCondition, Long memberId);

AcademyFee findAcademyFeeInfo(Long academyId);

boolean existsById(Long academyId);

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -2,35 +2,27 @@

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.guzzing.studayserver.domain.academy.model.Lesson;
import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository;
import org.guzzing.studayserver.domain.academy.repository.academycategory.AcademyCategoryRepository;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocation;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFilterWithScroll;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFiltering;
import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByLocationWithScroll;
import org.guzzing.studayserver.domain.academy.repository.lesson.LessonRepository;
import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationWithScrollParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByNameParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterWithScrollParam;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationWithScrollResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesFilterWithScrollResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyAndLessonDetailResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.LessonInfoToCreateDashboardResults;
import org.guzzing.studayserver.domain.academy.service.parser.FilterParser;
import org.guzzing.studayserver.domain.academy.util.GeometryUtil;
import org.guzzing.studayserver.domain.academy.util.dto.DistinctFilteredAcademy;
import org.guzzing.studayserver.domain.like.service.LikeAccessService;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
@@ -49,8 +41,8 @@ public class AcademyService {
private final AcademyCategoryRepository academyCategoryRepository;

public AcademyService(AcademyRepository academyRepository, LessonRepository lessonRepository,
ReviewCountRepository reviewCountRepository, LikeAccessService likeAccessService,
AcademyCategoryRepository academyCategoryRepository) {
ReviewCountRepository reviewCountRepository, LikeAccessService likeAccessService,
AcademyCategoryRepository academyCategoryRepository) {
this.academyRepository = academyRepository;
this.lessonRepository = lessonRepository;
this.reviewCountRepository = reviewCountRepository;
@@ -69,22 +61,7 @@ public AcademyGetResult getAcademy(Long academyId, Long memberId) {
}

@Transactional(readOnly = true)
public AcademiesByLocationResults findAcademiesByLocation(AcademiesByLocationParam param) {
String diagonal = GeometryUtil.makeDiagonal(param.baseLatitude(), param.baseLongitude(), DISTANCE);

List<AcademiesByLocation> academiesByLocation = academyRepository.findAcademiesByLocation(diagonal,
param.memberId());

Map<Long, List<Long>> academyIdWithCategories = FilterParser.makeCategoriesWithLocation(academiesByLocation);
Set<DistinctFilteredAcademy> distinctFilteredAcademies = FilterParser.distinctAcademiesWithLocation(
academiesByLocation);

return AcademiesByLocationResults.to(academyIdWithCategories, distinctFilteredAcademies);
}

@Transactional(readOnly = true)
public AcademiesByLocationWithScrollResults findAcademiesByLocationWithScroll(
AcademiesByLocationWithScrollParam param) {
public AcademiesByLocationWithScrollResults findAcademiesByLocationWithScroll(AcademiesByLocationWithScrollParam param) {
String diagonal = GeometryUtil.makeDiagonal(param.baseLatitude(), param.baseLongitude(), DISTANCE);

AcademiesByLocationWithScroll academiesByLocation = academyRepository.findAcademiesByLocation(
@@ -125,20 +102,6 @@ public AcademiesByNameResults findAcademiesByName(AcademiesByNameParam param) {
);
}

@Transactional(readOnly = true)
public AcademyFilterResults filterAcademies(AcademyFilterParam param, Long memberId) {
String diagonal = GeometryUtil.makeDiagonal(param.baseLatitude(), param.baseLongitude(), DISTANCE);

List<AcademyByFiltering> academiesByFiltering = academyRepository.filterAcademies(
AcademyFilterParam.to(param, diagonal), memberId);

Map<Long, List<Long>> academyIdWithCategories = FilterParser.makeCategoriesWithFilter(academiesByFiltering);
Set<DistinctFilteredAcademy> distinctFilteredAcademies = FilterParser.distinctAcademiesWithFilter(
academiesByFiltering);

return AcademyFilterResults.from(academyIdWithCategories, distinctFilteredAcademies);
}

@Transactional(readOnly = true)
public AcademiesFilterWithScrollResults filterAcademies(AcademyFilterWithScrollParam param, Long memberId) {
String diagonal = GeometryUtil.makeDiagonal(param.baseLatitude(), param.baseLongitude(), DISTANCE);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -12,7 +12,10 @@ public static AcademiesByLocationWithScrollParam of(
Double baseLongitude,
Long memberId,
int pageNumber) {
return new AcademiesByLocationWithScrollParam(baseLatitude, baseLongitude, memberId, pageNumber);
return new AcademiesByLocationWithScrollParam(
baseLatitude,
baseLongitude,
memberId,
pageNumber);
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -14,16 +14,12 @@
import org.guzzing.studayserver.domain.academy.repository.lesson.LessonRepository;
import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByNameParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterWithScrollParam;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationWithScrollResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesFilterWithScrollResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyAndLessonDetailResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFilterResults;
import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.LessonGetResult;
import org.guzzing.studayserver.domain.academy.service.dto.result.LessonInfoToCreateDashboardResults;
@@ -131,45 +127,6 @@ void getAcademy_academyId_reviewsAndLessons() {
ReviewPercentGetResult.from(savedReviewCountAboutSungnam));
}

@Test
@DisplayName("사용자의 중심 위치가 주어졌을 때 반경 거리 이내의 학원 목록이 조회된다.")
void findAcademiesByLocation_academiesWithinDistance_equalsSize() {
//Given
lessonRepository.deleteAll();
reviewCountRepository.deleteAll();
academyCategoryRepository.deleteAll();
academyRepository.deleteAll();

List<Academy> academies = AcademyFixture.randomAcademiesWithinDistance(LATITUDE, LONGITUDE);
for (Academy academy : academies) {
Academy savedAcademy = academyRepository.save(academy);
lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy));
reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy));

AcademyFixture.academyCategoryAboutSungnam(savedAcademy)
.forEach(
academyCategory -> academyCategoryRepository.save(academyCategory)
);
}
List<String> categoryNames = AcademyFixture.academyCategoryAboutSungnam(savedAcademyAboutSungnam).stream()
.map(academyCategory -> academyCategory.getCategoryId())
.map(categoryId -> CategoryInfo.getCategoryNameById(categoryId))
.toList();

//When
AcademiesByLocationResults academiesByLocations = academyService.findAcademiesByLocation(
AcademyFixture.academiesByLocationParam(LATITUDE, LONGITUDE));

//Then
assertThat(academiesByLocations.academiesByLocationResults().size()).isEqualTo(academies.size());
academiesByLocations.academiesByLocationResults()
.stream()
.map(academiesByLocationResult -> academiesByLocationResult.categories())
.forEach(
categoryName -> assertThat(categoryNames).isEqualTo(categoryName)
);
}

@Test
@DisplayName("사용자의 중심 위치가 주어졌을 때 반경 거리 이내의 학원 목록이 " + LOCATION_PAGE_SIZE + " 이내로 조회된다.")
void findAcademiesByLocation_academiesWithinDistance_equalsPageSize() {
@@ -237,48 +194,6 @@ void findAcademiesByName_academyName_relatedAcademies() {
}
}

@Test
@DisplayName("중심 위치 반경 이내에 있는 학원 중에서 교육비가 최소와 최대 사이에 있고 선택한 학원 분류 분야에 해당하는 학원들을 반환한다.")
void filterAcademy_BetweenEducationFeeAndLocationAndInExpertise() {
//Given
Academy savedAcademyWithTwoCategories = academySetUpForFilterAndDetail().academy;

List<Academy> academies = AcademyFixture.randomAcademiesWithinDistance(LATITUDE, LONGITUDE);
Long minFee = 10000L;
Long maxFee = 1000000L;

for (Academy academy : academies) {
Academy savedAcademy = academyRepository.save(academy);
savedAcademy.changeEducationFee(generateRandomAmount(minFee, maxFee));

AcademyFixture.academyCategoryAboutTwoCategories(savedAcademy)
.forEach(
academyCategory -> academyCategoryRepository.save(academyCategory)
);

lessonRepository.save(AcademyFixture.lessonForSunganm(savedAcademy));
reviewCountRepository.save(AcademyFixture.reviewCountDefault(savedAcademy));
}
AcademyFilterParam academyFilterParam = AcademyFixture.academyFilterParam(LATITUDE, LONGITUDE, minFee, maxFee);

//When
AcademyFilterResults academyFilterResults = academyService.filterAcademies(academyFilterParam,
savedAcademyWithTwoCategories.getId());

//Then
for (AcademyFilterResult academyFilterResult : academyFilterResults.academyFilterResults()) {
Academy filtedAcademy = academyRepository.getById(academyFilterResult.academyId());

assertThat(filtedAcademy.getMaxEducationFee()).
isGreaterThanOrEqualTo(minFee)
.isLessThanOrEqualTo(maxFee);
academyFilterResult.categories()
.forEach(
result -> assertThat(academyFilterParam.categories()).contains(result)
);
}
}

@Test
@DisplayName("중심 위치 반경 이내에 있는 학원 중에서 교육비가 최소와 최대 사이에 있고 선택한 학원 분류 분야에 해당하는 학원들을 반환한다." +
"또한 학원 목록 조회 결과가 " + LOCATION_PAGE_SIZE + " 이내로 조회된다.")
Original file line number Diff line number Diff line change
@@ -11,9 +11,7 @@
import org.guzzing.studayserver.domain.academy.model.vo.Location;
import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.AcademyInfo;
import org.guzzing.studayserver.domain.academy.model.vo.academyinfo.ShuttleAvailability;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademiesByLocationWithScrollParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterParam;
import org.guzzing.studayserver.domain.academy.service.dto.param.AcademyFilterWithScrollParam;
import org.guzzing.studayserver.domain.academy.util.CategoryInfo;
import org.guzzing.studayserver.domain.academy.util.GeometryUtil;
@@ -114,29 +112,8 @@ public static ReviewCount reviewCountDefault(Academy academy) {
return ReviewCount.makeDefaultReviewCount(academy);
}

public static AcademiesByLocationParam academiesByLocationParam(double latitude, double longitude) {
return AcademiesByLocationParam.of(latitude, longitude, 1L);
}

public static AcademiesByLocationWithScrollParam academiesByLocationWithScrollParam(double latitude,
double longitude) {
return AcademiesByLocationWithScrollParam.of(latitude, longitude, 1L, 0);
}

public static AcademyFilterParam academyFilterParam(
Double latitude,
Double longitude,
Long desiredMinAmount,
Long desiredMaxAmount) {
return new AcademyFilterParam(
latitude,
longitude,
List.of(
CategoryInfo.TUTORING_SCHOOL.getCategoryName(),
CategoryInfo.MATH.getCategoryName()),
desiredMinAmount,
desiredMaxAmount
);
public static AcademiesByLocationWithScrollParam academiesByLocationWithScrollParam(double latitude, double longitude) {
return AcademiesByLocationWithScrollParam.of(latitude, longitude, 1L,0 );
}

public static AcademyFilterWithScrollParam academyFilterWithScrollParam(