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/search place by tag1 #16

Merged
merged 22 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f0b51e7
refactor: 리뷰 조회 응답에 멤버 profile 추가
SonMinGyu Aug 16, 2023
bd92297
feat: 태그로 장소 검색하는 기능 구현
SonMinGyu Aug 16, 2023
d5e61f2
test: 태그들로 장소 조회 인수 테스트 구현
SonMinGyu Aug 16, 2023
abfb4f8
refactor: 장소 응답에 태그 보내도록 리팩토링
SonMinGyu Aug 16, 2023
7f77798
refactor: 장소 조회 응답에 관련된 태그 같이 보내도록 리팩토링
SonMinGyu Aug 16, 2023
921a1e7
refactor: place 관련 review 조회 시 reviewTag join 추가
SonMinGyu Aug 16, 2023
9a7bc2f
refactor: review 조회 시 이미지 응답하도록 리팩토링
SonMinGyu Aug 16, 2023
42fcea7
refactor: 리뷰 작성 시 이미지 필수 조건 수정
SonMinGyu Aug 16, 2023
c3abf66
feat: 장소 등록 시 이미지 존재여부 판단 로직 추가
SonMinGyu Aug 16, 2023
8429465
refactor: 리뷰 응답에 장소 이름 추가
SonMinGyu Aug 16, 2023
b737711
test: ReviewAcceptanceTest 수정
SonMinGyu Aug 16, 2023
f761488
test: test오류 수정
SonMinGyu Aug 16, 2023
56b81b3
test: StudyRecordAcceptanceTest 수정
SonMinGyu Aug 16, 2023
81d0203
feat: StudyRecord 이미지 존재 여부 검증 로직 추가
SonMinGyu Aug 16, 2023
191bb97
test: PlaceAcceptanceTest 수정
SonMinGyu Aug 16, 2023
d1c00a2
test: StudyRecordServiceTest 수정
SonMinGyu Aug 16, 2023
d0c9a62
refactor: studyrecord 응답 시 image 보내주도록 리팩토링
SonMinGyu Aug 16, 2023
c6db02d
refactor: 코드 리뷰 사항 수정
SonMinGyu Aug 17, 2023
e26c46e
refactor: 코드 리뷰 내용 반영
SonMinGyu Aug 21, 2023
04dafa0
refactor: 코드 리뷰 사항 반영
SonMinGyu Aug 22, 2023
5c53d26
chore: jpa hibernate ddl-auto 속성 변경
SonMinGyu Aug 22, 2023
fc7fa46
chore: ddl-auto 수정
SonMinGyu Aug 23, 2023
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 @@ -9,6 +9,8 @@
@UtilityClass
public class CustomListUtils {

private static final int MINIMUM_IMAGE_SIZE = 1;

public static <T, R> List<R> mapTo(final List<T> list, final Function<T, R> mappingFunction) {
if (isEmpty(list)) {
return List.of();
Expand All @@ -35,6 +37,9 @@ public static <T> boolean isEmpty(final List<T> list) {
}

public static <T> String joiningToString(final List<T> list, final String delimiter) {
if (list.size() < MINIMUM_IMAGE_SIZE) {
return "";
}
return list.stream()
.map(Object::toString)
.collect(Collectors.joining(delimiter));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.prography.kagongsillok.image.application.exception;

import java.util.List;
import org.prography.kagongsillok.common.exception.NotFoundException;
import org.prography.kagongsillok.common.utils.CustomListUtils;

public final class NotFoundImageException extends NotFoundException {

public NotFoundImageException(final List<Long> imageIds) {
super(String.format("존재하지 않는 이미지 id가 포함되어 있습니다. imageIds = %s",
CustomListUtils.joiningToString(imageIds, ",")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ public interface ImageRepositoryCustom {

Map<Long, Image> findByIdInToMap(List<Long> imageIds);

boolean isNotExistIdIn(final List<Long> imageIds);

Map<Long, Image> getImageMap(List<Long> imageIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,37 @@ public Map<Long, Image> findByIdInToMap(final List<Long> imageIds) {
.collect(Collectors.toMap(Image::getId, Function.identity()));
}

@Override
public boolean isNotExistIdIn(final List<Long> imageIds) {
List<Long> existImageIds = queryFactory
.selectFrom(image)
.where(
isNotDeleted()
)
.fetch()
.stream()
.map(i -> i.getId())
.collect(Collectors.toList());

return imageIds.stream()
.map(imageId -> existImageIds.contains(imageId))
.collect(Collectors.toList())
.contains(Boolean.FALSE);
}

@Override
public Map<Long, Image> getImageMap(final List<Long> imageIds) {
return queryFactory
.selectFrom(image)
.where(
idIn(imageIds),
isNotDeleted()
)
.fetch()
.stream()
.collect(Collectors.toMap(Image::getId, Function.identity()));
}

private BooleanExpression idIn(final List<Long> ids) {
return image.id.in(ids);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ public Member(final String nickname, final String email, final Role role, String
this.loginHistory = LoginHistory.init();
}

public static Member defaultOf() {
return Member.builder()
.nickname("알 수 없음")
.email("[email protected]")
.build();
}

public String getEmail() {
return email.getValue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.prography.kagongsillok.member.domain.Member;
Expand All @@ -19,17 +20,14 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom {

@Override
public Map<Long, Member> findByIdIn(final List<Long> memberIds) {
final List<Member> members = queryFactory
return queryFactory
.selectFrom(member)
.where(
idIn(memberIds),
isNotDeleted()
)
.fetch();

return members
.stream()
.collect(Collectors.toMap(Member::getId, m -> m));
.collect(Collectors.toMap(Member::getId, Function.identity()));
}

private BooleanExpression idIn(final List<Long> ids) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.prography.kagongsillok.place.application;

import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.prography.kagongsillok.common.utils.CustomListUtils;
import org.prography.kagongsillok.image.application.exception.NotFoundImageException;
import org.prography.kagongsillok.image.domain.Image;
import org.prography.kagongsillok.image.domain.ImageRepository;
import org.prography.kagongsillok.place.application.dto.PlaceCreateCommand;
import org.prography.kagongsillok.place.application.dto.PlaceDto;
import org.prography.kagongsillok.place.application.dto.PlaceLocationAroundSearchCondition;
Expand All @@ -11,6 +14,9 @@
import org.prography.kagongsillok.place.domain.Location;
import org.prography.kagongsillok.place.domain.Place;
import org.prography.kagongsillok.place.domain.PlaceRepository;
import org.prography.kagongsillok.review.domain.Review;
import org.prography.kagongsillok.review.domain.ReviewRepository;
import org.prography.kagongsillok.review.domain.ReviewTag;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -20,12 +26,15 @@
public class PlaceService {

private final PlaceRepository placeRepository;
private final ReviewRepository reviewRepository;
private final ImageRepository imageRepository;

@Transactional
public PlaceDto createPlace(final PlaceCreateCommand placeCreateCommand) {
checkExistImage(placeCreateCommand.getImageIds());
final Place savedPlace = placeRepository.save(placeCreateCommand.toEntity());

return PlaceDto.from(savedPlace);
return PlaceDto.of(savedPlace, getImages(savedPlace));
}

public PlaceDto getPlace(final Long id) {
Expand All @@ -35,7 +44,18 @@ public PlaceDto getPlace(final Long id) {
throw new NotFoundPlaceException(id);
}

return PlaceDto.from(place);
return PlaceDto.of(place, getImages(place));
}

public PlaceDto getPlaceWithTags(final Long placeId) {
final Place place = placeRepository.findById(placeId)
.orElseThrow(() -> new NotFoundPlaceException(placeId));
if (place.getIsDeleted()) {
throw new NotFoundPlaceException(placeId);
}
final List<Review> reviews = reviewRepository.findAllByPlaceId(placeId);

return PlaceDto.of(place, getImages(place), getReviewTagsRelatedToPlace(reviews));
}

public List<PlaceDto> searchPlacesLocationAround(final PlaceLocationAroundSearchCondition searchCondition) {
Expand All @@ -45,24 +65,26 @@ public List<PlaceDto> searchPlacesLocationAround(final PlaceLocationAroundSearch
searchCondition.getLongitudeBound()
);

return CustomListUtils.mapTo(places, PlaceDto::from);
return getPlaceDtos(places);
}

public List<PlaceDto> searchPlacesByName(final String name) {
final List<Place> places = placeRepository.findByNameContains(name);

return CustomListUtils.mapTo(places, PlaceDto::from);
return getPlaceDtos(places);
}

@Transactional
public PlaceDto updatePlace(final Long id, final PlaceUpdateCommand updateCommand) {
final Place place = placeRepository.findById(id)
.orElseThrow(() -> new NotFoundPlaceException(id));

checkExistImage(updateCommand.getImageIds());

final Place target = updateCommand.toEntity();
place.update(target);

return PlaceDto.from(place);
return PlaceDto.of(place, getImages(place));
}

@Transactional
Expand All @@ -72,4 +94,56 @@ public void deletePlace(final Long id) {

place.delete();
}

public List<PlaceDto> searchPlacesByTags(final List<Long> reviewTagIds) {
final List<Review> reviews = reviewRepository.findByReviewTagIds(reviewTagIds);
final List<Long> placeIds = reviews.stream()
.map(review -> review.getPlaceId())
.collect(Collectors.toSet())
.stream()
.toList();

final List<Place> places = placeRepository.findByIdIn(placeIds);

return createPlaceDtos(places, reviews);
}
private List<PlaceDto> getPlaceDtos(final List<Place> places) {
final List<Long> placeIds = places.stream()
.map(place -> place.getId())
.collect(Collectors.toList());
final List<Review> reviews = reviewRepository.findByPlaceIds(placeIds);

return createPlaceDtos(places, reviews);
}

private List<PlaceDto> createPlaceDtos(final List<Place> places, final List<Review> reviews) {
return places.stream()
.map(place -> {
List<Review> relatedReviews = reviews.stream()
.filter(review -> review.getPlaceId().equals(place.getId()))
.collect(Collectors.toList());
return PlaceDto.of(place, getImages(place), getReviewTagsRelatedToPlace(relatedReviews));
})
.collect(Collectors.toList());
}

private List<ReviewTag> getReviewTagsRelatedToPlace(final List<Review> reviews) {
return reviews.stream()
.flatMap(review -> review.getTagMappings()
.getValues()
.stream()
.map(reviewTagMapping -> reviewTagMapping.getReviewTag())
)
.collect(Collectors.toList());
}

private void checkExistImage(final List<Long> imageIds) {
if (imageRepository.isNotExistIdIn(imageIds)) {
throw new NotFoundImageException(imageIds);
}
}

private List<Image> getImages(final Place place) {
return imageRepository.findByIdIn(place.getImageIds());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.prography.kagongsillok.common.utils.CustomListUtils;
import org.prography.kagongsillok.image.application.dto.ImageDto;
import org.prography.kagongsillok.image.domain.Image;
import org.prography.kagongsillok.place.domain.BusinessHour;
import org.prography.kagongsillok.place.domain.Link;
import org.prography.kagongsillok.place.domain.Place;
import org.prography.kagongsillok.review.application.dto.ReviewTagDto;
import org.prography.kagongsillok.review.domain.ReviewTag;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
Expand All @@ -20,10 +24,11 @@ public class PlaceDto {
private String address;
private Double latitude;
private Double longitude;
private List<Long> imageIds;
private List<ImageDto> images;
private String phone;
private List<LinkDto> links;
private List<BusinessHourDto> businessHours;
private List<ReviewTagDto> reviewTags;

@Builder
public PlaceDto(
Expand All @@ -32,20 +37,22 @@ public PlaceDto(
final String address,
final Double latitude,
final Double longitude,
final List<Long> imageIds,
final List<ImageDto> images,
final String phone,
final List<LinkDto> links,
final List<BusinessHourDto> businessHours
final List<BusinessHourDto> businessHours,
final List<ReviewTagDto> reviewTags
) {
this.id = id;
this.name = name;
this.address = address;
this.latitude = latitude;
this.longitude = longitude;
this.imageIds = imageIds;
this.images = images;
this.phone = phone;
this.links = links;
this.businessHours = businessHours;
this.reviewTags = reviewTags;
}

public static PlaceDto from(final Place place) {
Expand All @@ -55,13 +62,41 @@ public static PlaceDto from(final Place place) {
.address(place.getAddress())
.latitude(place.getLatitude())
.longitude(place.getLongitude())
.imageIds(place.getImageIds())
.phone(place.getPhone())
.links(CustomListUtils.mapTo(place.getLinks().getValues(), LinkDto::from))
.businessHours(CustomListUtils.mapTo(place.getBusinessHours().getValues(), BusinessHourDto::from))
.build();
}

public static PlaceDto of(final Place place, final List<Image> images) {
return PlaceDto.builder()
.id(place.getId())
.name(place.getName())
.address(place.getAddress())
.latitude(place.getLatitude())
.longitude(place.getLongitude())
.images(CustomListUtils.mapTo(images, ImageDto::from))
.phone(place.getPhone())
.links(CustomListUtils.mapTo(place.getLinks().getValues(), LinkDto::from))
.businessHours(CustomListUtils.mapTo(place.getBusinessHours().getValues(), BusinessHourDto::from))
.build();
}

public static PlaceDto of(final Place place,final List<Image> images, final List<ReviewTag> reviewTags) {
return PlaceDto.builder()
.id(place.getId())
.name(place.getName())
.address(place.getAddress())
.latitude(place.getLatitude())
.longitude(place.getLongitude())
.images(CustomListUtils.mapTo(images, ImageDto::from))
.phone(place.getPhone())
.links(CustomListUtils.mapTo(place.getLinks().getValues(), LinkDto::from))
.businessHours(CustomListUtils.mapTo(place.getBusinessHours().getValues(), BusinessHourDto::from))
.reviewTags(CustomListUtils.mapTo(reviewTags, ReviewTagDto::from))
.build();
}

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class LinkDto {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.prography.kagongsillok.place.infrastructure;

import java.util.List;
import java.util.Map;
import org.prography.kagongsillok.place.domain.Location;
import org.prography.kagongsillok.place.domain.Place;

Expand All @@ -15,4 +16,6 @@ List<Place> findByLocationAround(
List<Place> findByNameContains(final String name);

List<Place> findByIdIn(final List<Long> placeIds);

Map<Long, Place> findByIdInToMap(final List<Long> placeIds);
}
Loading
Loading