From e829b3837d92b31b6edb367898d23a7db3788129 Mon Sep 17 00:00:00 2001 From: kevstevie Date: Mon, 18 Sep 2023 13:20:30 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20message=20entity,=20repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/message/Message.java | 54 +++++++ .../domain/message/MessageListDto.java | 10 ++ .../domain/message/MessageRepository.java | 31 ++++ .../message/MessageSenderReceiverDto.java | 10 ++ .../domain/message/MessageRepositoryTest.java | 152 ++++++++++++++++++ backend/src/test/resources/application.yml | 5 +- 6 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/yigongil/backend/domain/message/Message.java create mode 100644 backend/src/main/java/com/yigongil/backend/domain/message/MessageListDto.java create mode 100644 backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java create mode 100644 backend/src/main/java/com/yigongil/backend/domain/message/MessageSenderReceiverDto.java create mode 100644 backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java diff --git a/backend/src/main/java/com/yigongil/backend/domain/message/Message.java b/backend/src/main/java/com/yigongil/backend/domain/message/Message.java new file mode 100644 index 000000000..12c0e4f3a --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/domain/message/Message.java @@ -0,0 +1,54 @@ +package com.yigongil.backend.domain.message; + +import com.yigongil.backend.domain.BaseEntity; +import com.yigongil.backend.domain.member.Member; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Entity +public class Message extends BaseEntity { + + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + private Long id; + + @ManyToOne + @JoinColumn(nullable = false, updatable = false) + private Member sender; + + @ManyToOne + @JoinColumn(nullable = false, updatable = false) + private Member receiver; + + @Column(nullable = false) + private String content; + + protected Message() { + } + + @Builder + public Message(Long id, Member sender, Member receiver, String content) { + this.id = id; + this.sender = sender; + this.receiver = receiver; + this.content = content; + } + + @Override + public String toString() { + return "Message{" + + "id=" + id + + ", sender=" + sender + + ", receiver=" + receiver + + ", content='" + content + '\'' + + '}'; + } +} diff --git a/backend/src/main/java/com/yigongil/backend/domain/message/MessageListDto.java b/backend/src/main/java/com/yigongil/backend/domain/message/MessageListDto.java new file mode 100644 index 000000000..6adbc1650 --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/domain/message/MessageListDto.java @@ -0,0 +1,10 @@ +package com.yigongil.backend.domain.message; + +public interface MessageListDto { + + String getContent(); + + String getCreatedAt(); + + boolean getIsMine(); +} diff --git a/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java b/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java new file mode 100644 index 000000000..ff5168810 --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java @@ -0,0 +1,31 @@ +package com.yigongil.backend.domain.message; + +import com.yigongil.backend.domain.member.Member; +import java.util.List; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.Repository; + +public interface MessageRepository extends Repository { + + Message save(Message message); + + @Query(""" + select m.sender as sender, m.receiver as receiver + from Message m + group by m.sender, m.receiver + having m.sender = :member or m.receiver = :member + """) + List findBySenderOrReceiverOrderByIdDesc(Member member); + + @Query(""" + select m.content as content, m.createdAt as createdAt, + case when m.sender.id = :memberId then true else false end as isMine + from Message m + where (m.sender.id = :memberId and m.receiver.id = :opponentId) + or (m.sender.id = :opponentId and m.receiver.id = :memberId) + order by m.id desc + """) + Slice findAllMessageByMemberAndPaging(Long memberId, Long opponentId, Pageable pageable); +} diff --git a/backend/src/main/java/com/yigongil/backend/domain/message/MessageSenderReceiverDto.java b/backend/src/main/java/com/yigongil/backend/domain/message/MessageSenderReceiverDto.java new file mode 100644 index 000000000..fa382b161 --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/domain/message/MessageSenderReceiverDto.java @@ -0,0 +1,10 @@ +package com.yigongil.backend.domain.message; + +import com.yigongil.backend.domain.member.Member; + +public interface MessageSenderReceiverDto { + + Member getSender(); + + Member getReceiver(); +} diff --git a/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java b/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java new file mode 100644 index 000000000..93b6f2822 --- /dev/null +++ b/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java @@ -0,0 +1,152 @@ +package com.yigongil.backend.domain.message; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.yigongil.backend.config.JpaConfig; +import com.yigongil.backend.domain.member.Member; +import com.yigongil.backend.domain.member.MemberRepository; +import com.yigongil.backend.fixture.MemberFixture; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +@Import(JpaConfig.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@DataJpaTest +class MessageRepositoryTest { + + @Autowired + private MessageRepository messageRepository; + + @Autowired + private MemberRepository memberRepository; + + private Member 김진우; + private Member 노이만; + private Pageable pageable; + + @BeforeEach + void setUp() { + 김진우 = memberRepository.save(MemberFixture.김진우.toMember()); + 노이만 = memberRepository.save(MemberFixture.폰노이만.toMember()); + pageable = PageRequest.of(0, 10); + } + + @Test + void 메시지를_주고받은_상대들을_조회하는_쿼리() { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); + + List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + + assertThat(result).hasSize(2); + } + + @Test + void 메시지를_주고받은_상대들을_조회하는_쿼리2() { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); + + List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + + assertThat(result).hasSize(2); + } + + @Test + void 메시지를_주고받은_상대들을_조회하는_쿼리3() { + Member 파울러 = memberRepository.save(MemberFixture.마틴파울러.toMemberWithoutId()); + + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); + messageRepository.save(new Message(null, 파울러, 김진우, "Hello, world!")); + + List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + + assertThat(result).hasSize(3); + } + + @Test + void 메시지를_주고받은_상대들을_조회하는_쿼리4() { + Member 파울러 = memberRepository.save(MemberFixture.마틴파울러.toMemberWithoutId()); + + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); + messageRepository.save(new Message(null, 파울러, 김진우, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 파울러, "Hello, world!")); + + List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + + assertThat(result).hasSize(3); + } + + @Test + void 주고받은_쪽지를_정렬한다() { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); + + Slice result = messageRepository.findAllMessageByMemberAndPaging(김진우.getId(), 노이만.getId(), pageable); + + assertAll( + () -> assertThat(result).hasSize(3), + () -> assertThat(result.getContent().get(0).getIsMine()).isFalse(), + () -> assertThat(result.getContent().get(1).getIsMine()).isTrue(), + () -> assertThat(result.getContent().get(2).getIsMine()).isTrue() + ); + } + + @Test + void 주고받은_쪽지를_페이징한다() { + for (int i = 0; i < 11; i++) { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + } + + Slice result = messageRepository.findAllMessageByMemberAndPaging(김진우.getId(), 노이만.getId(), pageable); + + assertAll( + () -> assertThat(result).hasSize(pageable.getPageSize()), + () -> assertThat(result.hasNext()).isTrue() + ); + } + + @Test + void 주고받은_쪽지를_페이징한다2() { + for (int i = 0; i < 9; i++) { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + } + + Slice result = messageRepository.findAllMessageByMemberAndPaging(김진우.getId(), 노이만.getId(), pageable); + + assertAll( + () -> assertThat(result).hasSize(9), + () -> assertThat(result.hasNext()).isFalse(), + () -> assertThat(result).map(MessageListDto::getIsMine).doesNotContain(false) + ); + } + + @Test + void 파라미터_순서를_바꿔서_주고받은_쪽지를_페이징한다() { + for (int i = 0; i < 9; i++) { + messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); + } + + Slice result = messageRepository.findAllMessageByMemberAndPaging(노이만.getId(), 김진우.getId(), pageable); + + assertAll( + () -> assertThat(result).hasSize(9), + () -> assertThat(result.hasNext()).isFalse(), + () -> assertThat(result).map(MessageListDto::getIsMine).doesNotContain(true) + ); + } +} diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 77da21608..45b85a6e1 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -18,8 +18,11 @@ spring: format_sql: true show_sql: true hibernate: - ddl-auto: create + ddl-auto: update database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + generate-ddl: true + + flyway: enabled: false From e0a0c81259bf90d55e10f85eec0ea467a2af8365 Mon Sep 17 00:00:00 2001 From: kevstevie Date: Tue, 19 Sep 2023 10:14:25 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=BF=BC=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/message/MessageRepository.java | 7 +++---- .../backend/domain/message/MessageRepositoryTest.java | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java b/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java index ff5168810..a48625310 100644 --- a/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java +++ b/backend/src/main/java/com/yigongil/backend/domain/message/MessageRepository.java @@ -12,12 +12,11 @@ public interface MessageRepository extends Repository { Message save(Message message); @Query(""" - select m.sender as sender, m.receiver as receiver + select distinct m.sender as sender, m.receiver as receiver from Message m - group by m.sender, m.receiver - having m.sender = :member or m.receiver = :member + where m.sender = :member or m.receiver = :member """) - List findBySenderOrReceiverOrderByIdDesc(Member member); + List findBySenderOrReceiver(Member member); @Query(""" select m.content as content, m.createdAt as createdAt, diff --git a/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java b/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java index 93b6f2822..423433e60 100644 --- a/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java +++ b/backend/src/test/java/com/yigongil/backend/domain/message/MessageRepositoryTest.java @@ -45,7 +45,7 @@ void setUp() { messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); - List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + List result = messageRepository.findBySenderOrReceiver(김진우); assertThat(result).hasSize(2); } @@ -56,7 +56,7 @@ void setUp() { messageRepository.save(new Message(null, 김진우, 노이만, "Hello, world!")); messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); - List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + List result = messageRepository.findBySenderOrReceiver(김진우); assertThat(result).hasSize(2); } @@ -70,7 +70,7 @@ void setUp() { messageRepository.save(new Message(null, 노이만, 김진우, "Hello, world!")); messageRepository.save(new Message(null, 파울러, 김진우, "Hello, world!")); - List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + List result = messageRepository.findBySenderOrReceiver(김진우); assertThat(result).hasSize(3); } @@ -85,7 +85,7 @@ void setUp() { messageRepository.save(new Message(null, 파울러, 김진우, "Hello, world!")); messageRepository.save(new Message(null, 노이만, 파울러, "Hello, world!")); - List result = messageRepository.findBySenderOrReceiverOrderByIdDesc(김진우); + List result = messageRepository.findBySenderOrReceiver(김진우); assertThat(result).hasSize(3); }