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

refactor: 약속 단건 조회 API 구현 #256

Merged
merged 14 commits into from
Aug 6, 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
8 changes: 8 additions & 0 deletions backend/src/main/java/com/ody/mate/service/MateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.ody.meeting.domain.Meeting;
import com.ody.member.domain.Member;
import com.ody.notification.service.NotificationService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -32,4 +33,11 @@ public MateSaveResponse saveAndSendNotifications(MateSaveRequest mateSaveRequest
notificationService.saveAndSendNotifications(meeting, mate, member.getDeviceToken());
return MateSaveResponse.from(mate);
}

public List<Mate> findAllByMemberAndMeetingId(Member member, long meetingId) {
if (!mateRepository.existsByMeetingIdAndMemberId(meetingId, member.getId())) {
throw new OdyBadRequestException("존재하지 않는 모임이거나 약속 참여자가 아닙니다.");
}
return mateRepository.findAllByMeetingId(meetingId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[질문] 해당 메서드가 dto인 MeetingWithMatesResponse를 반환하게 하지 않고 List<Mate>를 반환하게 한 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두 가지 이유가 있었어요.

  1. 약속 1건 조회의 책임이 Mate보다는 Meeting에 있다고 생각했어요.
    물론, Mate는 Meeting을 알고 있어서 Mate에서 Response를 반환할 수도 있겠지만,
    MeetingServiceMateService를 호출만 하게 되는 구조가 어색한 것 같아요.

  2. MateService에서 바로 반환하면, MateRepository의 재사용성이 매우 낮다고 생각했어요.
    MateService에서 Response를 반환하게 되면, 사실상 MeetingService는 불필요해요.
    MateService에서 모든 로직을 처리하고, MateRepository 한방쿼리로 해결할 수 있을 거예요. 당장은 Mate 인원수가 최대 8명이고, 성능이 중요한 케이스는 아니라고 생각해요. Repository 재사용성 측면을 더 고려했습니다!

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,16 @@ ResponseEntity<MeetingSaveResponse> save(
responseCode = "200",
description = "약속 단건 조회 성공",
content = @Content(schema = @Schema(implementation = MeetingWithMatesResponse.class))
),
@ApiResponse(
responseCode = "404",
description = "존재하지 않는 약속이거나 해당 약속 참여자가 아닌 경우",
content = @Content(schema = @Schema(implementation = ProblemDetail.class))
)
}
)
@ErrorCode401
@ErrorCode404(description = "존재하지 않는 약속이거나 해당 약속 참여자가 아닌 경우")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

@ErrorCode500
ResponseEntity<MeetingWithMatesResponse> findMeetingWithMates(@Parameter(hidden = true) Member member, Long meetingId);
ResponseEntity<MeetingWithMatesResponse> findMeetingWithMates(
@Parameter(hidden = true) Member member,
Long meetingId
);

