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

Feat: 링크 @Entity에 링크 번들 ID 필드를 추가한다. #20

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/java/com/seong/shoutlink/domain/link/Link.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public class Link {


public Link(String url, String description) {
this(null, url, description);
}

public Link(Long linkId, String url, String description) {
this.linkId = linkId;
this.url = url;
this.description = description;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.seong.shoutlink.domain.link;

import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import lombok.Getter;

@Getter
public class LinkWithLinkBundle {

private final Link link;
private final LinkBundle linkBundle;

public LinkWithLinkBundle(Link link, LinkBundle linkBundle) {
this.link = link;
this.linkBundle = linkBundle;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public ResponseEntity<CreateLinkResponse> createLink(
@Valid @RequestBody CreateLinkRequest request) {
CreateLinkResponse response = linkService.createLink(new CreateLinkCommand(
memberId,
request.linkBundleId(),
request.url(),
request.description()));
return ResponseEntity.status(HttpStatus.CREATED).body(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.seong.shoutlink.domain.link.controller.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record CreateLinkRequest(
@NotNull(message = "링크 묶음 ID는 필수값입니다.")
Long linkBundleId,
@NotBlank(message = "링크 url은 필수값입니다.")
String url,
String description) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.seong.shoutlink.domain.link.repository;

import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.LinkWithLinkBundle;
import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand All @@ -20,13 +22,20 @@ public class LinkEntity {

private String url;
private String description;
private Long linkBundleId;

private LinkEntity(String url, String description) {
private LinkEntity(String url, String description, Long linkBundleId) {
this.url = url;
this.description = description;
this.linkBundleId = linkBundleId;
}

public static LinkEntity create(Link link) {
return new LinkEntity(link.getUrl(), link.getDescription());
public static LinkEntity create(LinkWithLinkBundle linkWithLinkBundle) {
Link link = linkWithLinkBundle.getLink();
LinkBundle linkBundle = linkWithLinkBundle.getLinkBundle();
return new LinkEntity(
link.getUrl(),
link.getDescription(),
linkBundle.getLinkBundleId());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.seong.shoutlink.domain.link.repository;

import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.LinkWithLinkBundle;
import com.seong.shoutlink.domain.link.service.LinkRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
Expand All @@ -12,8 +12,8 @@ public class LinkRepositoryImpl implements LinkRepository {
private final LinkJpaRepository linkJpaRepository;

@Override
public Long save(Link link) {
LinkEntity linkEntity = linkJpaRepository.save(LinkEntity.create(link));
public Long save(LinkWithLinkBundle linkWithLinkBundle) {
LinkEntity linkEntity = linkJpaRepository.save(LinkEntity.create(linkWithLinkBundle));
return linkEntity.getLinkId();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.seong.shoutlink.domain.link.service;

import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.LinkWithLinkBundle;

public interface LinkRepository {

Long save(Link link);
Long save(LinkWithLinkBundle linkWithLinkBundle);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.seong.shoutlink.domain.link.service;

import com.seong.shoutlink.domain.common.EventPublisher;
import com.seong.shoutlink.domain.exception.ErrorCode;
import com.seong.shoutlink.domain.exception.ShoutLinkException;
import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.LinkWithLinkBundle;
import com.seong.shoutlink.domain.link.service.event.CreateLinkEvent;
import com.seong.shoutlink.domain.link.service.request.CreateLinkCommand;
import com.seong.shoutlink.domain.link.service.response.CreateLinkResponse;
import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import com.seong.shoutlink.domain.linkbundle.service.LinkBundleRepository;
import com.seong.shoutlink.domain.member.service.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -16,15 +21,21 @@ public class LinkService {

private final MemberRepository memberRepository;
private final LinkRepository linkRepository;
private final LinkBundleRepository linkBundleRepository;
private final EventPublisher eventPublisher;

@Transactional
public CreateLinkResponse createLink(CreateLinkCommand command) {
// Member member = memberRepository.findById(command.memberId())
// .orElseThrow(() -> new ShoutLinkException("존재하지 않는 사용자입니다.", ErrorCode.NOT_FOUND));
LinkBundle linkBundle = getLinkBundle(command.linkBundleId());
Link link = new Link(command.url(), command.description());
Long linkId = linkRepository.save(link);
LinkWithLinkBundle linkWithLinkBundle = new LinkWithLinkBundle(link, linkBundle);
Long linkId = linkRepository.save(linkWithLinkBundle);
eventPublisher.publishEvent(new CreateLinkEvent(command.url()));
return new CreateLinkResponse(linkId);
}

private LinkBundle getLinkBundle(Long linkBundleId) {
return linkBundleRepository.findById(linkBundleId)
.orElseThrow(() -> new ShoutLinkException("존재하지 않는 링크 번들입니다.", ErrorCode.NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.seong.shoutlink.domain.link.service.request;

public record CreateLinkCommand(Long memberId, String url, String description) {
public record CreateLinkCommand(Long memberId, Long linkBundleId, String url, String description) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ public class LinkBundle {
private Long linkBundleId;
private String description;
private boolean isDefault;
private Member member;
private Long memberId;

public LinkBundle(String description, boolean isDefault, Member member) {
this(null, description, isDefault, member.getMemberId());
}

public LinkBundle(Long linkBundleId, String description, boolean isDefault, Long memberId) {
this.linkBundleId = linkBundleId;
this.description = description;
this.isDefault = isDefault;
this.member = member;
this.memberId = memberId;
}

public void initId(Long linkBundleId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ public static LinkBundleEntity create(LinkBundle linkBundle) {
linkBundle.getLinkBundleId(),
linkBundle.getDescription(),
linkBundle.isDefault(),
linkBundle.getMember().getMemberId());
linkBundle.getMemberId());
}

public LinkBundle toDomain() {
return new LinkBundle(
linkBundleId,
description,
isDefault,
memberId
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import com.seong.shoutlink.domain.linkbundle.service.LinkBundleRepository;
import com.seong.shoutlink.domain.member.Member;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

Expand All @@ -24,4 +25,10 @@ public Long save(LinkBundle linkBundle) {
public void updateDefaultBundleFalse(Member member) {
linkBundleJpaRepository.updateDefaultBundleFalse(member.getMemberId());
}

@Override
public Optional<LinkBundle> findById(Long linkBundleId) {
return linkBundleJpaRepository.findById(linkBundleId)
.map(LinkBundleEntity::toDomain);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import com.seong.shoutlink.domain.member.Member;
import java.util.Optional;

public interface LinkBundleRepository {

Long save(LinkBundle linkBundle);

void updateDefaultBundleFalse(Member member);

Optional<LinkBundle> findById(Long linkBundleId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class LinkControllerTest extends BaseControllerTest {
@DisplayName("성공: 링크 생성 API 호출 시")
void createLink() throws Exception {
//given
CreateLinkRequest request = new CreateLinkRequest("https://hseong.tistory.com/", "내 블로그");
CreateLinkRequest request = new CreateLinkRequest(1L, "https://hseong.tistory.com/", "내 블로그");
CreateLinkResponse response = new CreateLinkResponse(1L);
given(linkService.createLink(any())).willReturn(response);

Expand All @@ -42,6 +42,7 @@ void createLink() throws Exception {
headerWithName(AUTHORIZATION).description("사용자 액세스 토큰")
),
requestFields(
fieldWithPath("linkBundleId").type(JsonFieldType.NUMBER).description("링크 번들 ID"),
fieldWithPath("url").type(JsonFieldType.STRING).description("링크 url"),
fieldWithPath("description").type(JsonFieldType.STRING).description("링크 설명")
.optional()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.seong.shoutlink.domain.link.repository;

import com.seong.shoutlink.domain.link.Link;
import com.seong.shoutlink.domain.link.LinkWithLinkBundle;
import com.seong.shoutlink.domain.link.service.LinkRepository;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -10,9 +11,14 @@ public class FakeLinkRepository implements LinkRepository {
private final Map<Long, Link> memory = new HashMap<>();

@Override
public Long save(Link link) {
public Long save(LinkWithLinkBundle linkWithLinkBundle) {
long nextId = getNextId();
memory.put(nextId, linkWithLinkBundle.getLink());
return nextId;
}

private long getNextId() {
long nextId = memory.keySet().size() + 1;
memory.put(nextId, link);
return nextId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import com.seong.shoutlink.domain.link.repository.FakeLinkRepository;
import com.seong.shoutlink.domain.link.service.request.CreateLinkCommand;
import com.seong.shoutlink.domain.link.service.response.CreateLinkResponse;
import com.seong.shoutlink.domain.linkbundle.repository.FakeLinkBundleRepository;
import com.seong.shoutlink.domain.member.Member;
import com.seong.shoutlink.domain.member.repository.StubMemberRepository;
import com.seong.shoutlink.fixture.LinkBundleFixture;
import com.seong.shoutlink.fixture.MemberFixture;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -22,22 +25,26 @@ class CreateLinkTest {
private LinkService linkService;
private StubMemberRepository memberRepository;
private FakeLinkRepository linkRepository;
private FakeLinkBundleRepository linkBundleRepository;
private StubEventPublisher eventPublisher;

@BeforeEach
void setUp() {
memberRepository = new StubMemberRepository(MemberFixture.member());
Member member = MemberFixture.member();
memberRepository = new StubMemberRepository(member);
linkRepository = new FakeLinkRepository();
linkBundleRepository = new FakeLinkBundleRepository(LinkBundleFixture.linkBundle(member));
eventPublisher = new StubEventPublisher();
linkService = new LinkService(memberRepository, linkRepository, eventPublisher);
linkService = new LinkService(memberRepository, linkRepository, linkBundleRepository,
eventPublisher);
}

@Test
@DisplayName("성공: 링크 저장됨")
void createLink() {
//given
CreateLinkCommand command = new CreateLinkCommand(1L,
"https://hseong.tistory.com/", "내 블로그");
1L, "https://hseong.tistory.com/", "내 블로그");

//when
CreateLinkResponse response = linkService.createLink(command);
Expand All @@ -51,7 +58,7 @@ void createLink() {
void createLink_ThenPublishCreateLinkEvent() {
//given
CreateLinkCommand command = new CreateLinkCommand(1L,
"https://hseong.tistory.com/", "내 블로그");
1L, "https://hseong.tistory.com/", "내 블로그");

//when
CreateLinkResponse response = linkService.createLink(command);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class FakeLinkBundleRepository implements LinkBundleRepository {

private final Map<Long, LinkBundle> memory = new HashMap<>();

public FakeLinkBundleRepository(LinkBundle... linkBundles) {
for (LinkBundle linkBundle : linkBundles) {
memory.put(getNextId(), linkBundle);
}
}

@Override
public Long save(LinkBundle linkBundle) {
long nextId = getNextId();
Expand All @@ -22,16 +29,21 @@ public Long save(LinkBundle linkBundle) {
@Override
public void updateDefaultBundleFalse(Member member) {
List<LinkBundle> defaultLinkBundle = memory.values().stream()
.filter(linkBundle -> linkBundle.isDefault() && linkBundle.getMember().equals(member))
.filter(linkBundle -> linkBundle.isDefault() && linkBundle.getMemberId().equals(member.getMemberId()))
.toList();
defaultLinkBundle.forEach(lb -> {
memory.remove(lb.getLinkBundleId());
memory.put(lb.getLinkBundleId(),
new LinkBundle(lb.getDescription(), false, lb.getMember()));
new LinkBundle(lb.getDescription(), false, member));
});
}

private long getNextId() {
return memory.keySet().size() + 1;
}

@Override
public Optional<LinkBundle> findById(Long linkBundleId) {
return memory.values().stream().findFirst();
}
}
15 changes: 15 additions & 0 deletions src/test/java/com/seong/shoutlink/fixture/LinkBundleFixture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.seong.shoutlink.fixture;

import com.seong.shoutlink.domain.linkbundle.LinkBundle;
import com.seong.shoutlink.domain.member.Member;

public final class LinkBundleFixture {

public static final long LINK_BUNDLE_ID = 1L;
public static final String DESCRIPTION = "기본 분류";
public static final boolean IS_DEFAULT = true;

public static LinkBundle linkBundle(Member member) {
return new LinkBundle(LINK_BUNDLE_ID, DESCRIPTION, IS_DEFAULT, member.getMemberId());
}
}
2 changes: 2 additions & 0 deletions src/test/java/com/seong/shoutlink/fixture/LinkFixture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package com.seong.shoutlink.fixture;public class LinkFixture {
}
Loading