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] 장소 조회 API를 추가했어요 #166

Merged
merged 13 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -1,8 +1,12 @@
package team7.inplace.likedPlace.persistence;

import java.util.Optional;
import java.util.Set;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import team7.inplace.likedPlace.domain.LikedPlace;

import java.util.Optional;
Expand All @@ -12,4 +16,7 @@ public interface LikedPlaceRepository extends JpaRepository<LikedPlace, Long> {
Optional<LikedPlace> findByUserIdAndPlaceId(Long userId, Long placeId);

Page<LikedPlace> findByUserIdAndIsLikedTrue(Long userId, Pageable pageable);

@Query("SELECT l.place.id FROM LikedPlace l WHERE l.user.id = :userId AND l.isLiked = true")
Set<Long> findPlaceIdsByUserIdAndIsLikedTrue(@Param("userId") Long userId);
}
25 changes: 23 additions & 2 deletions src/main/java/team7/inplace/search/application/SearchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import org.springframework.transaction.annotation.Transactional;
import team7.inplace.favoriteInfluencer.persistent.FavoriteInfluencerRepository;
import team7.inplace.influencer.application.dto.InfluencerInfo;
import team7.inplace.likedPlace.persistence.LikedPlaceRepository;
import team7.inplace.search.application.dto.AutoCompletionInfo;
import team7.inplace.search.application.dto.PlaceSearchInfo;
import team7.inplace.search.application.dto.SearchType;
import team7.inplace.search.persistence.InfluencerSearchRepository;
import team7.inplace.search.persistence.PlaceSearchRepository;
Expand All @@ -28,6 +30,7 @@ public class SearchService {
private final InfluencerSearchRepository influencerSearchRepository;
private final PlaceSearchRepository placeSearchRepository;
private final FavoriteInfluencerRepository favoriteInfluencerRepository;
private final LikedPlaceRepository likedPlaceRepository;

public List<AutoCompletionInfo> searchAutoCompletions(String keyword) {
var influencerSearchInfo = influencerSearchRepository.searchEntityByKeywords(keyword);
Expand All @@ -46,7 +49,6 @@ public List<AutoCompletionInfo> searchAutoCompletions(String keyword) {
.toList();
}

@Transactional(readOnly = true)
public List<VideoInfo> searchVideo(String keyword) {
var videoInfos = videoSearchRepository.searchEntityByKeywords(keyword);

Expand All @@ -57,7 +59,6 @@ public List<VideoInfo> searchVideo(String keyword) {
.toList();
}

@Transactional(readOnly = true)
public List<InfluencerInfo> searchInfluencer(String keyword) {
var influencerInfos = influencerSearchRepository.searchEntityByKeywords(keyword);
Long userId = AuthorizationUtil.getUserId();
Expand All @@ -78,4 +79,24 @@ public List<InfluencerInfo> searchInfluencer(String keyword) {
.sorted((a, b) -> Boolean.compare(b.likes(), a.likes()))
.toList();
}

public List<PlaceSearchInfo> searchPlace(String keyword) {
var placeInfos = placeSearchRepository.searchEntityByKeywords(keyword);
Long userId = AuthorizationUtil.getUserId();

if (userId == null) {
return placeInfos.stream()
.map(placeInfo -> PlaceSearchInfo.from(placeInfo.searchResult(), false))
.toList();
}

var likedPlaceIds = likedPlaceRepository.findPlaceIdsByUserIdAndIsLikedTrue(userId);
return placeInfos.stream()
.map(placeInfo -> {
boolean isLiked = likedPlaceIds.contains(placeInfo.searchResult().getId());
return PlaceSearchInfo.from(placeInfo.searchResult(), isLiked);
})
.sorted((a, b) -> Boolean.compare(b.likes(), a.likes()))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package team7.inplace.search.application.dto;

import team7.inplace.place.domain.Place;

public record PlaceSearchInfo(
Long placeId,
String placeName,
String imageUrl,
Boolean likes
) {
public static PlaceSearchInfo from(Place place, Boolean likes) {
return new PlaceSearchInfo(
place.getId(),
place.getName(),
place.getMenuImgUrl(),
likes
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import team7.inplace.influencer.presentation.dto.InfluencerResponse;
import team7.inplace.search.application.SearchService;
import team7.inplace.search.application.dto.AutoCompletionInfo;
import team7.inplace.search.application.dto.PlaceSearchInfo;
import team7.inplace.video.presentation.dto.VideoResponse;

@RestController
Expand Down Expand Up @@ -48,4 +49,12 @@ public ResponseEntity<List<InfluencerResponse>> searchInfluencer(@RequestParam S
.toList();
return new ResponseEntity<>(response, HttpStatus.OK);
}

@Override
@GetMapping("/place")
public ResponseEntity<List<PlaceSearchInfo>> searchPlace(@RequestParam String value) {
var places = searchService.searchPlace(value);

return new ResponseEntity<>(places, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.http.ResponseEntity;
import team7.inplace.influencer.presentation.dto.InfluencerResponse;
import team7.inplace.search.application.dto.AutoCompletionInfo;
import team7.inplace.search.application.dto.PlaceSearchInfo;
import team7.inplace.video.presentation.dto.VideoResponse;

@Tag(name = "검색 API입니다.")
Expand All @@ -23,4 +24,8 @@ public interface SearchControllerApiSpec {
@Operation(summary = "인플루언서를 검색합니다.")
@ApiResponse(responseCode = "200", description = "인플루언서 검색 성공")
ResponseEntity<List<InfluencerResponse>> searchInfluencer(String value);

@Operation(summary = "장소를 검색합니다.")
@ApiResponse(responseCode = "200", description = "장소 검색 성공")
ResponseEntity<List<PlaceSearchInfo>> searchPlace(String value);
}
10 changes: 7 additions & 3 deletions src/main/resources/sql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ create table influencer
primary key,
job varchar(20) not null,
name varchar(30) not null,
img_url text not null
img_url text not null,

FULLTEXT INDEX ft_name_ngram (name) WITH PARSER ngram
);

create table places
Expand All @@ -20,8 +22,10 @@ create table places
latitude text not null,
longitude text not null,
menu_img_url text null,
category enum ('CAFE', 'JAPANESE', 'KOREAN', 'NONE', 'RESTAURANT', 'WESTERN') not null,
index idx_long_lat (longitude(15), latitude(15))
category enum ('CAFE', 'JAPANESE', 'KOREAN', 'NONE', 'RESTAURANT', 'WESTERN') not null

FULLTEXT INDEX ft_name_ngram (name) WITH PARSER ngram,
INDEX idx_long_lat (longitude(15), latitude(15))
);

create table places_menuboardphotourl_list
Expand Down