Skip to content

Commit 024f2cb

Browse files
committed
Merge branch 'develop' into feat/PRODUCT-256
2 parents 04501d1 + b8fa04b commit 024f2cb

File tree

12 files changed

+126
-43
lines changed

12 files changed

+126
-43
lines changed
Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package eatda.controller.cheer;
22

33
import eatda.domain.cheer.Cheer;
4-
import eatda.domain.store.Store;
54

65
public record CheerPreviewResponse(
76
long storeId,
@@ -11,19 +10,23 @@ public record CheerPreviewResponse(
1110
String storeNeighborhood,
1211
String storeCategory,
1312
long cheerId,
14-
String cheerDescription
13+
String cheerDescription,
14+
long memberId,
15+
String memberNickname
1516
) {
1617

17-
public CheerPreviewResponse(Cheer cheer, Store store, String imageUrl) {
18+
public CheerPreviewResponse(Cheer cheer, String imageUrl) {
1819
this(
19-
store.getId(),
20+
cheer.getStore().getId(),
2021
imageUrl,
21-
store.getName(),
22-
store.getAddressDistrict(),
23-
store.getAddressNeighborhood(),
24-
store.getCategory().getCategoryName(),
22+
cheer.getStore().getName(),
23+
cheer.getStore().getAddressDistrict(),
24+
cheer.getStore().getAddressNeighborhood(),
25+
cheer.getStore().getCategory().getCategoryName(),
2526
cheer.getId(),
26-
cheer.getDescription()
27+
cheer.getDescription(),
28+
cheer.getMember().getId(),
29+
cheer.getMember().getNickname()
2730
);
2831
}
2932
}
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package eatda.controller.cheer;
22

33
import eatda.domain.cheer.Cheer;
4-
import eatda.domain.cheer.CheerTag;
54
import eatda.domain.cheer.CheerTagName;
65
import eatda.domain.store.Store;
76
import java.util.List;
@@ -14,19 +13,13 @@ public record CheerResponse(
1413
List<CheerTagName> tags
1514
) {
1615

17-
public CheerResponse(Cheer cheer, List<CheerTag> cheerTags, Store store, String imageUrl) {
16+
public CheerResponse(Cheer cheer, Store store, String imageUrl) {
1817
this(
1918
store.getId(),
2019
cheer.getId(),
2120
imageUrl,
2221
cheer.getDescription(),
23-
toTagNames(cheerTags)
22+
cheer.getCheerTagNames()
2423
);
2524
}
26-
27-
private static List<CheerTagName> toTagNames(List<CheerTag> cheerTags) {
28-
return cheerTags.stream()
29-
.map(CheerTag::getName)
30-
.toList();
31-
}
3225
}

src/main/java/eatda/domain/cheer/Cheer.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import jakarta.persistence.JoinColumn;
1717
import jakarta.persistence.ManyToOne;
1818
import jakarta.persistence.Table;
19+
import java.util.Collections;
20+
import java.util.List;
1921
import lombok.AccessLevel;
2022
import lombok.Getter;
2123
import lombok.NoArgsConstructor;
@@ -44,6 +46,9 @@ public class Cheer extends AuditingEntity {
4446
@Embedded
4547
private ImageKey imageKey;
4648

49+
@Embedded
50+
private CheerTags cheerTags;
51+
4752
@Column(name = "is_admin", nullable = false)
4853
private boolean isAdmin;
4954

@@ -53,6 +58,7 @@ public Cheer(Member member, Store store, String description, ImageKey imageKey)
5358
this.store = store;
5459
this.description = description;
5560
this.imageKey = imageKey;
61+
this.cheerTags = new CheerTags();
5662

5763
this.isAdmin = false;
5864
}
@@ -67,4 +73,15 @@ private void validateDescription(String description) {
6773
throw new BusinessException(BusinessErrorCode.INVALID_CHEER_DESCRIPTION);
6874
}
6975
}
76+
77+
public void setCheerTags(List<CheerTagName> cheerTagNames) {
78+
this.cheerTags.setTags(this, cheerTagNames);
79+
}
80+
81+
public List<CheerTagName> getCheerTagNames() {
82+
if (cheerTags == null) {
83+
return Collections.emptyList();
84+
}
85+
return cheerTags.getNames();
86+
}
7087
}

src/main/java/eatda/domain/cheer/CheerTagNames.java renamed to src/main/java/eatda/domain/cheer/CheerTags.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,29 @@
22

33
import eatda.exception.BusinessErrorCode;
44
import eatda.exception.BusinessException;
5+
import jakarta.persistence.CascadeType;
6+
import jakarta.persistence.Embeddable;
7+
import jakarta.persistence.OneToMany;
8+
import java.util.ArrayList;
59
import java.util.List;
610
import java.util.stream.Collectors;
711

8-
public class CheerTagNames {
12+
@Embeddable
13+
public class CheerTags {
914

1015
private static final int MAX_CHEER_TAGS_PER_TYPE = 2;
1116

12-
private final List<CheerTagName> cheerTagNames;
17+
@OneToMany(mappedBy = "cheer", cascade = CascadeType.ALL, orphanRemoval = true)
18+
private List<CheerTag> values = new ArrayList<>();
1319

14-
public CheerTagNames(List<CheerTagName> cheerTagNames) {
20+
public void setTags(Cheer cheer, List<CheerTagName> cheerTagNames) {
1521
validate(cheerTagNames);
16-
this.cheerTagNames = List.copyOf(cheerTagNames);
22+
List<CheerTag> cheerTags = cheerTagNames.stream()
23+
.map(name -> new CheerTag(cheer, name)) // cheer is set later
24+
.toList();
25+
26+
this.values.clear();
27+
this.values.addAll(cheerTags);
1728
}
1829

1930
private void validate(List<CheerTagName> cheerTagNames) {
@@ -41,9 +52,9 @@ private long maxCountByType(List<CheerTagName> cheerTagNames) {
4152
.orElse(0L);
4253
}
4354

44-
public List<CheerTag> toCheerTags(Cheer cheer) {
45-
return cheerTagNames.stream()
46-
.map(name -> new CheerTag(cheer, name))
55+
public List<CheerTagName> getNames() {
56+
return values.stream()
57+
.map(CheerTag::getName)
4758
.toList();
4859
}
4960
}

src/main/java/eatda/repository/cheer/CheerRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
import java.util.List;
88
import java.util.Optional;
99
import org.springframework.data.domain.Pageable;
10+
import org.springframework.data.jpa.repository.EntityGraph;
1011
import org.springframework.data.jpa.repository.JpaRepository;
1112
import org.springframework.data.jpa.repository.Query;
1213

1314
public interface CheerRepository extends JpaRepository<Cheer, Long> {
1415

16+
@EntityGraph(attributePaths = {"store", "member"})
1517
List<Cheer> findAllByOrderByCreatedAtDesc(Pageable pageable);
1618

19+
@EntityGraph(attributePaths = {"member"})
1720
List<Cheer> findAllByStoreOrderByCreatedAtDesc(Store store, Pageable pageable);
1821

1922
@Query("""

src/main/java/eatda/service/cheer/CheerService.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import eatda.controller.cheer.CheersResponse;
99
import eatda.domain.ImageKey;
1010
import eatda.domain.cheer.Cheer;
11-
import eatda.domain.cheer.CheerTag;
12-
import eatda.domain.cheer.CheerTagNames;
1311
import eatda.domain.member.Member;
1412
import eatda.domain.store.Store;
1513
import eatda.domain.store.StoreSearchResult;
@@ -43,15 +41,15 @@ public CheerResponse registerCheer(CheerRegisterRequest request,
4341
StoreSearchResult result,
4442
ImageKey imageKey,
4543
long memberId) {
46-
CheerTagNames cheerTagNames = new CheerTagNames(request.tags());
4744
Member member = memberRepository.getById(memberId);
4845
validateRegisterCheer(member, request.storeKakaoId());
4946

5047
Store store = storeRepository.findByKakaoId(result.kakaoId())
5148
.orElseGet(() -> storeRepository.save(result.toStore())); // TODO 상점 조회/저장 동시성 이슈 해결
52-
Cheer cheer = cheerRepository.save(new Cheer(member, store, request.description(), imageKey));
53-
List<CheerTag> cheerTags = cheerTagRepository.saveAll(cheerTagNames.toCheerTags(cheer));
54-
return new CheerResponse(cheer, cheerTags, store, imageStorage.getPreSignedUrl(imageKey));
49+
Cheer cheer = new Cheer(member, store, request.description(), imageKey);
50+
cheer.setCheerTags(request.tags());
51+
Cheer savedCheer = cheerRepository.save(cheer);
52+
return new CheerResponse(savedCheer, store, imageStorage.getPreSignedUrl(imageKey));
5553
}
5654

5755
private void validateRegisterCheer(Member member, String storeKakaoId) {
@@ -71,8 +69,7 @@ public CheersResponse getCheers(int page, int size) {
7169

7270
private CheersResponse toCheersResponse(List<Cheer> cheers) {
7371
return new CheersResponse(cheers.stream()
74-
.map(cheer -> new CheerPreviewResponse(cheer, cheer.getStore(),
75-
imageStorage.getPreSignedUrl(cheer.getImageKey())))
72+
.map(cheer -> new CheerPreviewResponse(cheer, imageStorage.getPreSignedUrl(cheer.getImageKey())))
7673
.toList());
7774
}
7875

src/main/java/eatda/service/store/StoreService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public StoresInMemberResponse getStoresByCheeredMember(long memberId) {
7070
List<Store> stores = storeRepository.findAllByCheeredMemberId(memberId);
7171
List<StoreInMemberResponse> responses = stores.stream()
7272
.map(store -> new StoreInMemberResponse(store, cheerRepository.countByStore(store)))
73-
.toList();
73+
.toList(); // TODO : N+1 문제 해결 (특정 회원의 가게는 3명 제한이라 중요도 낮음)
7474
return new StoresInMemberResponse(responses);
7575
}
7676
}

src/main/resources/application.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ spring:
66
properties:
77
hibernate:
88
format_sql: true
9+
jdbc:
10+
batch_size: 100
11+
order_inserts: true
12+
order_updates: true
913
defer-datasource-initialization: false
1014
open-in-view: false
1115

src/test/java/eatda/document/cheer/CheerDocumentTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ class GetCheers {
156156
fieldWithPath("cheers[].storeNeighborhood").type(STRING).description("가게 주소 (동)"),
157157
fieldWithPath("cheers[].storeCategory").type(STRING).description("가게 카테고리"),
158158
fieldWithPath("cheers[].cheerId").type(NUMBER).description("응원 ID"),
159-
fieldWithPath("cheers[].cheerDescription").type(STRING).description("응원 내용")
159+
fieldWithPath("cheers[].cheerDescription").type(STRING).description("응원 내용"),
160+
fieldWithPath("cheers[].memberId").type(NUMBER).description("응원 작성자 회원 ID"),
161+
fieldWithPath("cheers[].memberNickname").type(STRING).description("응원 작성자 닉네임")
160162
);
161163

162164
@Test
@@ -165,9 +167,9 @@ class GetCheers {
165167
int size = 2;
166168
CheersResponse responses = new CheersResponse(List.of(
167169
new CheerPreviewResponse(2L, "https://example.image", "농민백암순대 본점", "강남구", "선릉구", "한식", 2L,
168-
"너무 맛있어요!"),
170+
"너무 맛있어요!", 5L, "커찬"),
169171
new CheerPreviewResponse(1L, null, "석관동떡볶이", "성북구", "석관동", "기타", 1L,
170-
"너무 매워요! 하지만 맛있어요!")
172+
"너무 매워요! 하지만 맛있어요!", 8L, "찬커")
171173
));
172174
doReturn(responses).when(cheerService).getCheers(page, size);
173175

src/test/java/eatda/domain/cheer/CheerTagNamesTest.java renamed to src/test/java/eatda/domain/cheer/CheerTagsTest.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,79 @@
44
import static org.assertj.core.api.Assertions.assertThatCode;
55
import static org.junit.jupiter.api.Assertions.assertThrows;
66

7+
import eatda.domain.ImageKey;
8+
import eatda.domain.member.Member;
9+
import eatda.domain.store.District;
10+
import eatda.domain.store.Store;
11+
import eatda.domain.store.StoreCategory;
712
import eatda.exception.BusinessErrorCode;
813
import eatda.exception.BusinessException;
914
import java.util.Collections;
1015
import java.util.List;
1116
import org.junit.jupiter.api.Nested;
1217
import org.junit.jupiter.api.Test;
1318

14-
class CheerTagNamesTest {
19+
class CheerTagsTest {
20+
21+
private static final Member DEFAULT_MEMBER = new Member("socialId", "[email protected]", "nickname");
22+
private static final Store DEFAULT_STORE = Store.builder()
23+
.kakaoId("123456789")
24+
.category(StoreCategory.OTHER)
25+
.phoneNumber("010-1234-5678")
26+
.name("가게 이름")
27+
.placeUrl("https://place.kakao.com/123456789")
28+
.roadAddress("")
29+
.lotNumberAddress("서울특별시 강남구 역삼동 123-45")
30+
.district(District.GANGNAM)
31+
.latitude(37.5665)
32+
.longitude(126.978)
33+
.build();
34+
private static final Cheer DEFAULT_CHEER = new Cheer(DEFAULT_MEMBER, DEFAULT_STORE, "Great store!",
35+
new ImageKey("imageKey"));
1536

1637
@Nested
17-
class Validate {
38+
class SetTags {
1839

1940
@Test
2041
void 각_카테고리별_태그는_최대_개수가_정해져있다() {
2142
List<CheerTagName> tagNames = List.of(
2243
CheerTagName.OLD_STORE_MOOD, CheerTagName.ENERGETIC,
2344
CheerTagName.GROUP_RESERVATION, CheerTagName.LARGE_PARKING);
45+
CheerTags cheerTags = new CheerTags();
2446

25-
assertThatCode(() -> new CheerTagNames(tagNames)).doesNotThrowAnyException();
47+
assertThatCode(() -> cheerTags.setTags(DEFAULT_CHEER, tagNames)).doesNotThrowAnyException();
2648
}
2749

2850
@Test
2951
void 태그_이름은_비어있을_수_있다() {
3052
List<CheerTagName> tagNames = Collections.emptyList();
53+
CheerTags cheerTags = new CheerTags();
3154

32-
assertThatCode(() -> new CheerTagNames(tagNames)).doesNotThrowAnyException();
55+
assertThatCode(() -> cheerTags.setTags(DEFAULT_CHEER, tagNames)).doesNotThrowAnyException();
3356
}
3457

3558
@Test
3659
void 카테고리별_태그는_최대_개수를_초과할_수_없다() {
3760
List<CheerTagName> tagNames = List.of(
3861
CheerTagName.OLD_STORE_MOOD, CheerTagName.ENERGETIC, CheerTagName.GOOD_FOR_DATING);
62+
CheerTags cheerTags = new CheerTags();
3963

40-
BusinessException exception = assertThrows(BusinessException.class, () -> new CheerTagNames(tagNames));
64+
BusinessException exception = assertThrows(BusinessException.class,
65+
() -> cheerTags.setTags(DEFAULT_CHEER, tagNames));
4166

4267
assertThat(exception.getErrorCode()).isEqualTo(BusinessErrorCode.EXCEED_CHEER_TAGS_PER_TYPE);
4368
}
4469

4570
@Test
4671
void 태그_이름은_중복될_수_없다() {
4772
List<CheerTagName> tagNames = List.of(CheerTagName.OLD_STORE_MOOD, CheerTagName.OLD_STORE_MOOD);
73+
CheerTags cheerTags = new CheerTags();
4874

49-
BusinessException exception = assertThrows(BusinessException.class, () -> new CheerTagNames(tagNames));
75+
BusinessException exception = assertThrows(BusinessException.class,
76+
() -> cheerTags.setTags(DEFAULT_CHEER, tagNames));
5077

5178
assertThat(exception.getErrorCode()).isEqualTo(BusinessErrorCode.CHEER_TAGS_DUPLICATED);
5279
}
5380
}
81+
5482
}

0 commit comments

Comments
 (0)