diff --git a/src/main/java/com/knu/ddip/ddipevent/domain/DdipEvent.java b/src/main/java/com/knu/ddip/ddipevent/domain/DdipEvent.java index b0e74d7..8f5cd40 100644 --- a/src/main/java/com/knu/ddip/ddipevent/domain/DdipEvent.java +++ b/src/main/java/com/knu/ddip/ddipevent/domain/DdipEvent.java @@ -17,6 +17,7 @@ public class DdipEvent { private final UUID requesterId; private final Double latitude; private final Double longitude; + private final String cellId; private final Instant createdAt; private String title; private String content; diff --git a/src/main/java/com/knu/ddip/ddipevent/infrastructure/DdipMapper.java b/src/main/java/com/knu/ddip/ddipevent/infrastructure/DdipMapper.java index 399e087..a440958 100644 --- a/src/main/java/com/knu/ddip/ddipevent/infrastructure/DdipMapper.java +++ b/src/main/java/com/knu/ddip/ddipevent/infrastructure/DdipMapper.java @@ -6,17 +6,23 @@ import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; import com.knu.ddip.ddipevent.infrastructure.entity.InteractionEntity; import com.knu.ddip.ddipevent.infrastructure.entity.PhotoEntity; +import com.knu.ddip.location.application.util.S2Converter; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.util.List; @Component +@RequiredArgsConstructor public class DdipMapper { + private final S2Converter s2Converter; + public DdipEventEntity toEntity(DdipEvent domain) { DdipEventEntity entity = buildDdipEventEntity(domain); entity.setPhotos(mapPhotos(domain.getPhotos(), entity)); entity.setInteractions(mapInteractions(domain.getInteractions(), entity)); + entity.setCellId(s2Converter.toCellIdString(domain.getLatitude(),domain.getLongitude())); return entity; } @@ -81,6 +87,7 @@ public DdipEvent toDomain(DdipEventEntity entity) { .reward(entity.getReward()) .latitude(entity.getLatitude()) .longitude(entity.getLongitude()) + .cellId(entity.getCellId()) .createdAt(entity.getCreatedAt()) .status(entity.getStatus()) .selectedResponderId(entity.getSelectedResponderId()) diff --git a/src/main/java/com/knu/ddip/ddipevent/infrastructure/entity/DdipEventEntity.java b/src/main/java/com/knu/ddip/ddipevent/infrastructure/entity/DdipEventEntity.java index eaba132..b47e5d8 100644 --- a/src/main/java/com/knu/ddip/ddipevent/infrastructure/entity/DdipEventEntity.java +++ b/src/main/java/com/knu/ddip/ddipevent/infrastructure/entity/DdipEventEntity.java @@ -44,6 +44,10 @@ public class DdipEventEntity { @Column(nullable = false) private Double longitude; + @Column(nullable = false) + @Setter + private String cellId; + @Column(nullable = false) private Instant createdAt; diff --git a/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepository.java b/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepository.java index 4d97567..2a2e751 100644 --- a/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepository.java +++ b/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepository.java @@ -3,7 +3,9 @@ import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.UUID; public interface DdipEventJpaRepository extends JpaRepository { + List findAllByCellIdIn(List cellIds); } diff --git a/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImpl.java b/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImpl.java index 6191998..f4ad711 100644 --- a/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImpl.java +++ b/src/main/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImpl.java @@ -2,26 +2,31 @@ import com.knu.ddip.ddipevent.application.service.DdipEventRepository; import com.knu.ddip.ddipevent.domain.DdipEvent; +import com.knu.ddip.ddipevent.domain.DdipStatus; import com.knu.ddip.ddipevent.infrastructure.DdipMapper; import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; +import com.knu.ddip.location.application.service.LocationService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.UUID; +@Transactional(readOnly = true) @Repository @RequiredArgsConstructor public class DdipEventRepositoryImpl implements DdipEventRepository { private final DdipEventJpaRepository ddipEventJpaRepository; private final DdipMapper ddipMapper; -// private final JPAQueryFactory queryFactory; -// private final RedisTemplate redisTemplate; -// private static final int S2_LEVEL = 15; + private final LocationService locationService; + + @Transactional @Override public DdipEvent save(DdipEvent ddipEvent) { DdipEventEntity entity = ddipMapper.toEntity(ddipEvent); @@ -36,59 +41,21 @@ public Optional findById(UUID id) { @Override public List findWithinBounds(double swLat, double swLon, double neLat, double neLon, String sort, Double userLat, Double userLon) { - // TODO: 실제 S2를 이용한 로직 구현 필요. 현재는 전체 다 반환 - return ddipEventJpaRepository.findAll() - .stream().map(ddipMapper::toDomain).toList(); + List cellIds = locationService.getNeighborCellIdsToRetrieveNearDdipRequest(swLat, swLon, neLat, neLon); + + List ddipEventEntities = ddipEventJpaRepository.findAllByCellIdIn(cellIds); + + Comparator comparator = (o1, o2) -> { + double dist1 = Math.pow(userLat - o1.getLatitude(), 2) + Math.pow(userLon - o1.getLongitude(), 2); + double dist2 = Math.pow(userLat - o2.getLatitude(), 2) + Math.pow(userLon - o2.getLongitude(), 2); + return dist1 - dist2 >= 0 ? 1 : -1; + }; + + // 유저와 이벤트 거리 비교해서 거리 가까운 순 정렬 + return ddipEventEntities.stream() + .filter(event -> event.getStatus().equals(DdipStatus.OPEN)) + .sorted(comparator) + .map(ddipMapper::toDomain) + .toList(); } -// S2LatLng sw = S2LatLng.fromDegrees(swLat, swLon); -// S2LatLng ne = S2LatLng.fromDegrees(neLat, neLon); -// S2RegionCoverer coverer = new S2RegionCoverer(); -// coverer.setMinLevel(S2_LEVEL); -// coverer.setMaxLevel(S2_LEVEL); -// List cellIds = coverer.getCovering(new com.google.common.geometry.S2LatLngRect(sw, ne)).cellIds(); -// -// List keys = cellIds.stream() -// .map(cellId -> "s2:" + cellId.toToken()) -// .toList(); -// -// List eventIds = keys.stream() -// .flatMap(key -> redisTemplate.opsForSet().members(key).stream()) -// .distinct() -// .toList(); -// -// if (eventIds.isEmpty()) { -// return List.of(); -// } -// -// List events = queryFactory -// .selectFrom(ddipEventEntity) -// .where(ddipEventEntity.id.in(eventIds.stream().map(UUID::fromString).collect(Collectors.toList())) -// .and(ddipEventEntity.latitude.between(swLat, neLat)) -// .and(ddipEventEntity.longitude.between(swLon, neLon))) -// .fetch() -// .stream() -// .map(ddipMapper::toDomain) -// .collect(Collectors.toList()); -// -// if ("distance".equals(sort) && userLat != null && userLon != null) { -// events.sort((e1, e2) -> { -// double dist1 = distance(userLat, userLon, e1.getLatitude(), e1.getLongitude()); -// double dist2 = distance(userLat, userLon, e2.getLatitude(), e2.getLongitude()); -// return Double.compare(dist1, dist2); -// }); -// } else { -// events.sort((e1, e2) -> e2.getCreatedAt().compareTo(e1.getCreatedAt())); -// } -// -// return events; -// } -// -// private double distance(double lat1, double lon1, double lat2, double lon2) { -// double theta = lon1 - lon2; -// double dist = Math.sin(Math.toRadians(lat1)) * Math.sin(Math.toRadians(lat2)) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.cos(Math.toRadians(theta)); -// dist = Math.acos(dist); -// dist = Math.toDegrees(dist); -// dist = dist * 60 * 1.1515 * 1609.344; -// return dist; -// } } diff --git a/src/main/java/com/knu/ddip/location/application/service/LocationService.java b/src/main/java/com/knu/ddip/location/application/service/LocationService.java index 0e8978a..83cfe7c 100644 --- a/src/main/java/com/knu/ddip/location/application/service/LocationService.java +++ b/src/main/java/com/knu/ddip/location/application/service/LocationService.java @@ -2,8 +2,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.geometry.S2CellId; +import com.google.common.geometry.*; import com.knu.ddip.location.application.dto.UpdateMyLocationRequest; +import com.knu.ddip.location.application.util.S2Constants; import com.knu.ddip.location.application.util.S2Converter; import com.knu.ddip.location.application.util.UuidBase64Utils; import lombok.RequiredArgsConstructor; @@ -21,6 +22,8 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static com.knu.ddip.location.application.util.S2Constants.*; + @Slf4j @Service @Transactional(readOnly = true) @@ -30,9 +33,10 @@ public class LocationService { private final LocationReader locationReader; private final LocationWriter locationWriter; + private final S2Converter s2Converter; + private final ObjectMapper objectMapper; - public static final int LEVEL = 17; public static final String KNU_GEOJSON_FEATURE_FILENAME = "geojson/cells.geojson"; // KNU GeoJSON 파일을 읽어서 각 Feature를 DB에 저장 @@ -62,7 +66,7 @@ public void loadAndSaveGeoJsonFeatures() { } public void saveUserLocationAtomic(UUID userId, UpdateMyLocationRequest request) { - S2CellId cellIdObj = S2Converter.toCellId(request.lat(), request.lng(), LEVEL); + S2CellId cellIdObj = s2Converter.toCellId(request.lat(), request.lng()); String cellId = cellIdObj.toToken(); // 경북대 내부에 위치하는지 확인 @@ -75,7 +79,7 @@ public void saveUserLocationAtomic(UUID userId, UpdateMyLocationRequest request) // 요청 전송 시 이웃 userIds 조회 public List getNeighborRecipientUserIds(UUID myUserId, double lat, double lng) { - S2CellId cellIdObj = S2Converter.toCellId(lat, lng, LEVEL); + S2CellId cellIdObj = s2Converter.toCellId(lat, lng); String cellId = cellIdObj.toToken(); // 경북대 내부에 위치하는지 확인 @@ -102,9 +106,9 @@ public List getNeighborRecipientUserIds(UUID myUserId, double lat, double return userIds; } - // 초기 화면에서 인접한 요청 가져오기 (현재는 인접한 cellId 가져오는 것만 구현) - public List getNeighborCellIds(double lat, double lng) { - S2CellId cellIdObj = S2Converter.toCellId(lat, lng, LEVEL); + // 띱 요청 보낼 대상 인접 셀 조회 + public List getNeighborCellIdsToSendDdipRequest(double lat, double lng) { + S2CellId cellIdObj = s2Converter.toCellId(lat, lng); String cellId = cellIdObj.toToken(); // 경북대 내부에 위치하는지 확인 @@ -124,6 +128,27 @@ public List getNeighborCellIds(double lat, double lng) { return targetCellIds; } + // 근처 띱 요청 조회용 셀 조회 + public List getNeighborCellIdsToRetrieveNearDdipRequest(double minLat, double minLng, double maxLat, double maxLng) { + S2LatLngRect rect = S2LatLngRect.fromPointPair( + S2LatLng.fromDegrees(minLat, minLng), + S2LatLng.fromDegrees(maxLat, maxLng) + ); + + S2RegionCoverer coverer = S2RegionCoverer.builder() + .setMinLevel(LEVEL) + .setMaxLevel(LEVEL) + .build(); + + S2CellUnion union = new S2CellUnion(); + coverer.getCovering(rect, union); + + List cellIds = normalizeCellLevel(union, LEVEL); + + List filteredCellIds = locationReader.findAllLocationsByCellIdIn(cellIds); + return filteredCellIds; + } + private String getGeoJsonContent() { ClassPathResource resource = new ClassPathResource(KNU_GEOJSON_FEATURE_FILENAME); try (InputStream is = resource.getInputStream()) { @@ -132,4 +157,22 @@ private String getGeoJsonContent() { throw new RuntimeException(e); } } + + private List normalizeCellLevel(S2CellUnion union, int level) { + List out = new ArrayList<>(); + for (S2CellId cid : union.cellIds()) { + if (cid.level() == level) { + out.add(cid.toToken()); + } else if (cid.level() < level) { + S2CellId begin = cid.childBegin(level); + S2CellId end = cid.childEnd(level); + for (S2CellId it = begin; !it.equals(end); it = it.next()) { + out.add(it.toToken()); + } + } else { + out.add(cid.parent(level).toToken()); + } + } + return out; + } } diff --git a/src/main/java/com/knu/ddip/location/application/util/S2Constants.java b/src/main/java/com/knu/ddip/location/application/util/S2Constants.java new file mode 100644 index 0000000..a023987 --- /dev/null +++ b/src/main/java/com/knu/ddip/location/application/util/S2Constants.java @@ -0,0 +1,5 @@ +package com.knu.ddip.location.application.util; + +public abstract class S2Constants { + public static int LEVEL = 17; +} diff --git a/src/main/java/com/knu/ddip/location/application/util/S2Converter.java b/src/main/java/com/knu/ddip/location/application/util/S2Converter.java index 893f0c0..58b9b46 100644 --- a/src/main/java/com/knu/ddip/location/application/util/S2Converter.java +++ b/src/main/java/com/knu/ddip/location/application/util/S2Converter.java @@ -2,11 +2,19 @@ import com.google.common.geometry.S2CellId; import com.google.common.geometry.S2LatLng; +import org.springframework.stereotype.Component; -public abstract class S2Converter { +import static com.knu.ddip.location.application.util.S2Constants.LEVEL; - public static S2CellId toCellId(double lat, double lng, int level) { +@Component +public class S2Converter { + public S2CellId toCellId(double lat, double lng) { S2LatLng latLng = S2LatLng.fromDegrees(lat, lng); - return S2CellId.fromLatLng(latLng).parent(level); + return S2CellId.fromLatLng(latLng).parent(LEVEL); + } + + public String toCellIdString(double lat, double lng) { + S2CellId cellId = toCellId(lat, lng); + return cellId.toToken(); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index dba2bd1..d379d61 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -13,9 +13,9 @@ spring.data.redis.port=${REDIS_PORT} spring.data.redis.password=${REDIS_PASSWORD} # JPA -spring.jpa.properties.hibernate.format_sql=true -spring.jpa.show-sql=true -spring.jpa.hibernate.ddl-auto=create +#spring.jpa.properties.hibernate.format_sql=true +#spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update spring.sql.init.mode=always spring.jpa.defer-datasource-initialization=true spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver diff --git a/src/test/java/com/knu/ddip/ddipevent/fixture/DdipEventFixture.java b/src/test/java/com/knu/ddip/ddipevent/fixture/DdipEventFixture.java new file mode 100644 index 0000000..13581e5 --- /dev/null +++ b/src/test/java/com/knu/ddip/ddipevent/fixture/DdipEventFixture.java @@ -0,0 +1,31 @@ +package com.knu.ddip.ddipevent.fixture; + +import com.knu.ddip.ddipevent.domain.DdipStatus; +import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; + +import java.time.Instant; +import java.util.UUID; + +public abstract class DdipEventFixture { + + public static DdipEventEntity createDdipEvent() { + DdipEventEntity event = createDdipEvent(0.0, 0.0, DdipStatus.OPEN, "content", "cellId"); + return event; + } + + public static DdipEventEntity createDdipEvent(Double lat, Double lon, DdipStatus status, String content, String cellId) { + DdipEventEntity event = DdipEventEntity.builder() + .content(content) + .createdAt(Instant.now()) + .difficulty(1) + .latitude(lat) + .longitude(lon) + .requesterId(UUID.randomUUID()) + .reward(1) + .status(status) + .title("title") + .cellId(cellId) + .build(); + return event; + } +} diff --git a/src/test/java/com/knu/ddip/ddipevent/infrastructure/DdipMapperTest.java b/src/test/java/com/knu/ddip/ddipevent/infrastructure/DdipMapperTest.java index fe07a41..2c31d27 100644 --- a/src/test/java/com/knu/ddip/ddipevent/infrastructure/DdipMapperTest.java +++ b/src/test/java/com/knu/ddip/ddipevent/infrastructure/DdipMapperTest.java @@ -6,6 +6,7 @@ import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; import com.knu.ddip.ddipevent.infrastructure.entity.InteractionEntity; import com.knu.ddip.ddipevent.infrastructure.entity.PhotoEntity; +import com.knu.ddip.location.application.util.S2Converter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,7 +22,8 @@ class DdipMapperTest { @BeforeEach void setUp() { - ddipMapper = new DdipMapper(); + S2Converter s2Converter = new S2Converter(); + ddipMapper = new DdipMapper(s2Converter); } @DisplayName("도메인을 엔티티로 변환 - 모든 필드 포함") @@ -34,6 +36,8 @@ void givenDdipEventDomainWithLists_whenToEntity_thenDdipEventEntityIsReturned() .id(UUID.randomUUID()) .photos(List.of(photo)) .interactions(List.of(interaction)) + .latitude(0.0) + .longitude(0.0) .build(); // when @@ -55,6 +59,8 @@ void givenDdipEventDomainWithNullLists_whenToEntity_thenDdipEventEntityIsReturne .id(UUID.randomUUID()) .photos(null) .interactions(null) + .latitude(0.0) + .longitude(0.0) .build(); // when diff --git a/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepositoryTest.java b/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepositoryTest.java new file mode 100644 index 0000000..d2deeba --- /dev/null +++ b/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventJpaRepositoryTest.java @@ -0,0 +1,55 @@ +package com.knu.ddip.ddipevent.infrastructure.repository; + +import com.knu.ddip.config.IntegrationTestConfig; +import com.knu.ddip.config.MySQLTestContainerConfig; +import com.knu.ddip.config.RedisTestContainerConfig; +import com.knu.ddip.config.TestEnvironmentConfig; +import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; +import com.knu.ddip.user.infrastructure.repository.UserRepositoryImpl; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static com.knu.ddip.ddipevent.fixture.DdipEventFixture.createDdipEvent; +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@ExtendWith({RedisTestContainerConfig.class, MySQLTestContainerConfig.class, TestEnvironmentConfig.class}) +@Import({IntegrationTestConfig.class, UserRepositoryImpl.class}) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class DdipEventJpaRepositoryTest { + + @Autowired + DdipEventJpaRepository ddipEventJpaRepository; + + @Test + void findAllByCellIdInTest() { + // given + int targetEventsNumber = 3; + + List targetCellIds = List.of("TargetCellId0", "TargetCellId1", "TargetCellId2"); + String notTargetCellId = "NotTargetCellId"; + + for (int i = 0; i < targetEventsNumber; i++) { + DdipEventEntity event = createDdipEvent(); + event.setCellId(targetCellIds.get(i)); + ddipEventJpaRepository.save(event); + } + + DdipEventEntity notTargetEvent = createDdipEvent(); + notTargetEvent.setCellId(notTargetCellId); + ddipEventJpaRepository.save(notTargetEvent); + + // when + List events = ddipEventJpaRepository.findAllByCellIdIn(targetCellIds); + + // then + assertThat(events).hasSize(targetEventsNumber); + } + +} \ No newline at end of file diff --git a/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImplIntegrationTest.java b/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImplIntegrationTest.java new file mode 100644 index 0000000..2fa2705 --- /dev/null +++ b/src/test/java/com/knu/ddip/ddipevent/infrastructure/repository/DdipEventRepositoryImplIntegrationTest.java @@ -0,0 +1,78 @@ +package com.knu.ddip.ddipevent.infrastructure.repository; + +import com.knu.ddip.config.IntegrationTestConfig; +import com.knu.ddip.config.MySQLTestContainerConfig; +import com.knu.ddip.config.RedisTestContainerConfig; +import com.knu.ddip.config.TestEnvironmentConfig; +import com.knu.ddip.ddipevent.domain.DdipEvent; +import com.knu.ddip.ddipevent.domain.DdipStatus; +import com.knu.ddip.ddipevent.fixture.DdipEventFixture; +import com.knu.ddip.ddipevent.infrastructure.entity.DdipEventEntity; +import com.knu.ddip.location.application.util.S2Converter; +import com.knu.ddip.user.infrastructure.repository.UserRepositoryImpl; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@Transactional +@ExtendWith({RedisTestContainerConfig.class, MySQLTestContainerConfig.class, TestEnvironmentConfig.class}) +@Import({IntegrationTestConfig.class, UserRepositoryImpl.class}) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class DdipEventRepositoryImplIntegrationTest { + + @Autowired + DdipEventJpaRepository ddipEventJpaRepository; + @Autowired + DdipEventRepositoryImpl ddipEventRepositoryImpl; + @Autowired + S2Converter s2Converter; + + @Test + void findWithinBoundsTest() { + // given + List ddipEvents = List.of( + DdipEventFixture.createDdipEvent(35.8880523, 128.6058911, DdipStatus.OPEN, "대운동장", s2Converter.toCellIdString(35.8880523, 128.6058911)), // 대운동장 + DdipEventFixture.createDdipEvent(35.8868876, 128.6082622, DdipStatus.OPEN, "공대9호관", s2Converter.toCellIdString(35.8868876, 128.6082622)), // 공대9호관 + DdipEventFixture.createDdipEvent(35.8880089, 128.6114594, DdipStatus.OPEN, "융복합관", s2Converter.toCellIdString(35.8880089, 128.6114594)) // 융복합관 + ); + ddipEventJpaRepository.saveAll(ddipEvents); + + // when + List sortDdipEvents = ddipEventRepositoryImpl.findWithinBounds(35.8853838, 128.6058911, 35.8955185, 128.6140665, "sort", 35.8886499, 128.6121487);// 일청담 + + // then + assertThat(sortDdipEvents).hasSize(3) + .extracting(DdipEvent::getContent) + .containsExactly("융복합관", "공대9호관", "대운동장"); // 거리 가까운 순 정렬 + } + + @Test + void findWithinBoundsWithOnlyOpenEventsTest() { + // given + List ddipEvents = List.of( + DdipEventFixture.createDdipEvent(35.8880523, 128.6058911, DdipStatus.OPEN, "대운동장", s2Converter.toCellIdString(35.8880523, 128.6058911)), // 대운동장 + DdipEventFixture.createDdipEvent(35.8868876, 128.6082622, DdipStatus.COMPLETED, "공대9호관", s2Converter.toCellIdString(35.8868876, 128.6082622)), // 공대9호관 + DdipEventFixture.createDdipEvent(35.8880089, 128.6114594, DdipStatus.COMPLETED, "융복합관", s2Converter.toCellIdString(35.8880089, 128.6114594)) // 융복합관 + ); + ddipEventJpaRepository.saveAll(ddipEvents); + + // when + List sortDdipEvents = ddipEventRepositoryImpl.findWithinBounds(35.8853838, 128.6058911, 35.8955185, 128.6140665, "sort", 35.8886499, 128.6121487); // 일청담 + + // then + assertThat(sortDdipEvents).hasSize(1) + .extracting(DdipEvent::getContent) + .containsExactly("대운동장"); + } + +} \ No newline at end of file diff --git a/src/test/java/com/knu/ddip/location/application/service/LocationServiceTest.java b/src/test/java/com/knu/ddip/location/application/service/LocationServiceTest.java index 3b4b5ed..1fbb4c1 100644 --- a/src/test/java/com/knu/ddip/location/application/service/LocationServiceTest.java +++ b/src/test/java/com/knu/ddip/location/application/service/LocationServiceTest.java @@ -25,6 +25,7 @@ import java.util.concurrent.*; import static com.knu.ddip.location.application.util.LocationKeyFactory.*; +import static com.knu.ddip.location.application.util.S2Constants.LEVEL; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,10 +34,11 @@ @Import(IntegrationTestConfig.class) class LocationServiceTest { - public static final int LEVEL = 17; @Autowired LocationService locationService; @Autowired + S2Converter s2Converter; + @Autowired RedisTemplate redisTemplate; @Autowired LocationJpaRepository locationJpaRepository; @@ -55,7 +57,7 @@ void saveUserLocationTest() { double lat = 35.8889737; double lng = 128.6099251; - String cellId = S2Converter.toCellId(lat, lng, LEVEL).toToken(); + String cellId = s2Converter.toCellIdString(lat, lng); UpdateMyLocationRequest request = UpdateMyLocationRequest.of(lat, lng); @@ -85,7 +87,7 @@ void saveUserLocationRemovesOldLocationAndSavesNewOne() { double lat = 35.8889737; double lng = 128.6099251; - String cellId = S2Converter.toCellId(lat, lng, LEVEL).toToken(); + String cellId = s2Converter.toCellIdString(lat, lng); UpdateMyLocationRequest request = UpdateMyLocationRequest.of(lat, lng); @@ -119,7 +121,7 @@ void saveUserLocationWithSameOldLocation() { double lat = 35.8889737; double lng = 128.6099251; - String cellId = S2Converter.toCellId(lat, lng, LEVEL).toToken(); + String cellId = s2Converter.toCellIdString(lat, lng); UpdateMyLocationRequest request = UpdateMyLocationRequest.of(lat, lng); @@ -180,38 +182,38 @@ void getNeighborRecipientUserIdsTest() { } @Test - void getNeighborCellIdsNotInTargetAreaTest() { + void getNeighborCellIdsToSendDdipRequestNotInTargetAreaTest() { // given double outsideTargetAreaLat = 1.0; double outsideTargetAreaLng = 1.0; // when // then - assertThatThrownBy(() -> locationService.getNeighborCellIds(outsideTargetAreaLat, outsideTargetAreaLng)) + assertThatThrownBy(() -> locationService.getNeighborCellIdsToSendDdipRequest(outsideTargetAreaLat, outsideTargetAreaLng)) .isInstanceOf(LocationNotFoundException.class) .hasMessage("위치를 찾을 수 없습니다."); } @Test - void getNeighborCellIdsTest() { + void getNeighborCellIdsToSendDdipRequestTest() { // given double lat = 35.8890084; double lng = 128.6107405; // when - List neighborCellIds = locationService.getNeighborCellIds(lat, lng); + List neighborCellIds = locationService.getNeighborCellIdsToSendDdipRequest(lat, lng); // then assertThat(neighborCellIds).hasSize(9); } @Test - void getNeighborCellIdsAtEdgeTest() { + void getNeighborCellIdsToSendDdipRequestAtEdgeTest() { // given double lat = 35.8928546; double lng = 128.608922; // when - List neighborCellIds = locationService.getNeighborCellIds(lat, lng); + List neighborCellIds = locationService.getNeighborCellIdsToSendDdipRequest(lat, lng); // then assertThat(neighborCellIds).hasSize(6); @@ -228,7 +230,7 @@ void saveUserIdByCellIdTest() { double requestLat = 35.8886597; double requestLng = 128.612138; - String cellId = S2Converter.toCellId(requestLat, requestLng, LEVEL).toToken(); + String cellId = s2Converter.toCellIdString(requestLat, requestLng); String cellIdUsersKey = createCellIdUsersKey(cellId); String cellIdExpiriesKey = createCellIdExpiriesKey(cellId); @@ -254,7 +256,7 @@ void saveUserIdByCellIdAtOutsideOfTargetAreaTest() { double requestLat = 35.8942626; double requestLng = 128.6066904; - String cellId = S2Converter.toCellId(requestLat, requestLng, LEVEL).toToken(); + String cellId = s2Converter.toCellIdString(requestLat, requestLng); String cellIdUsersKey = createCellIdUsersKey(cellId); String cellIdExpiriesKey = createCellIdExpiriesKey(cellId); @@ -334,4 +336,35 @@ void saveUserLocationAtomicConcurrencyTest() throws InterruptedException { assertThat(redisTemplate.opsForZSet().score(cellIdExpiriesKey, encodedUserId)).isNotNull(); } + @Test + void getNeighborCellIdsToRetrieveNearDdipRequestTest() { + // given + double minLat = 35.8878766; + double minLng = 128.6089617; + double maxLat = 35.8895281; + double maxLng = 128.6112577; + + // when + List neighborCellIds = locationService.getNeighborCellIdsToRetrieveNearDdipRequest(minLat, minLng, maxLat, maxLng); + + // then + assertThat(neighborCellIds).hasSize(21); + } + + @Test + void getNeighborCellIdsToRetrieveNearDdipRequestAtEdgeTest() { + // given + double minLat = 35.8897193; + double minLng = 128.6044985; + double maxLat = 35.8936654; + double maxLng = 128.6110217; + + // when + List neighborCellIds = locationService.getNeighborCellIdsToRetrieveNearDdipRequest(minLat, minLng, maxLat, maxLng); + + // then + assertThat(neighborCellIds.size()).isNotEqualTo(82); + assertThat(neighborCellIds).hasSize(56); + } + } \ No newline at end of file