Skip to content

Commit

Permalink
refactor: 행사 참여자 전체 수정 로직 리펙토링
Browse files Browse the repository at this point in the history
  • Loading branch information
Arachneee committed Sep 26, 2024
1 parent 6cc464a commit 78678cb
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 88 deletions.
108 changes: 20 additions & 88 deletions server/src/main/java/server/haengdong/application/MemberService.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package server.haengdong.application;


import static java.util.stream.Collectors.toMap;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import server.haengdong.application.request.MemberSaveAppRequest;
import server.haengdong.application.request.MemberUpdateAppRequest;
import server.haengdong.application.request.MembersSaveAppRequest;
import server.haengdong.application.request.MembersUpdateAppRequest;
import server.haengdong.application.response.MemberAppResponse;
Expand All @@ -22,6 +17,7 @@
import server.haengdong.domain.bill.BillRepository;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;
import server.haengdong.domain.member.Members;
import server.haengdong.domain.member.Member;
import server.haengdong.domain.member.MemberRepository;
import server.haengdong.exception.HaengdongErrorCode;
Expand Down Expand Up @@ -54,6 +50,16 @@ public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest re
return MembersSaveAppResponse.of(savedMembers);
}

private void validateMemberSave(List<String> memberNames, Event event) {
if (memberNames.size() != Set.copyOf(memberNames).size()) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames);
}
if (memberRepository.findAllByEvent(event).stream()
.anyMatch(member -> memberNames.contains(member.getName()))) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST);
}
}

public List<MemberAppResponse> getCurrentMembers(String token) {
Event event = getEvent(token);

Expand All @@ -65,16 +71,6 @@ public List<MemberAppResponse> getCurrentMembers(String token) {
.toList();
}

private void validateMemberSave(List<String> memberNames, Event event) {
if (memberNamesDuplicated(memberNames)) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, memberNames);
}
if (memberRepository.findAllByEvent(event).stream()
.anyMatch(member -> memberNames.contains(member.getName()))) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST);
}
}

public MembersDepositAppResponse findAllMembers(String token) {
Event event = getEvent(token);

Expand All @@ -86,80 +82,11 @@ public MembersDepositAppResponse findAllMembers(String token) {
@Transactional
public void updateMembers(String token, MembersUpdateAppRequest request) {
Event event = getEvent(token);
validateMemberUpdate(request);

List<Member> updatedMembers = request.members().stream()
.map(memberRequest -> memberRequest.toMember(event))
.toList();
List<Member> eventMembers = memberRepository.findAllByEvent(event);

validateUpdatedMembersExist(eventMembers, updatedMembers);
validateUpdatedNamesUnique(eventMembers, updatedMembers);
memberRepository.saveAll(updatedMembers);
}

private Event getEvent(String token) {
return eventRepository.findByToken(token)
.orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND));
}
Members requestMembers = new Members(request.toMembers(event));
Members members = new Members(memberRepository.findAllByEvent(event));

private void validateMemberUpdate(MembersUpdateAppRequest request) {
validateChangedNameUnique(request.members());
validateMemberUnique(request.members());
}

private void validateChangedNameUnique(List<MemberUpdateAppRequest> members) {
List<String> memberNames = members.stream()
.map(MemberUpdateAppRequest::name)
.toList();
if (memberNamesDuplicated(memberNames)) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE);
}
}

private boolean memberNamesDuplicated(List<String> memberNames) {
return memberNames.size() != Set.copyOf(memberNames).size();
}

private void validateMemberUnique(List<MemberUpdateAppRequest> members) {
List<Long> memberIds = members.stream()
.map(MemberUpdateAppRequest::id)
.distinct()
.toList();
if (members.size() != memberIds.size()) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE);
}
}

private void validateUpdatedMembersExist(List<Member> eventMembers, List<Member> updatedMembers) {
if (updatedMembers.size() != eventMembers.size()) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH);
}
Set<Member> members = new HashSet<>(eventMembers);

if (!members.containsAll(updatedMembers)) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH);
}
}

private void validateUpdatedNamesUnique(List<Member> eventMembers, List<Member> updatedMembers) {
Map<Long, String> eventMemberNames = eventMembers.stream()
.collect(toMap(Member::getId, Member::getName));
Set<String> existNames = new HashSet<>(eventMemberNames.values());

boolean memberNameDuplicated = updatedMembers.stream()
.filter(updatedMember -> isMemberNameUpdated(eventMemberNames, updatedMember))
.map(Member::getName)
.anyMatch(existNames::contains);

if (memberNameDuplicated) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE);
}
}

private boolean isMemberNameUpdated(Map<Long, String> eventMemberNames, Member updatedMember) {
String prevMemberName = eventMemberNames.get(updatedMember.getId());
return !updatedMember.hasName(prevMemberName);
members.validateUpdateAble(requestMembers);
memberRepository.saveAll(requestMembers.getMembers());
}

@Transactional
Expand All @@ -180,4 +107,9 @@ private void deleteMember(String token, Member member) {
billDetailRepository.deleteAllByMember(member);
memberRepository.delete(member);
}

