Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,24 @@ public Optional<Member> findById(final Long id) {
return memberEntity.map(memberPersistenceMapper::toDomain);
}

@Override
public Optional<Member> findByIdWithFetchDepartment(Long id) {
Optional<MemberEntity> memberEntity = memberRepository.findByIdWithFetchDepartment(id);
return memberEntity.map(memberPersistenceMapper::toDomain);
}

@Override
public Optional<Member> findActiveMemberById(final Long id) {
Optional<MemberEntity> memberEntity = memberRepository.findByStatusAndMemberId(MemberStatus.ACTIVE, id);
return memberEntity.map(memberPersistenceMapper::toDomain);
}

@Override
public Optional<Member> findActiveMemberByIdWithFetchDepartment(Long id) {
Optional<MemberEntity> memberEntity = memberRepository.findActiveMemberByIdWithFetchDepartment(id);
return memberEntity.map(memberPersistenceMapper::toDomain);
}

@Override
public Optional<Member> findActiveMemberByNickname(final String nickname) {
Optional<MemberEntity> memberEntity = memberRepository.findActiveMemberByNickname(nickname);
Expand Down Expand Up @@ -85,7 +97,7 @@ public List<Member> findActiveManagers() {

@Override
public Page<Member> findAllMembers(final Pageable pageable) {
return memberRepository.findAllMembers(pageable).map(memberPersistenceMapper::toDomain);
return memberRepository.findAllMembersWithFetchDepartment(pageable).map(memberPersistenceMapper::toDomain);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "spring", uses = {MemberPersistenceMapper.class})
@Mapper(componentModel = "spring")
public interface DepartmentPersistenceMapper extends PersistenceMapper<DepartmentEntity, Department> {

@Mapping(source = "admin.memberId", target = "adminId")
@Mapping(target = "adminId", ignore = true)
@Mapping(source = "manager", target = "isManager")
Department toDomain(DepartmentEntity entity);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,64 @@
package clap.server.adapter.outbound.persistense.mapper;

import clap.server.adapter.outbound.persistense.entity.member.DepartmentEntity;
import clap.server.adapter.outbound.persistense.entity.member.MemberEntity;
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.domain.model.member.MemberInfo;
import org.hibernate.Hibernate;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.springframework.beans.factory.annotation.Autowired;

@Mapper(componentModel = "spring", uses = {DepartmentPersistenceMapper.class})
@Mapper(componentModel = "spring", uses = DepartmentPersistenceMapper.class)
public abstract class MemberPersistenceMapper {

@Autowired
protected DepartmentPersistenceMapper departmentPersistenceMapper;

@Mapping(source = "name", target = "memberInfo.name")
@Mapping(source = "email", target = "memberInfo.email")
@Mapping(source = "nickname", target = "memberInfo.nickname")
@Mapping(source = "role", target = "memberInfo.role")
@Mapping(source = "departmentRole", target = "memberInfo.departmentRole")
@Mapping(source = "department", target = "memberInfo.department")
@Mapping(source = "reviewer", target = "memberInfo.isReviewer")
@Mapping(source = "admin", target = "admin", qualifiedByName = "toDomain")
@Mapping(source = "createdAt", target = "createdAt")
@Mapping(source = "updatedAt", target = "updatedAt")
@Mapping(source = "memberId", target = "memberId")
@Mapping(target = "memberInfo", expression = "java(memberEntityToMemberInfo(entity))")
@Mapping(target = "department", expression = "java(mapDepartment(entity))")
@Mapping(target = "admin", ignore = true)
@Mapping(source = "entity.createdAt", target = "createdAt")
@Mapping(source = "entity.updatedAt", target = "updatedAt")
@Mapping(source = "entity.memberId", target = "memberId")
public abstract Member toDomain(MemberEntity entity);

protected MemberInfo memberEntityToMemberInfo(MemberEntity memberEntity) {
if (memberEntity == null) {
return null;
}

DepartmentEntity departmentEntity = memberEntity.getDepartment();
Department department = (departmentEntity != null && Hibernate.isInitialized(departmentEntity))
? departmentPersistenceMapper.toDomain(departmentEntity)
: null;

return MemberInfo.builder()
.name(memberEntity.getName())
.email(memberEntity.getEmail())
.nickname(memberEntity.getNickname())
.role(memberEntity.getRole())
.departmentRole(memberEntity.getDepartmentRole())
.isReviewer(memberEntity.isReviewer())
.department(department)
.build();
}

protected Department mapDepartment(MemberEntity entity) {
DepartmentEntity department = entity.getDepartment();
if (department == null) {
return null;
}

if (!Hibernate.isInitialized(department)) {
return null;
}

return departmentPersistenceMapper.toDomain(department);
}

@Mapping(source = "memberInfo.name", target = "name")
@Mapping(source = "memberInfo.email", target = "email")
@Mapping(source = "memberInfo.nickname", target = "nickname")
Expand All @@ -40,6 +72,7 @@ public abstract class MemberPersistenceMapper {
@Mapping(source = "memberId", target = "memberId")
public abstract MemberEntity toEntity(Member member);


@Named("toDomain")
protected Member toDomainAdmin(MemberEntity admin) {
if (admin == null) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class MemberCustomRepositoryImpl implements MemberCustomRepository {
private Page<MemberEntity> executeQueryWithPageable(Pageable pageable, BooleanBuilder whereClause, OrderSpecifier<?> orderSpecifier) {
List<MemberEntity> result = queryFactory
.selectFrom(memberEntity)
.leftJoin(memberEntity.department).fetchJoin()
.where(whereClause)
.orderBy(orderSpecifier)
.offset(pageable.getOffset())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import clap.server.adapter.outbound.persistense.entity.member.MemberEntity;
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -13,7 +15,13 @@
import java.util.Set;

@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Long>, MemberCustomRepository {
public interface MemberRepository extends JpaRepository<MemberEntity, Long>, MemberCustomRepository {
@Query("SELECT m FROM MemberEntity m LEFT JOIN FETCH m.department WHERE m.memberId = :id")
Optional<MemberEntity> findByIdWithFetchDepartment(Long id);

@Query("SELECT m FROM MemberEntity m LEFT JOIN FETCH m.department WHERE m.memberId = :id AND m.status='ACTIVE'")
Optional<MemberEntity> findActiveMemberByIdWithFetchDepartment(Long id);

List<MemberEntity> findByRoleAndStatus(MemberRole role, MemberStatus status);

Optional<MemberEntity> findByStatusAndMemberId(MemberStatus memberStatus, Long memberId);
Expand All @@ -26,7 +34,9 @@ public interface MemberRepository extends JpaRepository<MemberEntity, Long>, Me

List<MemberEntity> findByIsReviewerTrue();

List<MemberEntity> findAll(); // 전체 회원 조회
@Query(value = "SELECT DISTINCT m FROM MemberEntity m LEFT JOIN FETCH m.department",
countQuery = "SELECT COUNT(DISTINCT m) FROM MemberEntity m")
Page<MemberEntity> findAllMembersWithFetchDepartment(Pageable pageable);

Optional<MemberEntity> findByMemberIdAndIsReviewerTrue(Long memberId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ public List<TaskEntity> findTasksByFilter(Long processorId, List<TaskStatus> sta
BooleanBuilder builder = createTaskBoardFilter(processorId, statuses, untilDateTime, request);
return queryFactory
.selectFrom(taskEntity)
.leftJoin(taskEntity.requester).fetchJoin()
.leftJoin(taskEntity.requester.department).fetchJoin()
.where(builder)
.orderBy(taskEntity.processorOrder.asc())
.fetch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import clap.server.adapter.inbound.web.dto.common.PageResponse;
import org.springframework.data.domain.Pageable;

@Deprecated
public interface FindAllMembersUsecase {
PageResponse<RetrieveAllMemberResponse> findAllMembers(Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
public interface LoadMemberPort {
Optional<Member> findById(Long id);

Optional<Member> findByIdWithFetchDepartment(Long id);

Optional<Member> findActiveMemberById(Long id);

Optional<Member> findActiveMemberByIdWithFetchDepartment(Long id);

List<Member> findActiveManagers();

Optional<Member> findReviewerById(Long id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import clap.server.exception.ApplicationException;
import clap.server.exception.code.MemberErrorCode;
import lombok.RequiredArgsConstructor;
import org.hibernate.Hibernate;
import org.springframework.transaction.annotation.Transactional;

@ApplicationService
Expand All @@ -29,7 +28,6 @@ public void deleteMember(Long memberId) {
if (member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) {
managerInfoUpdatePolicy.validateNoRemainingTasks(member);
}
Hibernate.initialize(member.getDepartment());
member.softDelete();
commandMemberPort.save(member);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,32 @@
import clap.server.application.mapper.response.MemberResponseMapper;
import clap.server.application.port.inbound.admin.MemberDetailUsecase;
import clap.server.application.port.inbound.admin.UpdateMemberUsecase;
import clap.server.application.port.inbound.domain.MemberService;
import clap.server.application.port.outbound.member.CommandMemberPort;
import clap.server.application.port.outbound.member.LoadDepartmentPort;
import clap.server.application.port.outbound.member.LoadMemberPort;
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Department;
import clap.server.domain.model.member.Member;
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.DepartmentErrorCode;
import clap.server.exception.code.MemberErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@ApplicationService
@RequiredArgsConstructor
class ManageMemberService implements UpdateMemberUsecase, MemberDetailUsecase {
private final MemberService memberService;
private final LoadMemberPort loadMemberPort;
private final CommandMemberPort commandMemberPort;
private final LoadDepartmentPort loadDepartmentPort;
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;

@Override
@Transactional
public void updateMemberInfo(Long adminId, Long memberId, UpdateMemberRequest request) {
Member member = memberService.findById(memberId);
Member member = loadMemberPort.findByIdWithFetchDepartment(memberId).orElseThrow(
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));
Department department = loadDepartmentPort.findById(request.departmentId()).orElseThrow(() ->
new ApplicationException(DepartmentErrorCode.DEPARTMENT_NOT_FOUND));
managerInfoUpdatePolicy.validateDepartment(department, request.role());
Expand All @@ -46,7 +48,8 @@ public void updateMemberInfo(Long adminId, Long memberId, UpdateMemberRequest re
@Override
@Transactional(readOnly = true)
public MemberDetailsResponse getMemberDetail(Long memberId) {
Member member = memberService.findById(memberId);
Member member = loadMemberPort.findByIdWithFetchDepartment(memberId).orElseThrow(
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));;
return MemberResponseMapper.toMemberDetailsResponse(member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import clap.server.adapter.inbound.web.dto.member.response.MemberDetailInfoResponse;
import clap.server.adapter.inbound.web.dto.member.response.MemberProfileResponse;
import clap.server.application.port.inbound.domain.MemberService;
import clap.server.application.port.inbound.member.MemberDetailInfoUsecase;
import clap.server.application.port.inbound.member.MemberProfileUsecase;
import clap.server.application.port.outbound.member.LoadMemberPort;
import clap.server.common.annotation.architecture.ApplicationService;
import clap.server.domain.model.member.Member;
import clap.server.exception.ApplicationException;
import clap.server.exception.code.MemberErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -16,19 +18,21 @@
@ApplicationService
@RequiredArgsConstructor
class MemberInfoService implements MemberProfileUsecase , MemberDetailInfoUsecase {
private final MemberService memberService;
private final LoadMemberPort loadMemberPort;

@Override
@Transactional(readOnly = true)
public MemberProfileResponse getMemberProfile(Long memberId) {
Member member = memberService.findActiveMember(memberId);
Member member = loadMemberPort.findActiveMemberByIdWithFetchDepartment(memberId).orElseThrow(
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));
return toMemberProfileResponse(member);
}

@Override
@Transactional(readOnly = true)
public MemberDetailInfoResponse getMemberInfo(Long memberId) {
Member member = memberService.findActiveMember(memberId);
Member member = loadMemberPort.findActiveMemberByIdWithFetchDepartment(memberId).orElseThrow(
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));
return toMemberDetailInfoResponse(member);
}
}