diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java index 01e117ea0..4e796b81d 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java @@ -3,7 +3,7 @@ import com.example.solidconnection.auth.dto.SignUpRequest; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountyRepository; +import com.example.solidconnection.location.country.repository.InterestedCountryRepository; import com.example.solidconnection.location.region.repository.InterestedRegionRepository; import com.example.solidconnection.location.region.repository.RegionRepository; import com.example.solidconnection.siteuser.domain.AuthType; @@ -20,9 +20,9 @@ public class EmailSignUpService extends SignUpService { public EmailSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountyRepository interestedCountyRepository, + CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository, EmailSignUpTokenProvider emailSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountyRepository); + super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountryRepository); this.emailSignUpTokenProvider = emailSignUpTokenProvider; } diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index 95bd4ecac..8cce448f7 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -5,7 +5,7 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.location.country.domain.InterestedCountry; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountyRepository; +import com.example.solidconnection.location.country.repository.InterestedCountryRepository; import com.example.solidconnection.location.region.domain.InterestedRegion; import com.example.solidconnection.location.region.repository.InterestedRegionRepository; import com.example.solidconnection.location.region.repository.RegionRepository; @@ -31,17 +31,17 @@ public abstract class SignUpService { protected final RegionRepository regionRepository; protected final InterestedRegionRepository interestedRegionRepository; protected final CountryRepository countryRepository; - protected final InterestedCountyRepository interestedCountyRepository; + protected final InterestedCountryRepository interestedCountryRepository; protected SignUpService(SignInService signInService, SiteUserRepository siteUserRepository, RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountyRepository interestedCountyRepository) { + CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository) { this.signInService = signInService; this.siteUserRepository = siteUserRepository; this.regionRepository = regionRepository; this.interestedRegionRepository = interestedRegionRepository; this.countryRepository = countryRepository; - this.interestedCountyRepository = interestedCountyRepository; + this.interestedCountryRepository = interestedCountryRepository; } @Transactional @@ -81,7 +81,7 @@ private void saveInterestedCountry(SignUpRequest signUpRequest, SiteUser savedSi List interestedCountries = countryRepository.findByKoreanNames(interestedCountryNames).stream() .map(country -> new InterestedCountry(savedSiteUser, country)) .toList(); - interestedCountyRepository.saveAll(interestedCountries); + interestedCountryRepository.saveAll(interestedCountries); } protected abstract void validateSignUpToken(SignUpRequest signUpRequest); diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java index 5676f1c7d..96253f548 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java @@ -5,7 +5,7 @@ import com.example.solidconnection.auth.service.SignUpService; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountyRepository; +import com.example.solidconnection.location.country.repository.InterestedCountryRepository; import com.example.solidconnection.location.region.repository.InterestedRegionRepository; import com.example.solidconnection.location.region.repository.RegionRepository; import com.example.solidconnection.siteuser.domain.AuthType; @@ -22,9 +22,9 @@ public class OAuthSignUpService extends SignUpService { OAuthSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountyRepository interestedCountyRepository, + CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository, OAuthSignUpTokenProvider oAuthSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountyRepository); + super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountryRepository); this.oAuthSignUpTokenProvider = oAuthSignUpTokenProvider; } diff --git a/src/main/java/com/example/solidconnection/location/country/domain/InterestedCountry.java b/src/main/java/com/example/solidconnection/location/country/domain/InterestedCountry.java index 9d75c51ed..edc68ba79 100644 --- a/src/main/java/com/example/solidconnection/location/country/domain/InterestedCountry.java +++ b/src/main/java/com/example/solidconnection/location/country/domain/InterestedCountry.java @@ -6,6 +6,8 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,6 +15,12 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity +@Table(uniqueConstraints = { + @UniqueConstraint( + name = "uk_interested_country_site_user_id_country_code", + columnNames = {"site_user_id", "country_code"} + ) +}) public class InterestedCountry { @Id diff --git a/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountyRepository.java b/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java similarity index 81% rename from src/main/java/com/example/solidconnection/location/country/repository/InterestedCountyRepository.java rename to src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java index 879323e28..2eacc2ca9 100644 --- a/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountyRepository.java +++ b/src/main/java/com/example/solidconnection/location/country/repository/InterestedCountryRepository.java @@ -8,6 +8,6 @@ import java.util.List; @Repository -public interface InterestedCountyRepository extends JpaRepository { +public interface InterestedCountryRepository extends JpaRepository { List findAllBySiteUser(SiteUser siteUser); } diff --git a/src/main/java/com/example/solidconnection/location/region/domain/InterestedRegion.java b/src/main/java/com/example/solidconnection/location/region/domain/InterestedRegion.java index 457ee4eb6..35214a95c 100644 --- a/src/main/java/com/example/solidconnection/location/region/domain/InterestedRegion.java +++ b/src/main/java/com/example/solidconnection/location/region/domain/InterestedRegion.java @@ -6,6 +6,8 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -13,6 +15,12 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity +@Table(uniqueConstraints = { + @UniqueConstraint( + name = "uk_interested_region_site_user_id_region_code", + columnNames = {"site_user_id", "region_code"} + ) +}) public class InterestedRegion { @Id diff --git a/src/main/resources/db/migration/V16__add_unique_constraint_to_intersted.sql b/src/main/resources/db/migration/V16__add_unique_constraint_to_intersted.sql new file mode 100644 index 000000000..2f7a8524c --- /dev/null +++ b/src/main/resources/db/migration/V16__add_unique_constraint_to_intersted.sql @@ -0,0 +1,7 @@ +ALTER TABLE interested_country +ADD CONSTRAINT uk_interested_country_site_user_id_country_code +UNIQUE (site_user_id, country_code); + +ALTER TABLE interested_region +ADD CONSTRAINT uk_interested_region_site_user_id_region_code +UNIQUE (site_user_id, region_code); diff --git a/src/test/java/com/example/solidconnection/location/country/repository/InterestedCountryRepositoryTest.java b/src/test/java/com/example/solidconnection/location/country/repository/InterestedCountryRepositoryTest.java new file mode 100644 index 000000000..4daeb55e1 --- /dev/null +++ b/src/test/java/com/example/solidconnection/location/country/repository/InterestedCountryRepositoryTest.java @@ -0,0 +1,86 @@ +package com.example.solidconnection.location.country.repository; + +import com.example.solidconnection.location.country.domain.Country; +import com.example.solidconnection.location.country.domain.InterestedCountry; +import com.example.solidconnection.location.country.fixture.CountryFixture; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.fixture.SiteUserFixture; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +@TestContainerSpringBootTest +public class InterestedCountryRepositoryTest { + + @Autowired + private InterestedCountryRepository interestedCountryRepository; + + @Autowired + private SiteUserFixture siteUserFixture; + + @Autowired + private CountryFixture countryFixture; + + @Nested + class 사용자와_나라는_복합_유니크_제약_조건을_가진다 { + + @Test + void 같은_사용자가_같은_나라에_관심_표시를_하면_예외_응답을_반환한다() { + // given + SiteUser user = siteUserFixture.사용자(); + Country country = countryFixture.미국(); + + InterestedCountry firstInterest = new InterestedCountry(user, country); + interestedCountryRepository.save(firstInterest); + + InterestedCountry secondInterest = new InterestedCountry(user, country); + + // when & then + assertThatCode(() -> interestedCountryRepository.save(secondInterest)) + .isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + void 다른_사용자가_같은_나라에_관심_표시를_하면_정상_저장된다() { + // given + SiteUser user1 = siteUserFixture.사용자(1, "user1"); + SiteUser user2 = siteUserFixture.사용자(2, "user2"); + Country country = countryFixture.미국(); + + InterestedCountry firstInterest = new InterestedCountry(user1, country); + interestedCountryRepository.save(firstInterest); + + InterestedCountry secondInterest = new InterestedCountry(user2, country); + + // when & then + assertThatCode(() -> { + InterestedCountry saved = interestedCountryRepository.save(secondInterest); + assertThat(saved.getId()).isNotNull(); + }).doesNotThrowAnyException(); + } + + @Test + void 같은_사용자가_다른_나라에_관심_표시를_하면_정상_저장된다() { + // given + SiteUser user = siteUserFixture.사용자(); + Country country1 = countryFixture.미국(); + Country country2 = countryFixture.일본(); + + InterestedCountry firstInterest = new InterestedCountry(user, country1); + interestedCountryRepository.save(firstInterest); + + InterestedCountry secondInterest = new InterestedCountry(user, country2); + + // when & then + assertThatCode(() -> { + InterestedCountry saved = interestedCountryRepository.save(secondInterest); + assertThat(saved.getId()).isNotNull(); + }).doesNotThrowAnyException(); + } + } +} diff --git a/src/test/java/com/example/solidconnection/location/region/repository/InterestedRegionRepositoryTest.java b/src/test/java/com/example/solidconnection/location/region/repository/InterestedRegionRepositoryTest.java new file mode 100644 index 000000000..a9594e0f8 --- /dev/null +++ b/src/test/java/com/example/solidconnection/location/region/repository/InterestedRegionRepositoryTest.java @@ -0,0 +1,86 @@ +package com.example.solidconnection.location.region.repository; + +import com.example.solidconnection.location.region.domain.InterestedRegion; +import com.example.solidconnection.location.region.domain.Region; +import com.example.solidconnection.location.region.fixture.RegionFixture; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.fixture.SiteUserFixture; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +@TestContainerSpringBootTest +public class InterestedRegionRepositoryTest { + + @Autowired + private InterestedRegionRepository interestedRegionRepository; + + @Autowired + private SiteUserFixture siteUserFixture; + + @Autowired + private RegionFixture regionFixture; + + @Nested + class 사용자와_지역은_복합_유니크_제약_조건을_가진다 { + + @Test + void 같은_사용자가_같은_지역에_관심_표시를_하면_예외_응답을_반환한다() { + // given + SiteUser user = siteUserFixture.사용자(); + Region region = regionFixture.영미권(); + + InterestedRegion firstInterest = new InterestedRegion(user, region); + interestedRegionRepository.save(firstInterest); + + InterestedRegion secondInterest = new InterestedRegion(user, region); + + // when & then + assertThatCode(() -> interestedRegionRepository.save(secondInterest)) + .isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + void 다른_사용자가_같은_지역에_관심_표시를_하면_정상_저장된다() { + // given + SiteUser user1 = siteUserFixture.사용자(1, "user1"); + SiteUser user2 = siteUserFixture.사용자(2, "user2"); + Region region = regionFixture.영미권(); + + InterestedRegion firstInterest = new InterestedRegion(user1, region); + interestedRegionRepository.save(firstInterest); + + InterestedRegion secondInterest = new InterestedRegion(user2, region); + + // when & then + assertThatCode(() -> { + InterestedRegion saved = interestedRegionRepository.save(secondInterest); + assertThat(saved.getId()).isNotNull(); + }).doesNotThrowAnyException(); + } + + @Test + void 같은_사용자가_다른_지역에_관심_표시를_하면_정상_저장된다() { + // given + SiteUser user = siteUserFixture.사용자(); + Region region1 = regionFixture.영미권(); + Region region2 = regionFixture.유럽(); + + InterestedRegion firstInterest = new InterestedRegion(user, region1); + interestedRegionRepository.save(firstInterest); + + InterestedRegion secondInterest = new InterestedRegion(user, region2); + + // when & then + assertThatCode(() -> { + InterestedRegion saved = interestedRegionRepository.save(secondInterest); + assertThat(saved.getId()).isNotNull(); + }).doesNotThrowAnyException(); + } + } +} diff --git a/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java index ff274b96a..7169f5021 100644 --- a/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java @@ -2,7 +2,7 @@ import com.example.solidconnection.location.country.domain.InterestedCountry; import com.example.solidconnection.location.country.fixture.CountryFixture; -import com.example.solidconnection.location.country.repository.InterestedCountyRepository; +import com.example.solidconnection.location.country.repository.InterestedCountryRepository; import com.example.solidconnection.location.region.domain.InterestedRegion; import com.example.solidconnection.location.region.fixture.RegionFixture; import com.example.solidconnection.location.region.repository.InterestedRegionRepository; @@ -34,7 +34,7 @@ class UniversityRecommendServiceTest { private InterestedRegionRepository interestedRegionRepository; @Autowired - private InterestedCountyRepository interestedCountyRepository; + private InterestedCountryRepository interestedCountryRepository; @Autowired private GeneralUniversityRecommendService generalUniversityRecommendService; @@ -97,7 +97,7 @@ void setUp() { @Test void 관심_국가_설정한_사용자의_맞춤_추천_대학을_조회한다() { // given - interestedCountyRepository.save(new InterestedCountry(user, countryFixture.덴마크())); + interestedCountryRepository.save(new InterestedCountry(user, countryFixture.덴마크())); // when UniversityRecommendsResponse response = universityRecommendService.getPersonalRecommends(user); @@ -115,7 +115,7 @@ void setUp() { void 관심_지역과_국가_모두_설정한_사용자의_맞춤_추천_대학을_조회한다() { // given interestedRegionRepository.save(new InterestedRegion(user, regionFixture.영미권())); - interestedCountyRepository.save(new InterestedCountry(user, countryFixture.덴마크())); + interestedCountryRepository.save(new InterestedCountry(user, countryFixture.덴마크())); // when UniversityRecommendsResponse response = universityRecommendService.getPersonalRecommends(user);