Skip to content
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
Expand Up @@ -3,11 +3,13 @@
import com.semosan.api.domain.hiking.repository.projection.UserHikingMountainRecordProjection;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Stream;

public record GetUserHikingMountainRecordResponse(
Long mountainId,
String mountainName,
String imageUrl,
List<String> imageUrls,
Long hikingCount,
LocalDate lastHikedAt
) {
Expand All @@ -17,9 +19,15 @@ public static GetUserHikingMountainRecordResponse from(UserHikingMountainRecordP
return new GetUserHikingMountainRecordResponse(
projection.getMountainId(),
projection.getMountainName(),
projection.getImageUrl(),
buildImageUrls(projection.getImageUrl1(), projection.getImageUrl2()),
projection.getHikingCount(),
projection.getLastHikedAt().toLocalDate()
);
}

private static List<String> buildImageUrls(String imageUrl1, String imageUrl2) {
return Stream.of(imageUrl1, imageUrl2)
.filter(imageUrl -> imageUrl != null && !imageUrl.isBlank())
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,59 @@ AND NOT EXISTS (
@Query(
value = """
SELECT
hr.mountain_id AS mountainId,
m.name AS mountainName,
m.image_urls->>0 AS imageUrl,
COUNT(hr.id) AS hikingCount,
MAX(hr.created_at) AS lastHikedAt
FROM hiking_records hr
JOIN hiking_members hm ON hm.hiking_record_id = hr.id
JOIN mountains m ON m.id = hr.mountain_id
WHERE hm.user_id = :userId
GROUP BY hr.mountain_id, m.name, m.image_urls->>0
ORDER BY MAX(hr.created_at) DESC, hr.mountain_id DESC
grouped.mountain_id AS mountainId,
grouped.mountain_name AS mountainName,
photos.image_url1 AS imageUrl1,
photos.image_url2 AS imageUrl2,
grouped.hiking_count AS hikingCount,
grouped.last_hiked_at AS lastHikedAt
FROM (
SELECT
hr.mountain_id,
m.name AS mountain_name,
m.location AS mountain_location,
COUNT(hr.id) AS hiking_count,
MAX(hr.created_at) AS last_hiked_at
FROM hiking_records hr
JOIN hiking_members hm ON hm.hiking_record_id = hr.id
JOIN mountains m ON m.id = hr.mountain_id
WHERE hm.user_id = :userId
GROUP BY hr.mountain_id, m.name, m.location
) grouped
LEFT JOIN LATERAL (
SELECT
MAX(CASE WHEN ranked.rn = 1 THEN ranked.image_url END) AS image_url1,
MAX(CASE WHEN ranked.rn = 2 THEN ranked.image_url END) AS image_url2
FROM (
SELECT
tp.image_url,
ROW_NUMBER() OVER (
ORDER BY
ST_Distance(
grouped.mountain_location,
ST_SetSRID(ST_MakePoint(tp.lng, tp.lat), 4326)::geography
) ASC,
Comment thread
pooreumjung marked this conversation as resolved.
tp.captured_at DESC,
tp.id DESC
) AS rn
FROM tracking_photos tp
JOIN tracking_sessions ts ON ts.id = tp.tracking_session_id
WHERE ts.user_id = :userId
AND ts.mountain_id = grouped.mountain_id
AND ts.status = 'COMPLETED'
AND grouped.mountain_location IS NOT NULL
AND NULLIF(tp.image_url, '') IS NOT NULL
ORDER BY
ST_Distance(
grouped.mountain_location,
ST_SetSRID(ST_MakePoint(tp.lng, tp.lat), 4326)::geography
) ASC,
tp.captured_at DESC,
tp.id DESC
LIMIT 2
) ranked
) photos ON true
ORDER BY grouped.last_hiked_at DESC, grouped.mountain_id DESC
""",
countQuery = """
SELECT COUNT(DISTINCT hr.mountain_id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ public interface UserHikingMountainRecordProjection {

String getMountainName();

String getImageUrl();
String getImageUrl1();

String getImageUrl2();

Long getHikingCount();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.semosan.api.domain.hiking.dto.response;

import com.semosan.api.domain.hiking.repository.projection.UserHikingMountainRecordProjection;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;

import static org.assertj.core.api.Assertions.assertThat;

class GetUserHikingMountainRecordResponseTest {

@Test
void fromMapsImageUrlsInOrder() {
GetUserHikingMountainRecordResponse response = GetUserHikingMountainRecordResponse.from(
projection("near-summit-1", "near-summit-2")
);

assertThat(response.imageUrls()).containsExactly("near-summit-1", "near-summit-2");
assertThat(response.lastHikedAt()).isEqualTo(LocalDate.of(2026, 5, 28));
}

@Test
void fromFiltersBlankImageUrls() {
GetUserHikingMountainRecordResponse response = GetUserHikingMountainRecordResponse.from(
projection("", "near-summit-2")
);

assertThat(response.imageUrls()).containsExactly("near-summit-2");
}

@Test
void fromReturnsEmptyImageUrlsWhenNoPhotos() {
GetUserHikingMountainRecordResponse response = GetUserHikingMountainRecordResponse.from(
projection(null, null)
);

assertThat(response.imageUrls()).isEmpty();
}

private UserHikingMountainRecordProjection projection(String imageUrl1, String imageUrl2) {
return new UserHikingMountainRecordProjection() {
@Override
public Long getMountainId() {
return 1L;
}

@Override
public String getMountainName() {
return "관악산";
}

@Override
public String getImageUrl1() {
return imageUrl1;
}

@Override
public String getImageUrl2() {
return imageUrl2;
}

@Override
public Long getHikingCount() {
return 3L;
}

@Override
public LocalDateTime getLastHikedAt() {
return LocalDateTime.of(2026, 5, 28, 10, 0);
}
};
}
}