@Operation(
summary = "참여중인 약속 목록 조회",
Expand Down
21 changes: 3 additions & 18 deletions backend/src/main/java/com/ody/meeting/service/MeetingService.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package com.ody.meeting.service;

import static com.google.common.graph.ElementOrder.sorted;

import com.ody.common.exception.OdyNotFoundException;
import com.ody.mate.domain.EtaStatus;
import com.ody.mate.domain.Mate;
import com.ody.mate.dto.request.MateEtaRequest;
import com.ody.mate.dto.request.MateSaveRequest;
import com.ody.mate.dto.response.MateEtaResponse;
import com.ody.mate.dto.response.MateEtaResponses;
import com.ody.mate.dto.response.MateResponse;
import com.ody.mate.dto.response.MateSaveResponse;
import com.ody.mate.repository.MateRepository;
import com.ody.mate.service.MateService;
Expand All @@ -22,8 +19,6 @@
import com.ody.meeting.repository.MeetingRepository;
import com.ody.member.domain.Member;
import com.ody.util.InviteCodeGenerator;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -40,7 +35,6 @@ public class MeetingService {

private final MeetingRepository meetingRepository;
private final MateRepository mateRepository;

private final MateService mateService;

@Transactional
Expand Down Expand Up @@ -96,18 +90,9 @@ public MateEtaResponses findAllMateEtas(Long meetingId, MateEtaRequest mateEtaRe
}

public MeetingWithMatesResponse findMeetingWithMates(Member member, Long meetingId) {
return new MeetingWithMatesResponse(
1L,
"우테코 16조",
LocalDate.parse("2024-07-15"),
LocalTime.parse("14:00"),
"서울 송파구 올림픽로35다길 42",
"37.515298",
"127.103113",
2,
List.of(new MateResponse("오디"), new MateResponse("제리")),
"초대코드"
);
Meeting meeting = findById(meetingId);
List<Mate> mates = mateService.findAllByMemberAndMeetingId(member, meetingId);
return MeetingWithMatesResponse.of(meeting, mates);
}

public MateSaveResponse saveMateAndSendNotifications(MateSaveRequest mateSaveRequest, Member member) {
Expand Down
38 changes: 38 additions & 0 deletions backend/src/test/java/com/ody/mate/service/MateServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ody.mate.service;

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

Expand All @@ -14,11 +15,13 @@
import com.ody.meeting.domain.Meeting;
import com.ody.meeting.dto.request.MeetingSaveRequestV1;
import com.ody.meeting.dto.response.MeetingSaveResponseV1;
import com.ody.meeting.repository.MeetingRepository;
import com.ody.meeting.service.MeetingService;
import com.ody.member.domain.Member;
import com.ody.member.repository.MemberRepository;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -37,6 +40,9 @@ class MateServiceTest extends BaseServiceTest {
@Autowired
private MateService mateService;

@Autowired
private MeetingRepository meetingRepository;

@DisplayName("모임 내 닉네임이 중복되지 않으면 모임에 참여한다.")
@Test
void saveMate() {
Expand Down Expand Up @@ -132,4 +138,36 @@ void saveMateWithDuplicateNickname() {
assertThatThrownBy(() -> mateService.saveAndSendNotifications(mateSaveRequest, member2, meeting))
.isInstanceOf(OdyBadRequestException.class);
}

@DisplayName("회원이 참여하고 있는 특정 약속의 참여자 리스트를 조회한다.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외 상황까지 꼼꼼한 테스트 👍🏻

@Test
void findAllByMemberAndMeetingIdSuccess() {
Member member1 = memberRepository.save(Fixture.MEMBER1);
Member member2 = memberRepository.save(Fixture.MEMBER2);

Meeting meeting = meetingRepository.save(Fixture.ODY_MEETING1);

Mate mate1 = mateRepository.save(new Mate(meeting, member1, new Nickname("조조"), Fixture.ORIGIN_LOCATION));
Mate mate2 = mateRepository.save(new Mate(meeting, member2, new Nickname("제리"), Fixture.ORIGIN_LOCATION));

List<Mate> mates = mateService.findAllByMemberAndMeetingId(member1, meeting.getId());
List<Long> mateIds = mates.stream()
.map(Mate::getId)
.toList();

assertThat(mateIds).containsOnly(mate1.getId(), mate2.getId());
}

@DisplayName("약속에 참여하고 있는 회원이 아니면 예외가 발생한다.")
@Test
void findAllByMemberAndMeetingIdException() {
Member member1 = memberRepository.save(Fixture.MEMBER1);
Member member2 = memberRepository.save(Fixture.MEMBER2);

Meeting meeting = meetingRepository.save(Fixture.ODY_MEETING1);
mateRepository.save(new Mate(meeting, member1, new Nickname("조조"), Fixture.ORIGIN_LOCATION));

assertThatThrownBy(() -> mateService.findAllByMemberAndMeetingId(member2, meeting.getId()))
.isInstanceOf(OdyBadRequestException.class);
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
package com.ody.meeting.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;

import com.ody.common.BaseServiceTest;
import com.ody.common.Fixture;
import com.ody.common.exception.OdyNotFoundException;
import com.ody.mate.domain.Mate;
import com.ody.mate.domain.Nickname;
import com.ody.mate.dto.response.MateResponse;
import com.ody.mate.repository.MateRepository;
import com.ody.meeting.domain.Meeting;
import com.ody.meeting.dto.request.MeetingSaveRequestV1;
import com.ody.meeting.dto.response.MeetingFindByMemberResponse;
import com.ody.meeting.dto.response.MeetingSaveResponseV1;
import com.ody.meeting.dto.response.MeetingWithMatesResponse;
import com.ody.meeting.repository.MeetingRepository;
import com.ody.member.domain.DeviceToken;
import com.ody.member.domain.Member;
import com.ody.member.repository.MemberRepository;
import java.util.List;
import com.ody.meeting.dto.request.MeetingSaveRequestV1;
import com.ody.meeting.dto.response.MeetingSaveResponseV1;
import com.ody.util.InviteCodeGenerator;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

class MeetingServiceTest extends BaseServiceTest {

@Autowired
private MeetingService meetingService;

@Autowired
private MemberRepository memberRepository;

Expand All @@ -33,19 +40,18 @@ class MeetingServiceTest extends BaseServiceTest {
@Autowired
private MateRepository mateRepository;

@Autowired
private MeetingService meetingService;

@DisplayName("내 약속 목록 조회 시 오름차순 정렬한다.")
@Test
void findAllByMember() {
Member member = memberRepository.save(new Member(new DeviceToken("Bearer device-token=new-member-device-token")));
Member member = memberRepository.save(
new Member(new DeviceToken("Bearer device-token=new-member-device-token")));

Meeting meetingDayAfterTomorrowAt14 = meetingRepository.save(Fixture.ODY_MEETING4);
Meeting meetingTomorrowAt12 = meetingRepository.save(Fixture.ODY_MEETING3);
Meeting meetingTomorrowAt14 = meetingRepository.save(Fixture.ODY_MEETING5);

mateRepository.save(new Mate(meetingDayAfterTomorrowAt14, member, new Nickname("제리1"), Fixture.ORIGIN_LOCATION));
mateRepository.save(
new Mate(meetingDayAfterTomorrowAt14, member, new Nickname("제리1"), Fixture.ORIGIN_LOCATION));
mateRepository.save(new Mate(meetingTomorrowAt12, member, new Nickname("제리2"), Fixture.ORIGIN_LOCATION));
mateRepository.save(new Mate(meetingTomorrowAt14, member, new Nickname("제리3"), Fixture.ORIGIN_LOCATION));

Expand Down Expand Up @@ -87,4 +93,38 @@ void saveV1Success() {
() -> assertThat(InviteCodeGenerator.decode(response.inviteCode())).isEqualTo(response.id())
);
}

@DisplayName("약속과 참여자들 정보를 조회한다.")
@Test
void findMeetingWithMatesSuccess() {
Member member1 = memberRepository.save(Fixture.MEMBER1);
Member member2 = memberRepository.save(Fixture.MEMBER2);

Meeting meeting = meetingRepository.save(Fixture.ODY_MEETING1);

Mate mate1 = new Mate(meeting, member1, new Nickname("조조"), Fixture.ORIGIN_LOCATION);
Mate mate2 = new Mate(meeting, member2, new Nickname("제리"), Fixture.ORIGIN_LOCATION);

mateRepository.save(mate1);
mateRepository.save(mate2);

MeetingWithMatesResponse response = meetingService.findMeetingWithMates(member1, meeting.getId());
List<String> mateNicknames = response.mates().stream()
.map(MateResponse::nickname)
.toList();

assertAll(
() -> assertThat(response.id()).isEqualTo(meeting.getId()),
() -> assertThat(mateNicknames).containsOnly(mate1.getNicknameValue(), mate2.getNicknameValue())
);
}

@DisplayName("약속 조회 시, 약속이 존재하지 않으면 예외가 발생한다.")
@Test
void findMeetingWithMatesException() {
Member member = memberRepository.save(Fixture.MEMBER1);

assertThatThrownBy(() -> meetingService.findMeetingWithMates(member, 1L))
.isInstanceOf(OdyNotFoundException.class);
}
}
Loading