diff --git a/src/main/java/com/dnd/runus/domain/badge/BadgeAchievementRepository.java b/src/main/java/com/dnd/runus/domain/badge/BadgeAchievementRepository.java index af98a013..08cdd0d1 100644 --- a/src/main/java/com/dnd/runus/domain/badge/BadgeAchievementRepository.java +++ b/src/main/java/com/dnd/runus/domain/badge/BadgeAchievementRepository.java @@ -11,5 +11,7 @@ public interface BadgeAchievementRepository { BadgeAchievement save(BadgeAchievement badgeAchievement); + void saveAllIgnoreDuplicated(List badgeAchievements); + void deleteByMemberId(long memberId); } diff --git a/src/main/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImpl.java b/src/main/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImpl.java index 93ab6929..66e4d555 100644 --- a/src/main/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImpl.java +++ b/src/main/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImpl.java @@ -35,6 +35,11 @@ public BadgeAchievement save(BadgeAchievement badgeAchievement) { .toDomain(badgeAchievement.badge()); } + @Override + public void saveAllIgnoreDuplicated(List badgeAchievements) { + jooqBadgeAchievementRepository.saveAllIgnoreDuplicated(badgeAchievements); + } + @Override public void deleteByMemberId(long memberId) { jpaBadgeAchievementRepository.deleteByMemberId(memberId); diff --git a/src/main/java/com/dnd/runus/infrastructure/persistence/jooq/badge/JooqBadgeAchievementRepository.java b/src/main/java/com/dnd/runus/infrastructure/persistence/jooq/badge/JooqBadgeAchievementRepository.java index 54da5b89..66f47878 100644 --- a/src/main/java/com/dnd/runus/infrastructure/persistence/jooq/badge/JooqBadgeAchievementRepository.java +++ b/src/main/java/com/dnd/runus/infrastructure/persistence/jooq/badge/JooqBadgeAchievementRepository.java @@ -3,8 +3,6 @@ import com.dnd.runus.domain.badge.BadgeAchievement; import lombok.RequiredArgsConstructor; import org.jooq.DSLContext; -import org.jooq.Record; -import org.jooq.RecordMapper; import org.springframework.stereotype.Repository; import java.time.OffsetDateTime; @@ -24,17 +22,26 @@ public List findByMemberIdWithBadge(long memberId) { .join(BADGE) .on(BADGE_ACHIEVEMENT.BADGE_ID.eq(BADGE.ID)) .where(BADGE_ACHIEVEMENT.MEMBER_ID.eq(memberId)) - .fetch(new BadgeAchievementMapper()); + .fetch(badge -> new BadgeAchievement.OnlyBadge( + badge.get(BADGE_ACHIEVEMENT.ID), + new JooqBadgeMapper().map(badge), + badge.get(BADGE_ACHIEVEMENT.CREATED_AT, OffsetDateTime.class), + badge.get(BADGE_ACHIEVEMENT.UPDATED_AT, OffsetDateTime.class))); } - private static class BadgeAchievementMapper implements RecordMapper { - @Override - public BadgeAchievement.OnlyBadge map(Record record) { - return new BadgeAchievement.OnlyBadge( - record.get(BADGE_ACHIEVEMENT.ID), - new JooqBadgeMapper().map(record), - record.get(BADGE_ACHIEVEMENT.CREATED_AT, OffsetDateTime.class), - record.get(BADGE_ACHIEVEMENT.UPDATED_AT, OffsetDateTime.class)); - } + public void saveAllIgnoreDuplicated(List badgeAchievements) { + dsl.batch(badgeAchievements.stream() + .map(badgeAchievement -> dsl.insertInto(BADGE_ACHIEVEMENT) + .set( + BADGE_ACHIEVEMENT.BADGE_ID, + badgeAchievement.badge().badgeId()) + .set( + BADGE_ACHIEVEMENT.MEMBER_ID, + badgeAchievement.member().memberId()) + .set(BADGE_ACHIEVEMENT.CREATED_AT, badgeAchievement.createdAt()) + .set(BADGE_ACHIEVEMENT.UPDATED_AT, badgeAchievement.updatedAt()) + .onConflictDoNothing()) + .toList()) + .execute(); } } diff --git a/src/test/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImplTest.java b/src/test/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImplTest.java index d23677cc..7afc5d96 100644 --- a/src/test/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImplTest.java +++ b/src/test/java/com/dnd/runus/infrastructure/persistence/domain/badge/BadgeAchievementRepositoryImplTest.java @@ -8,12 +8,15 @@ import com.dnd.runus.global.constant.BadgeType; import com.dnd.runus.global.constant.MemberRole; import com.dnd.runus.infrastructure.persistence.annotation.RepositoryTest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import com.dnd.runus.infrastructure.persistence.jpa.badge.entity.BadgeAchievementEntity; +import com.dnd.runus.infrastructure.persistence.jpa.badge.entity.BadgeEntity; +import jakarta.persistence.EntityManager; +import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; -import static org.junit.jupiter.api.Assertions.assertFalse; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; @RepositoryTest class BadgeAchievementRepositoryImplTest { @@ -47,4 +50,93 @@ public void deleteByMember() { .findById(badgeAchievement.badgeAchievementId()) .isPresent()); } + + @Nested + @DisplayName("BadgeAchievement 저장 테스트") + class BadgeAchievementSaveTest { + @Autowired + private EntityManager entityManager; + + private Badge badge1; + private Badge badge2; + + private BadgeAchievement badgeAchievement1; + private BadgeAchievement badgeAchievement2; + + @BeforeEach + void beforeEach() { + BadgeEntity badgeEntity1 = + BadgeEntity.from(new Badge(0L, "testBadge1", "testBadge1", "tesUrl1", BadgeType.DISTANCE_METER, 0)); + BadgeEntity badgeEntity2 = + BadgeEntity.from(new Badge(0L, "testBadge2", "testBadge2", "tesUrl2", BadgeType.DISTANCE_METER, 2)); + + entityManager.persist(badgeEntity1); + entityManager.persist(badgeEntity2); + + badge1 = badgeEntity1.toDomain(); + badge2 = badgeEntity2.toDomain(); + + badgeAchievement1 = new BadgeAchievement(badge1, savedMember); + badgeAchievement2 = new BadgeAchievement(badge2, savedMember); + + badgeAchievementRepository.save(badgeAchievement1); + badgeAchievementRepository.save(badgeAchievement2); + } + + @AfterEach + void afterEach() { + entityManager.createQuery("delete from badge_achievement").executeUpdate(); + entityManager.createQuery("delete from badge").executeUpdate(); + } + + @Test + @DisplayName("saveAllIgnoreDuplicated: 중복된 데이터가 없을 때 모든 데이터를 저장한다.") + void saveAllIgnoreDuplicated() { + // given + List badgeAchievements = List.of(badgeAchievement1, badgeAchievement2); + + // when + badgeAchievementRepository.saveAllIgnoreDuplicated(badgeAchievements); + + // then + List achievements = entityManager + .createQuery("select ba from badge_achievement ba", BadgeAchievementEntity.class) + .getResultList() + .stream() + .map(BadgeAchievementEntity::toDomain) + .toList(); + + assertFalse(achievements.isEmpty()); + + assertEquals(2, achievements.size()); + assertTrue(achievements.stream().anyMatch(ba -> ba.badge().badgeId() == badge1.badgeId())); + assertTrue(achievements.stream().anyMatch(ba -> ba.badge().badgeId() == badge2.badgeId())); + } + + @Test + @DisplayName("saveAllIgnoreDuplicated: 중복된 데이터가 있을 때 중복된 데이터는 무시하고 저장한다.") + void saveAllIgnoreDuplicated_case_duplicated() { + // given + List badgeAchievements = List.of(badgeAchievement1, badgeAchievement2); + + // when + // 저장 여러번 시도 + badgeAchievementRepository.saveAllIgnoreDuplicated(badgeAchievements); + badgeAchievementRepository.saveAllIgnoreDuplicated(badgeAchievements); + + // then + List achievements = entityManager + .createQuery("select ba from badge_achievement ba", BadgeAchievementEntity.class) + .getResultList() + .stream() + .map(BadgeAchievementEntity::toDomain) + .toList(); + + assertFalse(achievements.isEmpty()); + + assertEquals(2, achievements.size()); + assertTrue(achievements.stream().anyMatch(ba -> ba.badge().badgeId() == badge1.badgeId())); + assertTrue(achievements.stream().anyMatch(ba -> ba.badge().badgeId() == badge2.badgeId())); + } + } }