diff --git a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java index 6b5d5ede2..4fdfccc38 100644 --- a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckCommandPersistenceAdapter.java @@ -1,7 +1,7 @@ package konkuk.thip.attendancecheck.adapter.out.persistence; import konkuk.thip.attendancecheck.adapter.out.mapper.AttendanceCheckMapper; -import konkuk.thip.attendancecheck.adapter.out.persistence.repository.AttendanceCheckRepository; +import konkuk.thip.attendancecheck.adapter.out.persistence.repository.AttendanceCheckJpaRepository; import konkuk.thip.attendancecheck.application.port.out.AttendanceCheckCommandPort; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -10,7 +10,7 @@ @RequiredArgsConstructor public class AttendanceCheckCommandPersistenceAdapter implements AttendanceCheckCommandPort { - private final AttendanceCheckRepository attendanceCheckRepository; + private final AttendanceCheckJpaRepository attendanceCheckJpaRepository; private final AttendanceCheckMapper attendanceCheckMapper; } diff --git a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckQueryPersistenceAdapter.java index b920227ec..d092e1b2c 100644 --- a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/AttendanceCheckQueryPersistenceAdapter.java @@ -1,7 +1,7 @@ package konkuk.thip.attendancecheck.adapter.out.persistence; import konkuk.thip.attendancecheck.adapter.out.mapper.AttendanceCheckMapper; -import konkuk.thip.attendancecheck.adapter.out.persistence.repository.AttendanceCheckRepository; +import konkuk.thip.attendancecheck.adapter.out.persistence.repository.AttendanceCheckJpaRepository; import konkuk.thip.attendancecheck.application.port.out.AttendanceCheckQueryPort; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -10,7 +10,7 @@ @RequiredArgsConstructor public class AttendanceCheckQueryPersistenceAdapter implements AttendanceCheckQueryPort { - private final AttendanceCheckRepository jpaRepository; + private final AttendanceCheckJpaRepository jpaRepository; private final AttendanceCheckMapper attendanceCheckMapper; } diff --git a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckRepository.java b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckJpaRepository.java similarity index 67% rename from src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckRepository.java rename to src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckJpaRepository.java index e05af0e34..4d05c91c3 100644 --- a/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckRepository.java +++ b/src/main/java/konkuk/thip/attendancecheck/adapter/out/persistence/repository/AttendanceCheckJpaRepository.java @@ -3,5 +3,5 @@ import konkuk.thip.attendancecheck.adapter.out.jpa.AttendanceCheckJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface AttendanceCheckRepository extends JpaRepository { +public interface AttendanceCheckJpaRepository extends JpaRepository { } diff --git a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java index a4650b415..6d94870e1 100644 --- a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java +++ b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java @@ -42,11 +42,10 @@ public enum ErrorCode implements ResponseCode { /** * 75000 : follow error */ - FOLLOW_NOT_FOUND(HttpStatus.NOT_FOUND, 75001, "존재하지 않는 FOLLOW 입니다."), - USER_ALREADY_UNFOLLOWED(HttpStatus.BAD_REQUEST, 75002, "이미 언팔로우한 사용자입니다."), - USER_CANNOT_FOLLOW_SELF(HttpStatus.BAD_REQUEST, 75003, "사용자는 자신을 팔로우할 수 없습니다."), - - + FOLLOW_NOT_FOUND(HttpStatus.NOT_FOUND, 75000, "존재하지 않는 FOLLOW 입니다."), + USER_ALREADY_UNFOLLOWED(HttpStatus.BAD_REQUEST, 75001, "이미 언팔로우한 사용자입니다."), + USER_CANNOT_FOLLOW_SELF(HttpStatus.BAD_REQUEST, 75002, "사용자는 자신을 팔로우할 수 없습니다."), + FOLLOW_COUNT_IS_ZERO(HttpStatus.BAD_REQUEST, 75003, "사용자의 팔로우 수가 0일때는 언팔로우는 불가능합니다."), /** * 80000 : book error diff --git a/src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java b/src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java index 712a40dd6..9feef8915 100644 --- a/src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java +++ b/src/main/java/konkuk/thip/room/adapter/in/web/response/RoomGetMemberListResponse.java @@ -15,6 +15,6 @@ public record MemberSearchResult( String nickname, String imageUrl, String alias, - int subscriberCount + int followerCount ) {} } \ No newline at end of file diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java index 624f221de..2ed339ac2 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java @@ -6,7 +6,7 @@ import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.mapper.RoomMapper; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.room.application.port.out.RoomCommandPort; import konkuk.thip.room.domain.Room; diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java index 6ef187ef6..c58543572 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java @@ -4,7 +4,7 @@ import konkuk.thip.common.exception.code.ErrorCode; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.mapper.RoomParticipantMapper; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; import konkuk.thip.room.domain.RoomParticipant; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/CategoryJpaRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java similarity index 81% rename from src/main/java/konkuk/thip/room/adapter/out/persistence/repository/CategoryJpaRepository.java rename to src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java index 7997f2b51..43281a3bf 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/CategoryJpaRepository.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/category/CategoryJpaRepository.java @@ -1,4 +1,4 @@ -package konkuk.thip.room.adapter.out.persistence.repository; +package konkuk.thip.room.adapter.out.persistence.repository.category; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomParticipantJpaRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java similarity index 86% rename from src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomParticipantJpaRepository.java rename to src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java index 2db2ed018..bcc0e88ad 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/RoomParticipantJpaRepository.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java @@ -1,4 +1,4 @@ -package konkuk.thip.room.adapter.out.persistence.repository; +package konkuk.thip.room.adapter.out.persistence.repository.roomparticipant; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java b/src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java index 579d8d38f..86ed17650 100644 --- a/src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java +++ b/src/main/java/konkuk/thip/room/application/service/RoomGetMemberListService.java @@ -3,12 +3,11 @@ import konkuk.thip.room.adapter.in.web.response.RoomGetMemberListResponse; import konkuk.thip.room.application.port.in.RoomGetMemberListUseCase; import konkuk.thip.room.application.port.out.RoomCommandPort; +import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; import konkuk.thip.room.domain.Room; -import konkuk.thip.user.application.port.out.FollowingQueryPort; +import konkuk.thip.room.domain.RoomParticipant; import konkuk.thip.user.application.port.out.UserCommandPort; -import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; import konkuk.thip.user.domain.User; -import konkuk.thip.room.domain.RoomParticipant; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +22,6 @@ public class RoomGetMemberListService implements RoomGetMemberListUseCase { private final RoomCommandPort roomCommandPort; private final RoomParticipantCommandPort roomParticipantCommandPort; private final UserCommandPort userCommandPort; - private final FollowingQueryPort followingQueryPort; @Override @Transactional(readOnly = true) @@ -35,29 +33,26 @@ public RoomGetMemberListResponse getRoomMemberList(Long roomId) { // 2. 방 참여자(UserRoom) 전체 조회 List roomParticipants = roomParticipantCommandPort.findAllByRoomId(room.getId()); - // 3. 참여자 userId 목록 추출 List userIds = roomParticipants.stream() .map(RoomParticipant::getUserId) .toList(); - // 4. 배치 쿼리로 유저 정보, 팔로워 수 조회 + // 4. 배치 쿼리로 유저 정보만 조회 Map userMap = userCommandPort.findByIds(userIds); - Map subscriberCountMap = followingQueryPort.countByFollowingUserIds(userIds); - // 5. 각 userRoom에 대해 DTO 조립 + // 5. 각 roomParticipant에 대해 DTO 조립 List userList = roomParticipants.stream() - .map(userRoom -> { - Long userId = userRoom.getUserId(); + .map(roomParticipant -> { + Long userId = roomParticipant.getUserId(); User user = userMap.get(userId); - int subscriberCount = subscriberCountMap.getOrDefault(userId, 0); return RoomGetMemberListResponse.MemberSearchResult.builder() .userId(userId) .nickname(user.getNickname()) .imageUrl(user.getAlias().getImageUrl()) .alias(user.getAlias().getValue()) - .subscriberCount(subscriberCount) + .followerCount(user.getFollowerCount()) .build(); }) .toList(); diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java index 9335486f4..9c923a4a9 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/UserFollowersResponse.java @@ -13,22 +13,14 @@ public record UserFollowersResponse( boolean isFirst, boolean isLast ) { + @Builder public record Follower( Long userId, String nickname, String profileImageUrl, String aliasName, - Integer followingCount + Integer followerCount ){ - public static Follower of(Long userId, String nickname, String profileImageUrl, String aliasName, Integer followingCount) { - return new Follower( - userId, - nickname, - profileImageUrl, - aliasName, - followingCount - ); - } } } diff --git a/src/main/java/konkuk/thip/user/adapter/out/jpa/FollowingJpaEntity.java b/src/main/java/konkuk/thip/user/adapter/out/jpa/FollowingJpaEntity.java index c254926d8..c457388a0 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/jpa/FollowingJpaEntity.java +++ b/src/main/java/konkuk/thip/user/adapter/out/jpa/FollowingJpaEntity.java @@ -21,7 +21,7 @@ public class FollowingJpaEntity extends BaseJpaEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") - private UserJpaEntity followerUserJpaEntity; + private UserJpaEntity userJpaEntity; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "following_user_id") diff --git a/src/main/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntity.java b/src/main/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntity.java index a58e35c4c..47ec8d4ed 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntity.java +++ b/src/main/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntity.java @@ -27,6 +27,9 @@ public class UserJpaEntity extends BaseJpaEntity { @Column(name = "oauth2_id", length = 50, nullable = false) private String oauth2Id; + @Builder.Default + private Integer followerCount = 0; // 팔로워 수 + @Enumerated(EnumType.STRING) @Column(nullable = false) private UserRole role; @@ -35,4 +38,8 @@ public class UserJpaEntity extends BaseJpaEntity { @JoinColumn(name = "user_alias_id", nullable = false) private AliasJpaEntity aliasForUserJpaEntity; + public void updateFollowerCount(int followerCount) { + this.followerCount = followerCount; + } + } \ No newline at end of file diff --git a/src/main/java/konkuk/thip/user/adapter/out/mapper/FollowingMapper.java b/src/main/java/konkuk/thip/user/adapter/out/mapper/FollowingMapper.java index ab64c1f36..8063e2c9d 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/mapper/FollowingMapper.java +++ b/src/main/java/konkuk/thip/user/adapter/out/mapper/FollowingMapper.java @@ -10,7 +10,7 @@ public class FollowingMapper { public FollowingJpaEntity toJpaEntity(UserJpaEntity followerUserJpaEntity, UserJpaEntity followingUserJpaEntity) { return FollowingJpaEntity.builder() - .followerUserJpaEntity(followerUserJpaEntity) + .userJpaEntity(followerUserJpaEntity) .followingUserJpaEntity(followingUserJpaEntity) .build(); } @@ -18,7 +18,7 @@ public FollowingJpaEntity toJpaEntity(UserJpaEntity followerUserJpaEntity, UserJ public Following toDomainEntity(FollowingJpaEntity followingJpaEntity) { return Following.builder() .id(followingJpaEntity.getFollowingId()) - .followerUserId(followingJpaEntity.getFollowerUserJpaEntity().getUserId()) + .userId(followingJpaEntity.getUserJpaEntity().getUserId()) .followingUserId(followingJpaEntity.getFollowingUserJpaEntity().getUserId()) .createdAt(followingJpaEntity.getCreatedAt()) .modifiedAt(followingJpaEntity.getModifiedAt()) diff --git a/src/main/java/konkuk/thip/user/adapter/out/mapper/UserMapper.java b/src/main/java/konkuk/thip/user/adapter/out/mapper/UserMapper.java index 4d7fd43a4..1476860d9 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/mapper/UserMapper.java +++ b/src/main/java/konkuk/thip/user/adapter/out/mapper/UserMapper.java @@ -16,6 +16,7 @@ public UserJpaEntity toJpaEntity(User user, AliasJpaEntity aliasJpaEntity) { .imageUrl(user.getAlias().getImageUrl()) .role(UserRole.from(user.getUserRole())) .oauth2Id(user.getOauth2Id()) + .followerCount(user.getFollowerCount()) .aliasForUserJpaEntity(aliasJpaEntity) .build(); } @@ -26,6 +27,7 @@ public User toDomainEntity(UserJpaEntity userJpaEntity) { .nickname(userJpaEntity.getNickname()) .userRole(userJpaEntity.getRole().getType()) .oauth2Id(userJpaEntity.getOauth2Id()) + .followerCount(userJpaEntity.getFollowerCount()) .alias(Alias.from(userJpaEntity.getAliasForUserJpaEntity().getValue())) .createdAt(userJpaEntity.getCreatedAt()) .modifiedAt(userJpaEntity.getModifiedAt()) diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingCommandPersistenceAdapter.java index 3e289b6cf..e7025639a 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingCommandPersistenceAdapter.java @@ -4,10 +4,13 @@ import konkuk.thip.user.adapter.out.jpa.FollowingJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.mapper.FollowingMapper; -import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; +import konkuk.thip.user.adapter.out.mapper.UserMapper; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; import konkuk.thip.user.application.port.out.FollowingCommandPort; import konkuk.thip.user.domain.Following; +import konkuk.thip.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -22,8 +25,10 @@ public class FollowingCommandPersistenceAdapter implements FollowingCommandPort private final FollowingJpaRepository followingJpaRepository; private final UserJpaRepository userJpaRepository; + private final AliasJpaRepository aliasJpaRepository; private final FollowingMapper followingMapper; + private final UserMapper userMapper; @Override //ACTIVE, INACTIVE 모두 조회 public Optional findByUserIdAndTargetUserId(Long userId, Long targetUserId) { @@ -32,21 +37,32 @@ public Optional findByUserIdAndTargetUserId(Long userId, Long targetU } @Override - public void save(Following following) { // insert용 - UserJpaEntity userJpaEntity = userJpaRepository.findById(following.getFollowerUserId()).orElseThrow( + public void save(Following following, User targetUser) { // insert용 + UserJpaEntity userJpaEntity = userJpaRepository.findById(following.getUserId()).orElseThrow( () -> new EntityNotFoundException(USER_NOT_FOUND)); - UserJpaEntity targetUser = userJpaRepository.findById(following.getFollowingUserId()).orElseThrow( - () -> new EntityNotFoundException(USER_NOT_FOUND)); + UserJpaEntity targetUserJpaEntity = updateUserFollowerCount(targetUser); + followingJpaRepository.save(followingMapper.toJpaEntity(userJpaEntity, targetUserJpaEntity)); - followingJpaRepository.save(followingMapper.toJpaEntity(userJpaEntity, targetUser)); } @Override - public void updateStatus(Following following) { // 상태변경 용 - FollowingJpaEntity entity = followingJpaRepository.findByUserAndTargetUser(following.getFollowerUserId(), following.getFollowingUserId()) + public void updateStatus(Following following, User targetUser) { // 상태변경 용 + updateUserFollowerCount(targetUser); + + FollowingJpaEntity entity = followingJpaRepository.findByUserAndTargetUser(following.getUserId(), following.getFollowingUserId()) .orElseThrow(() -> new EntityNotFoundException(FOLLOW_NOT_FOUND)); entity.setStatus(following.getStatus()); } + + private UserJpaEntity updateUserFollowerCount(User targetUser) { + UserJpaEntity userJpaEntity = userJpaRepository.findById(targetUser.getId()).orElseThrow( + () -> new EntityNotFoundException(USER_NOT_FOUND) + ); + + userJpaEntity.updateFollowerCount(targetUser.getFollowerCount()); + userJpaRepository.save(userJpaEntity); + return userJpaEntity; + } } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingQueryPersistenceAdapter.java index 25ab18ddf..278f7e3c2 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/FollowingQueryPersistenceAdapter.java @@ -11,7 +11,6 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Map; @Repository @RequiredArgsConstructor @@ -19,42 +18,39 @@ public class FollowingQueryPersistenceAdapter implements FollowingQueryPort { private final FollowingJpaRepository followingJpaRepository; - @Override - public Map countByFollowingUserIds(List userIds) { - return followingJpaRepository.countByFollowingUserIds(userIds); - } - @Override public UserFollowersResponse getFollowersByUserId(Long userId, String cursor, int size) { LocalDateTime nextCursor = null; if (cursor != null && !cursor.isBlank()) { - nextCursor = DateUtil.parseDateTime(cursor); + nextCursor = DateUtil.parseDateTime(cursor); } List followerEntities = followingJpaRepository.findFollowersByUserIdBeforeCreatedAt(userId, nextCursor, size); List followers = followerEntities.stream() - .map(FollowingJpaEntity::getFollowerUserJpaEntity) // 팔로워 사용자 + .map(FollowingJpaEntity::getUserJpaEntity) // 팔로워 사용자 .toList(); - Map followingCountMap = countByFollowingUserIds( - followers.stream().map(UserJpaEntity::getUserId).toList() - ); - List followerList = followers.stream() - .map(follower -> UserFollowersResponse.Follower.of(follower.getUserId(), follower.getNickname(), follower.getAliasForUserJpaEntity().getImageUrl(), follower.getAliasForUserJpaEntity().getValue(), followingCountMap.getOrDefault(follower.getUserId(), 0))) + .map(follower -> UserFollowersResponse.Follower.builder() + .userId(follower.getUserId()) + .nickname(follower.getNickname()) + .profileImageUrl(follower.getAliasForUserJpaEntity().getImageUrl()) + .aliasName(follower.getAliasForUserJpaEntity().getValue()) + .followerCount(follower.getFollowerCount()) + .build()) .toList(); boolean isLast = followerEntities.size() < size; - nextCursor = isLast ? null : + nextCursor = isLast ? null : followerEntities.get(followerEntities.size() - 1).getCreatedAt(); return UserFollowersResponse.builder() .followerList(followerList) .size(followerList.size()) .nextCursor(nextCursor) - .isFirst(cursor == null) // cursor가 null이면 첫 페이지 + .isFirst(cursor == null) // cursor가 null이면 첫 페이지 .isLast(isLast) .build(); } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserCommandPersistenceAdapter.java index b87374d06..98075a878 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserCommandPersistenceAdapter.java @@ -4,7 +4,7 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.mapper.UserMapper; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.user.application.port.out.UserCommandPort; import konkuk.thip.user.domain.User; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java index 5d4980975..d05f06384 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java @@ -1,7 +1,7 @@ package konkuk.thip.user.adapter.out.persistence; import konkuk.thip.user.adapter.out.mapper.UserMapper; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.user.application.port.in.dto.UserViewAliasChoiceResult; import konkuk.thip.user.application.port.out.UserQueryPort; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasJpaRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasJpaRepository.java similarity index 82% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasJpaRepository.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasJpaRepository.java index 417f471ab..96829e2f8 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasJpaRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasJpaRepository.java @@ -1,4 +1,4 @@ -package konkuk.thip.user.adapter.out.persistence.repository; +package konkuk.thip.user.adapter.out.persistence.repository.alias; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepository.java similarity index 72% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepository.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepository.java index 0a82932db..d0518fa08 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepository.java @@ -1,4 +1,4 @@ -package konkuk.thip.user.adapter.out.persistence.repository; +package konkuk.thip.user.adapter.out.persistence.repository.alias; import konkuk.thip.user.application.port.in.dto.UserViewAliasChoiceResult; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepositoryImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepositoryImpl.java similarity index 95% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepositoryImpl.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepositoryImpl.java index e36286976..b1073de6d 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/AliasQueryRepositoryImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/alias/AliasQueryRepositoryImpl.java @@ -1,4 +1,4 @@ -package konkuk.thip.user.adapter.out.persistence.repository; +package konkuk.thip.user.adapter.out.persistence.repository.alias; import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java index 77957e69a..9b50430d9 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java @@ -49,7 +49,7 @@ public Optional findByUserAndTargetUser(Long userId, Long ta FollowingJpaEntity followingJpaEntity = jpaQueryFactory .selectFrom(following) - .where(following.followerUserJpaEntity.userId.eq(userId) + .where(following.userJpaEntity.userId.eq(userId) .and(following.followingUserJpaEntity.userId.eq(targetUserId))) .fetchOne(); @@ -72,8 +72,8 @@ public List findFollowersByUserIdBeforeCreatedAt(Long userId return jpaQueryFactory .selectFrom(following) - .join(following.followerUserJpaEntity, user).fetchJoin() // N+1 문제 방지를 위해 fetchJoin - .join(user.aliasForUserJpaEntity, alias).fetchJoin() + .leftJoin(following.userJpaEntity, user).fetchJoin() // N+1 문제 방지를 위해 fetchJoin + .leftJoin(user.aliasForUserJpaEntity, alias).fetchJoin() .where(condition) .orderBy(following.createdAt.desc()) .limit(size) diff --git a/src/main/java/konkuk/thip/user/application/port/out/FollowingCommandPort.java b/src/main/java/konkuk/thip/user/application/port/out/FollowingCommandPort.java index 7f7ad8ac8..9b423c452 100644 --- a/src/main/java/konkuk/thip/user/application/port/out/FollowingCommandPort.java +++ b/src/main/java/konkuk/thip/user/application/port/out/FollowingCommandPort.java @@ -1,6 +1,7 @@ package konkuk.thip.user.application.port.out; import konkuk.thip.user.domain.Following; +import konkuk.thip.user.domain.User; import java.util.Optional; @@ -8,7 +9,7 @@ public interface FollowingCommandPort { Optional findByUserIdAndTargetUserId(Long userId, Long targetUserId); - void save(Following following); + void save(Following following, User targetUser); - void updateStatus(Following following); + void updateStatus(Following following, User targetUser); } diff --git a/src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java b/src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java index f96c09d3e..cfaa74bc3 100644 --- a/src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java +++ b/src/main/java/konkuk/thip/user/application/port/out/FollowingQueryPort.java @@ -2,12 +2,7 @@ import konkuk.thip.user.adapter.in.web.response.UserFollowersResponse; -import java.util.List; -import java.util.Map; - public interface FollowingQueryPort { - Map countByFollowingUserIds(List userIds); - UserFollowersResponse getFollowersByUserId(Long userId, String cursor, int size); } diff --git a/src/main/java/konkuk/thip/user/application/service/following/UserFollowService.java b/src/main/java/konkuk/thip/user/application/service/following/UserFollowService.java index c04815b3e..85894d197 100644 --- a/src/main/java/konkuk/thip/user/application/service/following/UserFollowService.java +++ b/src/main/java/konkuk/thip/user/application/service/following/UserFollowService.java @@ -4,7 +4,9 @@ import konkuk.thip.user.application.port.in.UserFollowUsecase; import konkuk.thip.user.application.port.in.dto.UserFollowCommand; import konkuk.thip.user.application.port.out.FollowingCommandPort; +import konkuk.thip.user.application.port.out.UserCommandPort; import konkuk.thip.user.domain.Following; +import konkuk.thip.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,6 +22,7 @@ public class UserFollowService implements UserFollowUsecase { private final FollowingCommandPort followingCommandPort; + private final UserCommandPort userCommandPort; @Override @Transactional @@ -31,17 +34,20 @@ public Boolean changeFollowingState(UserFollowCommand followCommand) { validateParams(userId, targetUserId); Optional optionalFollowing = followingCommandPort.findByUserIdAndTargetUserId(userId, targetUserId); + User targetUser = userCommandPort.findById(targetUserId); if (optionalFollowing.isPresent()) { // 이미 팔로우 관계가 존재하는 경우 Following following = optionalFollowing.get(); boolean isFollowing = following.changeFollowingState(type); - followingCommandPort.updateStatus(following); + targetUser.updateFollowerCount(isFollowing); + followingCommandPort.updateStatus(following, targetUser); return isFollowing; } else { // 팔로우 관계가 존재하지 않는 경우 if (!type) { throw new InvalidStateException(USER_ALREADY_UNFOLLOWED); // 언팔로우 요청인데 팔로우 관계가 존재하지 않으므로 이미 언팔로우 상태 } - followingCommandPort.save(Following.withoutId(userId, targetUserId)); + targetUser.increaseFollowerCount(); + followingCommandPort.save(Following.withoutId(userId, targetUserId), targetUser); return true; // 새로 팔로우한 경우 } } diff --git a/src/main/java/konkuk/thip/user/domain/Following.java b/src/main/java/konkuk/thip/user/domain/Following.java index 060b9207d..6ffa7efb2 100644 --- a/src/main/java/konkuk/thip/user/domain/Following.java +++ b/src/main/java/konkuk/thip/user/domain/Following.java @@ -15,13 +15,13 @@ public class Following extends BaseDomainEntity { private Long id; - private Long followerUserId; + private Long userId; private Long followingUserId; public static Following withoutId(Long userId, Long followingUserId) { return Following.builder() - .followerUserId(userId) + .userId(userId) .followingUserId(followingUserId) .status(StatusType.ACTIVE) .build(); diff --git a/src/main/java/konkuk/thip/user/domain/User.java b/src/main/java/konkuk/thip/user/domain/User.java index 3de8ab730..6a7494782 100644 --- a/src/main/java/konkuk/thip/user/domain/User.java +++ b/src/main/java/konkuk/thip/user/domain/User.java @@ -1,6 +1,8 @@ package konkuk.thip.user.domain; import konkuk.thip.common.entity.BaseDomainEntity; +import konkuk.thip.common.exception.InvalidStateException; +import konkuk.thip.common.exception.code.ErrorCode; import lombok.Getter; import lombok.experimental.SuperBuilder; @@ -16,6 +18,8 @@ public class User extends BaseDomainEntity { private String oauth2Id; + private Integer followerCount; // 팔로워 수 + private Alias alias; public static User withoutId(String nickname, String userRole, String oauth2Id, Alias alias) { @@ -24,8 +28,28 @@ public static User withoutId(String nickname, String userRole, String oauth2Id, .nickname(nickname) .userRole(userRole) .oauth2Id(oauth2Id) + .followerCount(0) .alias(alias) .build(); } + public void updateFollowerCount(boolean isFollowing) { + if (isFollowing) { + increaseFollowerCount(); + } else { + decreaseFollowerCount(); + } + } + + public void increaseFollowerCount() { + followerCount++; + } + + private void decreaseFollowerCount() { + if(followerCount == 0) { + throw new InvalidStateException(ErrorCode.FOLLOW_COUNT_IS_ZERO); + } + followerCount--; + } + } diff --git a/src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java b/src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java index 534e55fa2..33919e4ce 100644 --- a/src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java +++ b/src/test/java/konkuk/thip/book/adapter/in/web/BookChangeSavedControllerTest.java @@ -12,7 +12,7 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java b/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java index 2f67b25c8..c10dcdc3f 100644 --- a/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java +++ b/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java @@ -8,13 +8,13 @@ import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import konkuk.thip.feed.adapter.out.jpa.FeedJpaEntity; import konkuk.thip.feed.adapter.out.persistence.FeedJpaRepository; import konkuk.thip.saved.adapter.out.jpa.SavedBookJpaEntity; diff --git a/src/test/java/konkuk/thip/book/adapter/in/web/BookMostSearchedBooksControllerTest.java b/src/test/java/konkuk/thip/book/adapter/in/web/BookMostSearchedBooksControllerTest.java index 7856eb5e1..06cead4ee 100644 --- a/src/test/java/konkuk/thip/book/adapter/in/web/BookMostSearchedBooksControllerTest.java +++ b/src/test/java/konkuk/thip/book/adapter/in/web/BookMostSearchedBooksControllerTest.java @@ -7,7 +7,7 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/konkuk/thip/book/adapter/in/web/BookQueryControllerTest.java b/src/test/java/konkuk/thip/book/adapter/in/web/BookQueryControllerTest.java index d0c2eb0d5..142d5dc29 100644 --- a/src/test/java/konkuk/thip/book/adapter/in/web/BookQueryControllerTest.java +++ b/src/test/java/konkuk/thip/book/adapter/in/web/BookQueryControllerTest.java @@ -9,7 +9,7 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/konkuk/thip/common/util/TestEntityFactory.java b/src/test/java/konkuk/thip/common/util/TestEntityFactory.java index 8e93d6ef3..a964f4da2 100644 --- a/src/test/java/konkuk/thip/common/util/TestEntityFactory.java +++ b/src/test/java/konkuk/thip/common/util/TestEntityFactory.java @@ -140,7 +140,7 @@ public static CommentJpaEntity createComment(PostJpaEntity post, UserJpaEntity u public static FollowingJpaEntity createFollowing(UserJpaEntity followerUser,UserJpaEntity followingUser) { return FollowingJpaEntity.builder() - .followerUserJpaEntity(followerUser) + .userJpaEntity(followerUser) .followingUserJpaEntity(followingUser) .build(); } diff --git a/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java b/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java index cf91a064f..6f1d86a01 100644 --- a/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java +++ b/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java @@ -7,7 +7,7 @@ import konkuk.thip.feed.adapter.out.persistence.FeedJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java b/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java index d8c6ab03d..1c1037fc8 100644 --- a/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java +++ b/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java @@ -12,12 +12,12 @@ import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/record/adapter/in/web/RecordQueryControllerTest.java b/src/test/java/konkuk/thip/record/adapter/in/web/RecordQueryControllerTest.java index 96a53a5f2..8927a4a81 100644 --- a/src/test/java/konkuk/thip/record/adapter/in/web/RecordQueryControllerTest.java +++ b/src/test/java/konkuk/thip/record/adapter/in/web/RecordQueryControllerTest.java @@ -10,12 +10,12 @@ import konkuk.thip.record.adapter.out.persistence.repository.RecordJpaRepository; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.vote.adapter.out.jpa.VoteItemJpaEntity; import konkuk.thip.vote.adapter.out.jpa.VoteJpaEntity; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java index 4c60e9ea2..5b91b716a 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java @@ -7,12 +7,12 @@ import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java index 11933700c..1c56de3ed 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java @@ -6,12 +6,12 @@ import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java index 6ca7eb9f9..b7b4ffc2e 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java @@ -5,15 +5,16 @@ import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; -import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; +import konkuk.thip.user.adapter.out.jpa.UserRole; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -25,7 +26,8 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -72,9 +74,32 @@ void setUp() { AliasJpaEntity alias = TestEntityFactory.createLiteratureAlias(); aliasJpaRepository.save(alias); - user1 = userJpaRepository.save(TestEntityFactory.createUser(alias)); - user2 = userJpaRepository.save(TestEntityFactory.createUser(alias)); - user3 = userJpaRepository.save(TestEntityFactory.createUser(alias)); + user1 = userJpaRepository.save(UserJpaEntity.builder() + .nickname("테스터1") + .imageUrl("https://test1.img") + .oauth2Id("kakao_1") + .aliasForUserJpaEntity(alias) + .role(UserRole.USER) + .followerCount(2) // user1이 user2, user3를 팔로우 + .build()); + + user2 = userJpaRepository.save(UserJpaEntity.builder() + .nickname("테스터2") + .imageUrl("https://test2.img") + .oauth2Id("kakao_2") + .aliasForUserJpaEntity(alias) + .role(UserRole.USER) + .followerCount(1) // user2가 user3를 팔로우 + .build()); + + user3 = userJpaRepository.save(UserJpaEntity.builder() + .nickname("테스터3") + .imageUrl("https://test3.img") + .oauth2Id("kakao_3") + .aliasForUserJpaEntity(alias) + .role(UserRole.USER) + .followerCount(1) // user3가 user1을 팔로우 + .build()); book = bookJpaRepository.save(TestEntityFactory.createBook()); category = categoryJpaRepository.save(TestEntityFactory.createLiteratureCategory(alias)); @@ -125,17 +150,17 @@ void getRoomMemberList_success() throws Exception { .andExpect(jsonPath("$.data.userList[0].nickname").exists()) .andExpect(jsonPath("$.data.userList[0].imageUrl").exists()) .andExpect(jsonPath("$.data.userList[0].alias").exists()) - .andExpect(jsonPath("$.data.userList[0].subscriberCount").isNumber()) + .andExpect(jsonPath("$.data.userList[0].followerCount").isNumber()) .andExpect(jsonPath("$.data.userList[1].userId").value(user2.getUserId().intValue())) .andExpect(jsonPath("$.data.userList[1].nickname").exists()) .andExpect(jsonPath("$.data.userList[1].imageUrl").exists()) .andExpect(jsonPath("$.data.userList[1].alias").exists()) - .andExpect(jsonPath("$.data.userList[1].subscriberCount").isNumber()) + .andExpect(jsonPath("$.data.userList[1].followerCount").isNumber()) .andExpect(jsonPath("$.data.userList[2].userId").value(user3.getUserId().intValue())) .andExpect(jsonPath("$.data.userList[2].nickname").exists()) .andExpect(jsonPath("$.data.userList[2].imageUrl").exists()) .andExpect(jsonPath("$.data.userList[2].alias").exists()) - .andExpect(jsonPath("$.data.userList[2].subscriberCount").isNumber()); + .andExpect(jsonPath("$.data.userList[2].followerCount").isNumber()); } @Test @@ -153,7 +178,7 @@ void getRoomMemberList_empty() throws Exception { } @Test - @DisplayName("팔로워(구독자) 수가 올바르게 집계된다.") + @DisplayName("팔로워 수가 올바르게 집계된다.") void getRoomMemberList_subscriberCount() throws Exception { //given Long roomId = room1.getRoomId(); @@ -162,17 +187,17 @@ void getRoomMemberList_subscriberCount() throws Exception { ResultActions result = mockMvc.perform(get("/rooms/{roomId}/users", roomId)); //then - // user1: user3이 팔로우(1명) - // user2: user1이 팔로우(1명) - // user3: user1, user2가 팔로우(2명) + // user1이 팔로우하는 사람: user2, user3 (2명) + // user2가 팔로우하는 사람: user3 (1명) + // user3이 팔로우하는 사람: user1 (1명) result.andExpect(status().isOk()) - .andExpect(jsonPath("$.data.userList[?(@.userId==" + user1.getUserId() + ")].subscriberCount").value(contains(1))) - .andExpect(jsonPath("$.data.userList[?(@.userId==" + user2.getUserId() + ")].subscriberCount").value(contains(1))) - .andExpect(jsonPath("$.data.userList[?(@.userId==" + user3.getUserId() + ")].subscriberCount").value(contains(2))); + .andExpect(jsonPath("$.data.userList[?(@.userId==" + user1.getUserId() + ")].followerCount").value(contains(2))) + .andExpect(jsonPath("$.data.userList[?(@.userId==" + user2.getUserId() + ")].followerCount").value(contains(1))) + .andExpect(jsonPath("$.data.userList[?(@.userId==" + user3.getUserId() + ")].followerCount").value(contains(1))); } @Test - @DisplayName("팔로워가 한 명도 없는 사용자는 subscriberCount가 0으로 조회된다.") + @DisplayName("팔로워가 한 명도 없는 사용자는 followerCount가 0으로 조회된다.") void getRoomMemberList_noSubscriber() throws Exception { //given UserJpaEntity userNoFollower = userJpaRepository.save(TestEntityFactory.createUser(aliasJpaRepository.findAll().get(0))); @@ -184,6 +209,6 @@ void getRoomMemberList_noSubscriber() throws Exception { //then result.andExpect(status().isOk()) - .andExpect(jsonPath("$.data.userList[?(@.userId==" + userNoFollower.getUserId() + ")].subscriberCount").value(contains(0))); + .andExpect(jsonPath("$.data.userList[?(@.userId==" + userNoFollower.getUserId() + ")].followerCount").value(contains(0))); } } \ No newline at end of file diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java index 2350811c0..80e5e1e53 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java @@ -8,12 +8,12 @@ import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import konkuk.thip.vote.adapter.out.jpa.VoteItemJpaEntity; import konkuk.thip.vote.adapter.out.jpa.VoteJpaEntity; import konkuk.thip.vote.adapter.out.persistence.repository.VoteItemJpaRepository; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java index 0dd68a4c2..3e2a8c575 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java @@ -8,12 +8,12 @@ import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java index d245ffb77..1ff8b70cb 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java @@ -7,12 +7,12 @@ import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.RoomParticipantJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomVerifyPasswordAPITest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomVerifyPasswordAPITest.java index 2feb00ef4..9e9c35a2c 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomVerifyPasswordAPITest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomVerifyPasswordAPITest.java @@ -6,11 +6,11 @@ import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.room.adapter.in.web.request.RoomVerifyPasswordRequest; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java index b612bb33e..45a045b83 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java @@ -6,11 +6,11 @@ import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.record.adapter.out.jpa.RecordJpaEntity; import konkuk.thip.record.adapter.out.persistence.repository.RecordJpaRepository; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java index f2fe82941..fdc7b5c19 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java @@ -4,11 +4,11 @@ import jakarta.persistence.PersistenceContext; import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; import konkuk.thip.common.util.TestEntityFactory; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.book.adapter.out.persistence.repository.BookJpaRepository; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java index a3a25d647..3915a7feb 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java @@ -4,11 +4,11 @@ import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; import konkuk.thip.book.adapter.out.persistence.repository.BookJpaRepository; import konkuk.thip.common.util.TestEntityFactory; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.vote.adapter.out.jpa.VoteJpaEntity; import konkuk.thip.vote.adapter.out.persistence.repository.VoteJpaRepository; diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowApiTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowApiTest.java index 3bf5ef372..130eee046 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowApiTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowApiTest.java @@ -1,14 +1,13 @@ package konkuk.thip.user.adapter.in.web; -import com.fasterxml.jackson.databind.ObjectMapper; import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.FollowingJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; -import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -33,9 +32,6 @@ class UserFollowApiTest { @Autowired private MockMvc mockMvc; - @Autowired - private ObjectMapper objectMapper; - @Autowired private UserJpaRepository userJpaRepository; @@ -58,7 +54,7 @@ void changeFollowingState_follow_then_unfollow() throws Exception { // 사용자 2명 저장 AliasJpaEntity alias = aliasJpaRepository.save(TestEntityFactory.createScienceAlias()); - UserJpaEntity user = userJpaRepository.save(UserJpaEntity.builder() + UserJpaEntity followingUser = userJpaRepository.save(UserJpaEntity.builder() .nickname("user100") .imageUrl("http://image") .oauth2Id("oauth2_user100") @@ -76,26 +72,32 @@ void changeFollowingState_follow_then_unfollow() throws Exception { // 팔로우 요청 mockMvc.perform(post("/users/following/{followingUserId}", target.getUserId()) - .requestAttr("userId", user.getUserId()) + .requestAttr("userId", followingUser.getUserId()) .contentType(MediaType.APPLICATION_JSON) .content("{\"type\": true}")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.isFollowing").value(true)); // DB에 팔로우 상태가 ACTIVE로 저장되었는지 확인 - FollowingJpaEntity followEntity = followingJpaRepository.findByUserAndTargetUser(user.getUserId(), target.getUserId()).orElseThrow(); + FollowingJpaEntity followEntity = followingJpaRepository.findByUserAndTargetUser(followingUser.getUserId(), target.getUserId()).orElseThrow(); assertThat(followEntity.getStatus().name()).isEqualTo("ACTIVE"); + UserJpaEntity userJpaEntity = userJpaRepository.findById(target.getUserId()).orElseThrow(); + assertThat(userJpaEntity.getFollowerCount()).isEqualTo(1); // 팔로워 수 증가 확인 + // 언팔로우 요청 mockMvc.perform(post("/users/following/{followingUserId}", target.getUserId()) - .requestAttr("userId", user.getUserId()) + .requestAttr("userId", followingUser.getUserId()) .contentType(MediaType.APPLICATION_JSON) .content("{\"type\": false}")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.isFollowing").value(false)); // DB에 상태가 INACTIVE로 변경되었는지 확인 - FollowingJpaEntity updatedEntity = followingJpaRepository.findByUserAndTargetUser(user.getUserId(), target.getUserId()).orElseThrow(); + FollowingJpaEntity updatedEntity = followingJpaRepository.findByUserAndTargetUser(followingUser.getUserId(), target.getUserId()).orElseThrow(); assertThat(updatedEntity.getStatus().name()).isEqualTo("INACTIVE"); + + userJpaEntity = userJpaRepository.findById(target.getUserId()).orElseThrow(); + assertThat(userJpaEntity.getFollowerCount()).isEqualTo(0); // 팔로워 수 감소 확인 } } \ No newline at end of file diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowControllerTest.java index 16aec5cbf..74f4fda2f 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserFollowControllerTest.java @@ -31,12 +31,6 @@ class UserFollowControllerTest { @Autowired private ObjectMapper objectMapper; - private Map buildValidRequest() { - Map req = new HashMap<>(); - req.put("type", true); - return req; - } - private void assertBad(Map req, String msg) throws Exception { mockMvc.perform(post("/users/following/{followingUserId}", 2L) .requestAttr("userId", 1L) diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserGetFollowersApiTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserGetFollowersApiTest.java index 54a40820a..64deb6889 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserGetFollowersApiTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserGetFollowersApiTest.java @@ -4,7 +4,7 @@ import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.following.FollowingJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java index 61e839dea..085c7b178 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java @@ -7,7 +7,7 @@ import konkuk.thip.user.adapter.in.web.request.UserSignupRequest; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserVerifyNicknameControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserVerifyNicknameControllerTest.java index 72c5814fd..2be04fb61 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserVerifyNicknameControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserVerifyNicknameControllerTest.java @@ -6,7 +6,7 @@ import konkuk.thip.user.adapter.in.web.request.UserVerifyNicknameRequest; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserViewAliasChoiceControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserViewAliasChoiceControllerTest.java index 19fcbc3ce..571ccc3f3 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserViewAliasChoiceControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserViewAliasChoiceControllerTest.java @@ -4,10 +4,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import konkuk.thip.common.util.TestEntityFactory; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.user.adapter.in.web.response.UserViewAliasChoiceResponse; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java b/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java index 859f70d76..e847afb95 100644 --- a/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java +++ b/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java @@ -3,7 +3,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import konkuk.thip.common.util.TestEntityFactory; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/konkuk/thip/user/application/service/UserFollowServiceTest.java b/src/test/java/konkuk/thip/user/application/service/UserFollowServiceTest.java index 211c93fca..29447f007 100644 --- a/src/test/java/konkuk/thip/user/application/service/UserFollowServiceTest.java +++ b/src/test/java/konkuk/thip/user/application/service/UserFollowServiceTest.java @@ -1,11 +1,13 @@ package konkuk.thip.user.application.service; +import konkuk.thip.common.entity.StatusType; import konkuk.thip.common.exception.InvalidStateException; import konkuk.thip.user.application.port.in.dto.UserFollowCommand; import konkuk.thip.user.application.port.out.FollowingCommandPort; +import konkuk.thip.user.application.port.out.UserCommandPort; import konkuk.thip.user.application.service.following.UserFollowService; import konkuk.thip.user.domain.Following; -import konkuk.thip.common.entity.StatusType; +import konkuk.thip.user.domain.User; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -23,12 +25,14 @@ class UserFollowServiceTest { private FollowingCommandPort followingCommandPort; + private UserCommandPort userCommandPort; private UserFollowService userFollowService; @BeforeEach void setUp() { followingCommandPort = mock(FollowingCommandPort.class); - userFollowService = new UserFollowService(followingCommandPort); + userCommandPort = mock(UserCommandPort.class); + userFollowService = new UserFollowService(followingCommandPort, userCommandPort); } @Nested @@ -36,19 +40,22 @@ void setUp() { class Follow { @Test - @DisplayName("기존 inactive row가 존재하면 active로 변경") + @DisplayName("기존 inactive row가 존재하면 active로 변경 + followerCount 증가") void activate_existingFollowing() { // given Long userId = 1L, targetUserId = 2L; Following inactiveFollowing = Following.builder() .id(10L) - .followerUserId(userId) + .userId(userId) .followingUserId(targetUserId) .status(StatusType.INACTIVE) .build(); + User user = createUserWithFollowingCount(0); + when(followingCommandPort.findByUserIdAndTargetUserId(userId, targetUserId)) .thenReturn(Optional.of(inactiveFollowing)); + when(userCommandPort.findById(targetUserId)).thenReturn(user); UserFollowCommand command = new UserFollowCommand(userId, targetUserId, true); @@ -58,17 +65,21 @@ void activate_existingFollowing() { // then assertThat(result).isTrue(); assertThat(inactiveFollowing.getStatus()).isEqualTo(StatusType.ACTIVE); - verify(followingCommandPort).updateStatus(inactiveFollowing); + assertThat(user.getFollowerCount()).isEqualTo(1); // followerCount 증가 확인 + verify(followingCommandPort).updateStatus(inactiveFollowing, user); } @Test - @DisplayName("팔로우 관계가 존재하지 않으면 새로 생성") + @DisplayName("팔로우 관계가 존재하지 않으면 새로 생성 + followerCount 증가") void create_newFollowing() { // given Long userId = 1L, targetUserId = 2L; when(followingCommandPort.findByUserIdAndTargetUserId(userId, targetUserId)) .thenReturn(Optional.empty()); + User user = createUserWithFollowingCount(0); + when(userCommandPort.findById(targetUserId)).thenReturn(user); + UserFollowCommand command = new UserFollowCommand(userId, targetUserId, true); // when @@ -76,11 +87,13 @@ void create_newFollowing() { // then assertThat(result).isTrue(); + assertThat(user.getFollowerCount()).isEqualTo(1); // followerCount 증가 확인 + ArgumentCaptor captor = ArgumentCaptor.forClass(Following.class); - verify(followingCommandPort).save(captor.capture()); + verify(followingCommandPort).save(captor.capture(), eq(user)); Following saved = captor.getValue(); - assertThat(saved.getFollowerUserId()).isEqualTo(userId); + assertThat(saved.getUserId()).isEqualTo(userId); assertThat(saved.getFollowingUserId()).isEqualTo(targetUserId); assertThat(saved.getStatus()).isEqualTo(StatusType.ACTIVE); } @@ -91,19 +104,22 @@ void create_newFollowing() { class Unfollow { @Test - @DisplayName("active row가 존재하면 inactive로 변경") + @DisplayName("active row가 존재하면 inactive로 변경 + followerCount 감소") void deactivate_existingFollowing() { // given Long userId = 1L, targetUserId = 2L; Following activeFollowing = Following.builder() .id(10L) - .followerUserId(userId) + .userId(userId) .followingUserId(targetUserId) .status(StatusType.ACTIVE) .build(); + User user = createUserWithFollowingCount(1); + when(followingCommandPort.findByUserIdAndTargetUserId(userId, targetUserId)) .thenReturn(Optional.of(activeFollowing)); + when(userCommandPort.findById(targetUserId)).thenReturn(user); UserFollowCommand command = new UserFollowCommand(userId, targetUserId, false); @@ -113,7 +129,8 @@ void deactivate_existingFollowing() { // then assertThat(result).isFalse(); assertThat(activeFollowing.getStatus()).isEqualTo(StatusType.INACTIVE); - verify(followingCommandPort).updateStatus(activeFollowing); + assertThat(user.getFollowerCount()).isEqualTo(0); // followerCount 감소 확인 + verify(followingCommandPort).updateStatus(activeFollowing, user); } @Test @@ -143,4 +160,15 @@ void cannot_follow_self() { .isInstanceOf(InvalidStateException.class) .hasMessageContaining(USER_CANNOT_FOLLOW_SELF.getMessage()); } + + private User createUserWithFollowingCount(int count) { + return User.builder() + .id(1L) + .nickname("tester") + .userRole("USER") + .oauth2Id("oauth-id") + .followerCount(count) + .alias(null) + .build(); + } } \ No newline at end of file diff --git a/src/test/java/konkuk/thip/user/domain/FollowingTest.java b/src/test/java/konkuk/thip/user/domain/FollowingTest.java index 099c0aabc..c4426ad7d 100644 --- a/src/test/java/konkuk/thip/user/domain/FollowingTest.java +++ b/src/test/java/konkuk/thip/user/domain/FollowingTest.java @@ -21,7 +21,7 @@ class Follow { @DisplayName("inactive 상태에서 follow 요청 → active로 변경") void follow_from_inactive() { Following following = Following.builder() - .followerUserId(1L) + .userId(1L) .followingUserId(2L) .status(StatusType.INACTIVE) .build(); @@ -36,7 +36,7 @@ void follow_from_inactive() { @DisplayName("이미 active 상태에서 follow 요청 → 예외 발생") void follow_from_active_should_throw() { Following following = Following.builder() - .followerUserId(1L) + .userId(1L) .followingUserId(2L) .status(StatusType.ACTIVE) .build(); @@ -55,7 +55,7 @@ class Unfollow { @DisplayName("active 상태에서 unfollow 요청 → inactive로 변경") void unfollow_from_active() { Following following = Following.builder() - .followerUserId(1L) + .userId(1L) .followingUserId(2L) .status(StatusType.ACTIVE) .build(); @@ -70,7 +70,7 @@ void unfollow_from_active() { @DisplayName("이미 inactive 상태에서 unfollow 요청 → 예외 발생") void unfollow_from_inactive_should_throw() { Following following = Following.builder() - .followerUserId(1L) + .userId(1L) .followingUserId(2L) .status(StatusType.INACTIVE) .build(); @@ -86,7 +86,7 @@ void unfollow_from_inactive_should_throw() { void create_following_should_be_active() { Following following = Following.withoutId(1L, 2L); - assertThat(following.getFollowerUserId()).isEqualTo(1L); + assertThat(following.getUserId()).isEqualTo(1L); assertThat(following.getFollowingUserId()).isEqualTo(2L); assertThat(following.getStatus()).isEqualTo(StatusType.ACTIVE); } diff --git a/src/test/java/konkuk/thip/vote/adapter/in/web/VoteCreateControllerTest.java b/src/test/java/konkuk/thip/vote/adapter/in/web/VoteCreateControllerTest.java index 684929776..879edb48a 100644 --- a/src/test/java/konkuk/thip/vote/adapter/in/web/VoteCreateControllerTest.java +++ b/src/test/java/konkuk/thip/vote/adapter/in/web/VoteCreateControllerTest.java @@ -6,12 +6,12 @@ import konkuk.thip.book.adapter.out.persistence.repository.BookJpaRepository; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; -import konkuk.thip.room.adapter.out.persistence.repository.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserRole; -import konkuk.thip.user.adapter.out.persistence.repository.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import konkuk.thip.vote.adapter.in.web.request.VoteCreateRequest; import konkuk.thip.vote.adapter.out.jpa.VoteItemJpaEntity;