private Event getEvent(String token) {
return eventRepository.findByToken(token)
.orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package server.haengdong.application.request;

import java.util.List;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.member.Member;

public record MembersUpdateAppRequest(List<MemberUpdateAppRequest> members) {

public List<Member> toMembers(Event event) {
return members.stream()
.map(memberRequest -> memberRequest.toMember(event))
.toList();
}
}
65 changes: 65 additions & 0 deletions server/src/main/java/server/haengdong/domain/member/Members.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package server.haengdong.domain.member;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import server.haengdong.exception.HaengdongErrorCode;
import server.haengdong.exception.HaengdongException;

public class Members {

private final Set<Member> members;

public Members(List<Member> members) {
validateNameUnique(members);
validateMemberUnique(members);
this.members = new HashSet<>(members);
}

private void validateNameUnique(List<Member> members) {
List<String> memberNames = members.stream()
.map(Member::getName)
.toList();
if (memberNames.size() != Set.copyOf(memberNames).size()) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE);
}
}

private void validateMemberUnique(List<Member> members) {
if (members.size() != Set.copyOf(members).size()) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE);
}
}

public void validateUpdateAble(Members requestMembers) {
validateUpdatedMembersExist(requestMembers);
validateUpdatedNamesUnique(requestMembers);
}

private void validateUpdatedMembersExist(Members requestMembers) {
if (!this.members.equals(requestMembers.members)) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH);
}
}

private void validateUpdatedNamesUnique(Members requestMembers) {
boolean duplicated = requestMembers.members.stream()
.anyMatch(this::isMemberNameUpdated);

if (duplicated) {
throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE);
}
}

private boolean isMemberNameUpdated(Member updatedMember) {
return this.members.stream()
.filter(member -> !member.getId().equals(updatedMember.getId()))
.anyMatch(member -> member.hasName(updatedMember.getName()));
}

public List<Member> getMembers() {
return members.stream().toList();
}
}


118 changes: 118 additions & 0 deletions server/src/test/java/server/haengdong/domain/member/MembersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package server.haengdong.domain.member;

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

import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import server.haengdong.domain.event.Event;
import server.haengdong.exception.HaengdongException;

class MembersTest {

@DisplayName("이벤트 이름들은 중복될 수 없다.")
@Test
void validateNameUnique() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
List<Member> members = List.of(
new Member(1L, event, "고구마", false),
new Member(2L, event, "감자", false),
new Member(3L, event, "감자", false)
);

assertThatThrownBy(() -> new Members(members))
.isInstanceOf(HaengdongException.class)
.hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다.");
}

@DisplayName("이벤트 회원들은 중복될 수 없다.")
@Test
void validateMemberUnique() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
Member member1 = new Member(1L, event, "고구마", false);
Member member2 = new Member(2L, event, "감자", false);
List<Member> members = List.of(member1, member2, member2);


assertThatThrownBy(() -> new Members(members))
.isInstanceOf(HaengdongException.class)
.hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다.");
}

@DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.")
@Test
void create() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
Member member1 = new Member(1L, event, "고구마", false);
Member member2 = new Member(2L, event, "감자", false);
Member member3 = new Member(3L, event, "당근", false);
List<Member> members = List.of(member1, member2, member3);

Members eventMembers = new Members(members);
assertThat(eventMembers.getMembers()).hasSize(3)
.containsExactlyInAnyOrder(member1, member2, member3);
}

@DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.")
@Test
void validateUpdatedMembersExist() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
Member member1 = new Member(1L, event, "고구마", false);
Member member2 = new Member(2L, event, "감자", false);
Member member3 = new Member(3L, event, "당근", false);
Member member4 = new Member(4L, event, "양파", false);
Members members = new Members(List.of(member1, member2, member3, member4));

Member updateMember1 = new Member(1L, event, "토다리", false);
Member updateMember2 = new Member(2L, event, "쿠키", false);
Member updateMember3 = new Member(3L, event, "백호", false);
Members updatedMembers = new Members(List.of(updateMember1, updateMember2, updateMember3));

assertThatThrownBy(() -> members.validateUpdateAble(updatedMembers))
.isInstanceOf(HaengdongException.class)
.hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다.");
}

@DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.")
@Test
void validateUpdatedNamesUnique() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
Member member1 = new Member(1L, event, "고구마", false);
Member member2 = new Member(2L, event, "감자", false);
Member member3 = new Member(3L, event, "당근", false);
Member member4 = new Member(4L, event, "양파", false);
Members members = new Members(List.of(member1, member2, member3, member4));

Member updateMember1 = new Member(1L, event, "토다리", false);
Member updateMember2 = new Member(2L, event, "쿠키", false);
Member updateMember3 = new Member(3L, event, "백호", false);
Member updateMember4 = new Member(4L, event, "감자", false);
Members updatedMembers = new Members(List.of(updateMember1, updateMember2, updateMember3, updateMember4));

assertThatThrownBy(() -> members.validateUpdateAble(updatedMembers))
.isInstanceOf(HaengdongException.class)
.hasMessage("중복된 행사 참여 인원 이름이 존재합니다.");
}

@DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.")
@Test
void validateUpdateAble() {
Event event = new Event("행동대장 회식", "1234", "1231415jaksdf");
Member member1 = new Member(1L, event, "고구마", false);
Member member2 = new Member(2L, event, "감자", false);
Member member3 = new Member(3L, event, "당근", false);
Member member4 = new Member(4L, event, "양파", false);
Members members = new Members(List.of(member1, member2, member3, member4));

Member updateMember1 = new Member(1L, event, "토다리", false);
Member updateMember2 = new Member(2L, event, "쿠키", false);
Member updateMember3 = new Member(3L, event, "백호", false);
Member updateMember4 = new Member(4L, event, "망쵸", false);
Members updatedMembers = new Members(List.of(updateMember1, updateMember2, updateMember3, updateMember4));

assertThatCode(() -> members.validateUpdateAble(updatedMembers))
.doesNotThrowAnyException();
}
}

0 comments on commit 78678cb

Please sign in to comment.