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: MomentImage update 시 수동 삭제 적용 #591 #593

Merged
merged 8 commits into from
Feb 5, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public interface CommentRepository extends JpaRepository<Comment, Long> {

@Modifying
@Query("DELETE FROM Comment c WHERE c.moment.id IN :momentIds")
void deleteAllByMomentIdInBatch(@Param("momentIds") List<Long> momentIds);
void deleteAllByMomentIdInBulk(@Param("momentIds") List<Long> momentIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ public interface MemoryMemberRepository extends JpaRepository<MemoryMember, Long

@Modifying
@Query("DELETE FROM MemoryMember mm WHERE mm.memory.id = :memoryId")
void deleteAllByMemoryIdInBatch(@Param("memoryId") Long memoryId);
void deleteAllByMemoryIdInBulk(@Param("memoryId") Long memoryId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ private void deleteAllRelatedMemory(long memoryId) {
.stream()
.map(Moment::getId)
.toList();
momentImageRepository.deleteAllByMomentIdInBatch(momentIds);
commentRepository.deleteAllByMomentIdInBatch(momentIds);
momentRepository.deleteAllByMemoryIdInBatch(memoryId);
memoryMemberRepository.deleteAllByMemoryIdInBatch(memoryId);
momentImageRepository.deleteAllByMomentIdInBulk(momentIds);
commentRepository.deleteAllByMomentIdInBulk(momentIds);
momentRepository.deleteAllByMemoryIdInBulk(memoryId);
memoryMemberRepository.deleteAllByMemoryIdInBulk(memoryId);
}
}
17 changes: 6 additions & 11 deletions backend/src/main/java/com/staccato/moment/domain/Moment.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,12 @@ private void validateIsWithinMemoryDuration(LocalDateTime visitedAt, Memory memo
}
}

public void update(String title, MomentImages newMomentImages) {
this.title = title;
this.momentImages.update(newMomentImages, this);
}

public void update(Moment updatedMoment) {
this.visitedAt = updatedMoment.getVisitedAt();
this.title = updatedMoment.getTitle();
this.spot = updatedMoment.getSpot();
this.momentImages.update(updatedMoment.momentImages, this);
this.memory = updatedMoment.getMemory();
public void update(Moment newMoment) {
this.visitedAt = newMoment.getVisitedAt();
this.title = newMoment.getTitle();
this.spot = newMoment.getSpot();
this.momentImages.update(newMoment.momentImages, this);
this.memory = newMoment.getMemory();
}

public String getThumbnailUrl() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -36,4 +35,8 @@ public MomentImage(@Nonnull String imageUrl) {
protected void belongTo(Moment moment) {
this.moment = moment;
}

protected boolean isSame(MomentImage momentImage) {
return imageUrl.equals(momentImage.imageUrl);
}
}
36 changes: 28 additions & 8 deletions backend/src/main/java/com/staccato/moment/domain/MomentImages.java
Copy link
Contributor

Choose a reason for hiding this comment

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

놓친 테스트가 없는지 한 번 확인 부탁드립니다! (필요없다고 판단하시면 추가하지 않으셔도 됩니다!)

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MomentImages {
private static final int MAX_COUNT = 5;
@OneToMany(mappedBy = "moment", cascade = CascadeType.ALL, orphanRemoval = true)
@OneToMany(mappedBy = "moment", cascade = CascadeType.PERSIST)
private List<MomentImage> images = new ArrayList<>();

public MomentImages(List<String> addedImages) {
Expand All @@ -38,16 +38,36 @@ protected void addAll(MomentImages newMomentImages, Moment moment) {
});
}

protected void update(MomentImages momentImages, Moment moment) {
removeExistsImages(new ArrayList<>(images));
addAll(momentImages, moment);
public boolean isNotEmpty() {
return !images.isEmpty();
}

private void removeExistsImages(List<MomentImage> originalImages) {
originalImages.forEach(this.images::remove);
public List<MomentImage> findImagesNotPresentIn(MomentImages targetMomentImages) {
return images.stream()
.filter(image -> !targetMomentImages.contains(image))
.toList();
}

public boolean isNotEmpty() {
return !images.isEmpty();
protected void update(MomentImages newMomentImages, Moment moment) {
removeExistImages(newMomentImages);
saveNewImages(newMomentImages, moment);
}

private void removeExistImages(MomentImages newMomentImages) {
List<MomentImage> momentImages = findImagesNotPresentIn(newMomentImages);
images.removeAll(momentImages);
}

private void saveNewImages(MomentImages newMomentImages, Moment moment) {
List<MomentImage> momentImages = newMomentImages.findImagesNotPresentIn(this);
momentImages.forEach(image -> {
this.images.add(image);
image.belongTo(moment);
});
}

private boolean contains(MomentImage momentImage) {
return this.images.stream()
.anyMatch(image -> image.isSame(momentImage));
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.staccato.moment.repository;

import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.staccato.moment.domain.MomentImage;

public interface MomentImageRepository extends JpaRepository<MomentImage, Long> {
Optional<MomentImage> findFirstByMomentId(long momentId);

@Modifying
@Query("DELETE FROM MomentImage mi WHERE mi.moment.id In :momentIds")
void deleteAllByMomentIdInBatch(@Param("momentIds") List<Long> momentIds);
void deleteAllByMomentIdInBulk(@Param("momentIds") List<Long> momentIds);

@Modifying
@Query("DELETE FROM MomentImage mi WHERE mi.id In :ids")
void deleteAllByIdInBulk(@Param("ids") List<Long> ids);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ public interface MomentRepository extends JpaRepository<Moment, Long> {

@Modifying
@Query("DELETE FROM Moment m WHERE m.memory.id = :memoryId")
void deleteAllByMemoryIdInBatch(@Param("memoryId") Long memoryId);
void deleteAllByMemoryIdInBulk(@Param("memoryId") Long memoryId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import com.staccato.memory.repository.MemoryRepository;
import com.staccato.moment.domain.Feeling;
import com.staccato.moment.domain.Moment;
import com.staccato.moment.domain.MomentImage;
import com.staccato.moment.domain.MomentImages;
import com.staccato.moment.repository.MomentImageRepository;
import com.staccato.moment.repository.MomentRepository;
import com.staccato.moment.service.dto.request.FeelingRequest;
Expand Down Expand Up @@ -43,11 +45,6 @@ public MomentIdResponse createMoment(MomentRequest momentRequest, Member member)
return new MomentIdResponse(moment.getId());
}

private Memory getMemoryById(long memoryId) {
return memoryRepository.findById(memoryId)
.orElseThrow(() -> new StaccatoException("요청하신 추억을 찾을 수 없어요."));
}

public MomentLocationResponses readAllMoment(Member member) {
return new MomentLocationResponses(momentRepository.findAllByMemory_MemoryMembers_Member(member)
.stream()
Expand All @@ -72,21 +69,32 @@ public void updateMomentById(
Memory targetMemory = getMemoryById(momentRequest.memoryId());
validateMemoryOwner(targetMemory, member);

Moment updatedMoment = momentRequest.toMoment(targetMemory);
moment.update(updatedMoment);
Moment newMoment = momentRequest.toMoment(targetMemory);
MomentImages originMomentImages = moment.getMomentImages();
List<MomentImage> images = originMomentImages.findImagesNotPresentIn(newMoment.getMomentImages());
removeImages(images);

moment.update(newMoment);
}

private Moment getMomentById(long momentId) {
return momentRepository.findById(momentId)
.orElseThrow(() -> new StaccatoException("요청하신 스타카토를 찾을 수 없어요."));
private void removeImages(List<MomentImage> images) {
List<Long> ids = images.stream()
.map(MomentImage::getId)
.toList();
momentImageRepository.deleteAllByIdInBulk(ids);
}

private Memory getMemoryById(long memoryId) {
return memoryRepository.findById(memoryId)
.orElseThrow(() -> new StaccatoException("요청하신 추억을 찾을 수 없어요."));
}

@Transactional
public void deleteMomentById(long momentId, Member member) {
momentRepository.findById(momentId).ifPresent(moment -> {
validateMemoryOwner(moment.getMemory(), member);
commentRepository.deleteAllByMomentIdInBatch(List.of(momentId));
momentImageRepository.deleteAllByMomentIdInBatch(List.of(momentId));
commentRepository.deleteAllByMomentIdInBulk(List.of(momentId));
momentImageRepository.deleteAllByMomentIdInBulk(List.of(momentId));
momentRepository.deleteById(momentId);
});
}
Expand All @@ -99,6 +107,11 @@ public void updateMomentFeelingById(long momentId, Member member, FeelingRequest
moment.changeFeeling(feeling);
}

private Moment getMomentById(long momentId) {
return momentRepository.findById(momentId)
.orElseThrow(() -> new StaccatoException("요청하신 스타카토를 찾을 수 없어요."));
}

private void validateMemoryOwner(Memory memory, Member member) {
if (memory.isNotOwnedBy(member)) {
throw new ForbiddenException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CommentRepositoryTest extends RepositoryTest {

@DisplayName("특정 스타카토의 id를 여러개를 가지고 있는 모든 댓글들을 삭제한다.")
@Test
void deleteAllByMomentIdInBatch() {
void deleteAllByMomentIdInBulk() {
// given
Member member = memberRepository.save(MemberFixture.create());
Memory memory = memoryRepository.save(MemoryFixture.create(null, null));
Expand All @@ -46,7 +46,7 @@ void deleteAllByMomentIdInBatch() {
momentRepository.save(moment2);

// when
commentRepository.deleteAllByMomentIdInBatch(List.of(moment1.getId(), moment2.getId()));
commentRepository.deleteAllByMomentIdInBulk(List.of(moment1.getId(), moment2.getId()));
em.flush();
em.clear();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void findAllByMemberIdAndDateWhenNull() {

@DisplayName("특정 추억의 id를 가지고 있는 모든 MemoryMember를 삭제한다.")
@Test
void deleteAllByMemoryIdInBatch() {
void deleteAllByMemoryIdInBulk() {
// given
Member member = memberRepository.save(MemberFixture.create());
Member member2 = memberRepository.save(MemberFixture.create("hotea"));
Expand All @@ -90,7 +90,7 @@ void deleteAllByMemoryIdInBatch() {
MemoryMember memoryMember2 = memoryMemberRepository.save(new MemoryMember(member2, memory));

// when
memoryMemberRepository.deleteAllByMemoryIdInBatch(memory.getId());
memoryMemberRepository.deleteAllByMemoryIdInBulk(memory.getId());
entityManager.flush();
entityManager.clear();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,25 @@ void update() {
() -> assertThat(images.size()).isEqualTo(2)
);
}

@DisplayName("포함되지 않는 사진들을 선별할 수 있다.")
@Test
void findImagesNotPresentIn() {
// given
MomentImages existingImages = new MomentImages(List.of("picture1", "picture3"));
MomentImages newImages = new MomentImages(List.of("picture1", "picture4"));

// when
List<MomentImage> remainingExistingImages = existingImages.findImagesNotPresentIn(newImages);
List<MomentImage> remainingNewImages = newImages.findImagesNotPresentIn(existingImages);

// then
assertAll(

() -> assertThat(remainingExistingImages.size()).isEqualTo(1),
() -> assertThat(remainingNewImages.size()).isEqualTo(1),
() -> assertThat(remainingExistingImages.get(0).getImageUrl()).isEqualTo("picture3"),
() -> assertThat(remainingNewImages.get(0).getImageUrl()).isEqualTo("picture4")
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.staccato.memory.domain.Memory;
import com.staccato.memory.repository.MemoryRepository;
import com.staccato.moment.domain.Moment;
import com.staccato.moment.domain.MomentImage;
import com.staccato.moment.domain.MomentImages;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -29,9 +30,9 @@ class MomentImageRepositoryTest extends RepositoryTest {
@PersistenceContext
private EntityManager em;

@DisplayName("특정 스타카토의 id 여러개를 가지고 있는 모든 스타카토 이미지들을 삭제한다.")
@DisplayName("특정 스타카토의 id 여러개를 가지고 있는 모든 스타카토 이미지들을 벌크 삭제한다.")
@Test
void deleteAllByMomentIdInBatch() {
void deleteAllByMomentIdInBulk() {
// given
Memory memory = memoryRepository.save(MemoryFixture.create(LocalDate.of(2023, 12, 31), LocalDate.of(2024, 1, 10)));
Moment moment1 = momentRepository.save(MomentFixture
Expand All @@ -40,8 +41,7 @@ void deleteAllByMomentIdInBatch() {
.createWithImages(memory, LocalDateTime.of(2023, 12, 31, 22, 20), new MomentImages(List.of("url1", "url2"))));

// when
momentImageRepository.deleteAllByMomentIdInBatch(List.of(moment1.getId(), moment2.getId()));
em.flush();
momentImageRepository.deleteAllByMomentIdInBulk(List.of(moment1.getId(), moment2.getId()));
em.clear();

// then
Expand All @@ -53,4 +53,25 @@ void deleteAllByMomentIdInBatch() {
.isNotEmpty()).isFalse()
);
}

@DisplayName("특정 스타카토 이미지들을 벌크 삭제한다.")
@Test
void deleteAllByIdInBulk() {
// given
Memory memory = memoryRepository.save(MemoryFixture.create(LocalDate.of(2023, 12, 31), LocalDate.of(2024, 1, 10)));
MomentImages momentImages = new MomentImages(List.of("url1", "url2", "url3"));
Moment moment = momentRepository.save(MomentFixture.createWithImages(memory, LocalDateTime.of(2023, 12, 31, 22, 20), momentImages));

List<Long> imageIds = moment.getMomentImages()
.getImages()
.stream()
.map(MomentImage::getId)
.toList();

// when
momentImageRepository.deleteAllByIdInBulk(imageIds);

// then
assertThat(momentImageRepository.findAll()).isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void findAllByMemory_MemoryMembers_Member() {

@DisplayName("특정 추억의 id를 가진 모든 스타카토를 삭제한다.")
@Test
void deleteAllByMemoryIdInBatch() {
void deleteAllByMemoryIdInBulk() {
// given
Member member = memberRepository.save(MemberFixture.create());
Memory memory = memoryRepository.save(MemoryFixture.create(LocalDate.of(2023, 12, 31), LocalDate.of(2024, 1, 10)));
Expand All @@ -80,7 +80,7 @@ void deleteAllByMemoryIdInBatch() {
Moment moment2 = momentRepository.save(MomentFixture.create(memory, LocalDateTime.of(2024, 1, 1, 22, 21)));

// when
momentRepository.deleteAllByMemoryIdInBatch(memory.getId());
momentRepository.deleteAllByMemoryIdInBulk(memory.getId());
entityManager.flush();
entityManager.clear();

Expand Down
Loading
Loading