Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pet 280 refactor : todo 조회 로직 리팩터링 #195

Merged
merged 9 commits into from
Dec 26, 2023
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.pawith.todoapplication.dto.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
import com.pawith.tododomain.entity.TodoNotification;

import java.time.LocalTime;
import java.util.Optional;
import java.util.function.Supplier;

@AllArgsConstructor
@Getter
public class TodoNotificationInfoResponse {
private Boolean isNotification;
@JsonInclude(JsonInclude.Include.NON_NULL)
private LocalTime notificationTime;
public record TodoNotificationInfoResponse(
Boolean isNotification,
@JsonInclude(JsonInclude.Include.NON_NULL) LocalTime notificationTime
) {
public static TodoNotificationInfoResponse of(Supplier<Optional<TodoNotification>> todoNotificationSupplier) {
return todoNotificationSupplier.get()
.map(todoNotification -> new TodoNotificationInfoResponse(true, todoNotification.getNotificationTime()))
.orElse(new TodoNotificationInfoResponse(false, null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private void cachingUserInfo(List<IncompleteTodoCountInfoDao> executionResult) {
.map(IncompleteTodoCountInfoDao::getUserId)
.filter(userId -> !valueOperator.contains(userId))
.toList();
userQueryService.findUserMapByIds(userIds)
userQueryService.findMapWithUserIdKeyByIds(userIds)
.forEach((userId, user) -> valueOperator.setWithExpire(userId, user.getNickname(), 1, TimeUnit.MINUTES));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public ListResponse<RegisterManageInfoResponse> getManageRegisters(final Long te
final Map<Long, User> registerUserMap = getRegisterUserMap(allRegisters);
Comparator<Authority> authorityComparator = Comparator.comparing(Enum::ordinal);
final List<RegisterManageInfoResponse> manageRegisterInfoResponses = allRegisters.stream()
.sorted(Comparator.comparing(register -> register.getAuthority(), authorityComparator))
.sorted(Comparator.comparing(Register::getAuthority, authorityComparator))
.map(register -> {
final User registerUser = registerUserMap.get(register.getUserId());
return new RegisterManageInfoResponse(register.getId(), register.getAuthority(), registerUser.getNickname(), registerUser.getEmail(), registerUser.getImageUrl());
Expand All @@ -67,7 +67,7 @@ private Map<Long, User> getRegisterUserMap(List<Register> allRegisters) {
final List<Long> registerUserIds = allRegisters.stream()
.map(Register::getUserId)
.collect(Collectors.toList());
return userQueryService.findUserMapByIds(registerUserIds);
return userQueryService.findMapWithUserIdKeyByIds(registerUserIds);
}

public ListResponse<RegisterSearchInfoResponse> searchRegisterByNickname(final Long todoTeamId, final String nickname) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.pawith.todoapplication.service;

import com.pawith.commonmodule.annotation.ApplicationService;
import com.pawith.todoapplication.dto.response.TodoCompletionResponse;
import com.pawith.tododomain.entity.Todo;
import com.pawith.tododomain.service.TodoQueryService;
import lombok.RequiredArgsConstructor;

@ApplicationService
@RequiredArgsConstructor
public class TodoCompleteGetUseCase {
private final TodoQueryService todoQueryService;

public TodoCompletionResponse getTodoCompletion(Long todoId) {
final Todo todo = todoQueryService.findTodoByTodoId(todoId);
return new TodoCompletionResponse(todo.getCompletionStatus());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import com.pawith.commonmodule.annotation.ApplicationService;
import com.pawith.commonmodule.response.ListResponse;
import com.pawith.todoapplication.dto.response.*;
import com.pawith.todoapplication.dto.response.AssignUserInfoResponse;
import com.pawith.todoapplication.dto.response.CategorySubTodoResponse;
import com.pawith.todoapplication.dto.response.TodoInfoResponse;
import com.pawith.todoapplication.dto.response.TodoNotificationInfoResponse;
import com.pawith.todoapplication.mapper.TodoMapper;
import com.pawith.tododomain.entity.*;
import com.pawith.tododomain.service.AssignQueryService;
Expand All @@ -16,7 +19,6 @@
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
Expand All @@ -33,6 +35,7 @@ public class TodoGetUseCase {
private final AssignQueryService assignQueryService;
private final TodoNotificationQueryService todoNotificationQueryService;


public ListResponse<TodoInfoResponse> getTodoListByTodoTeamId(final Long todoTeamId) {
final User user = userUtils.getAccessUser();
final List<Assign> allAssigns = assignQueryService.findAllByUserIdAndTodoTeamIdAndScheduledDate(user.getId(), todoTeamId);
Expand All @@ -49,36 +52,40 @@ public ListResponse<TodoInfoResponse> getTodoListByTodoTeamId(final Long todoTea

public ListResponse<CategorySubTodoResponse> getTodoListByCategoryId(Long categoryId, LocalDate moveDate) {
final User accessUser = userUtils.getAccessUser();
final Map<Todo, List<Assign>> todoAssignMap = createTodoAssignListMap(categoryId, moveDate);
final Map<Long, TodoNotification> todoNotificationMap = createTodoNotificationMapWithTodoId(new ArrayList<>(todoAssignMap.keySet()), accessUser.getId());

final Map<Todo, List<Assign>> todoAssignMap =
assignQueryService.findMapWithTodoKeyAndAssignListValueByCategoryIdAndScheduledDate(categoryId, moveDate);
final List<Todo> todoList = List.copyOf(todoAssignMap.keySet());

final Map<Long, TodoNotification> todoNotificationMap =
todoNotificationQueryService.findMapTodoIdKeyAndTodoNotificationValueByTodoIdsAndUserId(todoList, accessUser.getId());

final Map<Long, User> userMap = createUserIdMap(todoAssignMap);
final ArrayList<CategorySubTodoResponse> todoMainResponses = new ArrayList<>();
for (Todo todo : todoAssignMap.keySet()) {
final AtomicReference<Boolean> isAssigned = new AtomicReference<>(false);
final List<AssignUserInfoResponse> assignUserInfoResponses = todoAssignMap.get(todo).stream()
.map(assign -> {
final Register register = assign.getRegister();
final User findUser = userMap.get(register.getUserId());
if (Objects.equals(findUser.getId(), accessUser.getId())) {
isAssigned.set(true);
}
return new AssignUserInfoResponse(findUser.getId(), findUser.getNickname(), assign.getCompletionStatus());
})
.sorted(Comparator.comparing(assignUserInfoResponse -> !Objects.equals(assignUserInfoResponse.getAssigneeId(), accessUser.getId())))
.collect(Collectors.toList());
TodoNotificationInfoResponse todoNotificationInfoResponse = getTodoNotificationInfoResponse(todo, todoNotificationMap);
todoMainResponses.add(TodoMapper.mapToCategorySubTodoResponse(todo, assignUserInfoResponses, isAssigned.get(),todoNotificationInfoResponse));
}
return ListResponse.from(todoMainResponses);

final List<CategorySubTodoResponse> subTodoResponseList = todoList.stream()
.map(todo -> {
final AtomicReference<Boolean> isAssigned = new AtomicReference<>(false);
final List<Assign> assigns = todoAssignMap.get(todo);
final List<AssignUserInfoResponse> assignUserInfoResponses = getAssignUserInfoResponses(assigns, userMap, accessUser, isAssigned);
final TodoNotificationInfoResponse todoNotificationInfoResponse =
TodoNotificationInfoResponse.of(() -> Optional.ofNullable(todoNotificationMap.get(todo.getId())));
return TodoMapper.mapToCategorySubTodoResponse(todo, assignUserInfoResponses, isAssigned.get(), todoNotificationInfoResponse);
}).toList();
return ListResponse.from(subTodoResponseList);
}

private static TodoNotificationInfoResponse getTodoNotificationInfoResponse(Todo todo, Map<Long, TodoNotification> todoNotificationMap) {
if(todoNotificationMap.containsKey(todo.getId())){
final TodoNotification todoNotification = todoNotificationMap.get(todo.getId());
final LocalTime notificationTime = todoNotification.getNotificationTime();
return new TodoNotificationInfoResponse(true, notificationTime);
}
return new TodoNotificationInfoResponse(false, null);
private List<AssignUserInfoResponse> getAssignUserInfoResponses(List<Assign> assigns, Map<Long, User> userMap, User accessUser, AtomicReference<Boolean> isAssigned) {
return assigns.stream()
.map(assign -> {
final Register register = assign.getRegister();
final User findUser = userMap.get(register.getUserId());
if (Objects.equals(findUser.getId(), accessUser.getId())) {
isAssigned.set(true);
}
return new AssignUserInfoResponse(findUser.getId(), findUser.getNickname(), assign.getCompletionStatus());
})
.sorted(Comparator.comparing(assignUserInfoResponse -> !Objects.equals(assignUserInfoResponse.getAssigneeId(), accessUser.getId())))
.collect(Collectors.toList());
}

private Map<Long, User> createUserIdMap(Map<Todo, List<Assign>> groupByTodo) {
Expand All @@ -90,25 +97,7 @@ private Map<Long, User> createUserIdMap(Map<Todo, List<Assign>> groupByTodo) {
})
.boxed()
.collect(Collectors.toList());
return userQueryService.findUserMapByIds(userIds);
}

private Map<Long, TodoNotification> createTodoNotificationMapWithTodoId(List<Todo> todoList, Long userId) {
final List<Long> todoIds = todoList.stream().map(Todo::getId).collect(Collectors.toList());
return todoNotificationQueryService.findAllByTodoIdsWithIncompleteAssign(todoIds, userId)
.stream()
.collect(Collectors.toMap(todoNotification -> todoNotification.getAssign().getTodo().getId(), todoNotification -> todoNotification));
}

public TodoCompletionResponse getTodoCompletion(Long todoId) {
final Todo todo = todoQueryService.findTodoByTodoId(todoId);
return new TodoCompletionResponse(todo.getCompletionStatus());
}

private Map<Todo, List<Assign>> createTodoAssignListMap(Long categoryId, LocalDate moveDate) {
return assignQueryService.findAllAssignByCategoryIdAndScheduledDate(categoryId, moveDate)
.stream()
.collect(Collectors.groupingBy(Assign::getTodo, LinkedHashMap::new, Collectors.toList()));
return userQueryService.findMapWithUserIdKeyByIds(userIds);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void getRegisters() {
);
final List<Long> userIds = registerList.stream().map(Register::getUserId).collect(Collectors.toList());
given(registerQueryService.findAllRegistersByTodoTeamId(todoTeamId)).willReturn(registerList);
given(userQueryService.findUserMapByIds(userIds)).willReturn(Map.of(mockFindUser.getId(), mockFindUser));
given(userQueryService.findMapWithUserIdKeyByIds(userIds)).willReturn(Map.of(mockFindUser.getId(), mockFindUser));
// when
ListResponse<RegisterInfoResponse> registerInfoListResponse = registersGetUseCase.getRegisters(todoTeamId);
// then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.tododomain.entity.Assign;
import com.pawith.tododomain.entity.Todo;
import com.pawith.tododomain.exception.AssignNotFoundException;
import com.pawith.tododomain.exception.TodoError;
import com.pawith.tododomain.repository.AssignRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@DomainService
@Transactional(readOnly = true)
Expand All @@ -22,6 +26,12 @@ public List<Assign> findAllAssignByCategoryIdAndScheduledDate(Long categoryId, L
return assignRepository.findAllByCategoryIdAndScheduledDateQuery(categoryId, scheduledDate);
}

public Map<Todo, List<Assign>> findMapWithTodoKeyAndAssignListValueByCategoryIdAndScheduledDate(Long categoryId, LocalDate scheduledDate) {
return assignRepository.findAllByCategoryIdAndScheduledDateQuery(categoryId, scheduledDate)
.stream()
.collect(Collectors.groupingBy(Assign::getTodo, LinkedHashMap::new, Collectors.toList()));
}

public List<Assign> findAllByUserIdAndTodoTeamIdAndScheduledDate(Long userId, Long todoTeamId) {
final LocalDate now = LocalDate.now();
return assignRepository.findAllByUserIdAndTodoTeamIdAndScheduledDateQuery(userId, todoTeamId, now);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.pawith.tododomain.service;

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.tododomain.entity.Assign;
import com.pawith.tododomain.entity.Todo;
import com.pawith.tododomain.entity.TodoNotification;
import com.pawith.tododomain.repository.TodoNotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@DomainService
@RequiredArgsConstructor
Expand All @@ -15,7 +19,14 @@ public class TodoNotificationQueryService {

private final TodoNotificationRepository todoNotificationRepository;

public List<TodoNotification> findAllByTodoIdsWithIncompleteAssign(List<Long> todoIds, Long userId) {
return todoNotificationRepository.findAllByTodoIdsAndUserIdWithInCompleteAssignQuery(todoIds, userId);
public Map<Long, TodoNotification> findMapTodoIdKeyAndTodoNotificationValueByTodoIdsAndUserId(List<Todo> todoList, Long userId) {
final List<Long> todoIds = todoList.stream().map(Todo::getId).collect(Collectors.toList());
return todoNotificationRepository.findAllByTodoIdsAndUserIdWithInCompleteAssignQuery(todoIds, userId)
.stream()
.collect(Collectors.toMap(todoNotification -> {
final Assign assign = todoNotification.getAssign();
final Todo todo = assign.getTodo();
return todo.getId();
}, todoNotification -> todoNotification));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class TodoController {
private final TodoValidationUseCase todoValidationUseCase;
private final TodoNotificationCreateUseCase todoNotificationCreateUseCase;
private final TodoWithdrawGetUseCase todoWithdrawGetUseCase;
private final TodoCompleteGetUseCase todoCompleteGetUseCase;

@GetMapping("/{todoTeamId}/todos/progress")
public TodoProgressResponse getTodoProgress(@PathVariable Long todoTeamId) {
Expand Down Expand Up @@ -80,7 +81,7 @@ public void putAssign(@PathVariable Long todoId, @RequestBody AssignChangeReques

@GetMapping("/todos/{todoId}/completion")
public TodoCompletionResponse getTodoCompletion(@PathVariable Long todoId){
return todoGetUseCase.getTodoCompletion(todoId);
return todoCompleteGetUseCase.getTodoCompletion(todoId);
}

@DeleteMapping("/todos/{todoId}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public class TodoControllerTest extends BaseRestDocsTest {
private TodoNotificationCreateUseCase todoNotificationCreateUseCase;
@MockBean
private TodoWithdrawGetUseCase todoWithdrawGetUseCase;
@MockBean
private TodoCompleteGetUseCase todoCompleteGetUseCase;

private static final String TODO_REQUEST_URL = "/teams";

Expand Down Expand Up @@ -302,7 +304,7 @@ void getTodoCompletion() throws Exception {
//given
final Long testTodoId = FixtureMonkeyUtils.getJavaTypeBasedFixtureMonkey().giveMeOne(Long.class);
final TodoCompletionResponse todoCompletionResponse = FixtureMonkeyUtils.getConstructBasedFixtureMonkey().giveMeOne(TodoCompletionResponse.class);
given(todoGetUseCase.getTodoCompletion(testTodoId)).willReturn(todoCompletionResponse);
given(todoCompleteGetUseCase.getTodoCompletion(testTodoId)).willReturn(todoCompletionResponse);
MockHttpServletRequestBuilder request = get(TODO_REQUEST_URL + "/todos/{todoId}/completion", testTodoId)
.header("Authorization", "Bearer accessToken");
//when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ public User findById(Long userId){
return findUser(() -> userRepository.findById(userId));
}

public <T> Map<Long,User> findUserMapByIds(List<Long> userIds){
public Map<Long,User> findMapWithUserIdKeyByIds(List<Long> userIds){
return userRepository.findAllByIds(userIds)
.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
}

private <T> User findUser(Supplier<Optional<User>> method){
private User findUser(Supplier<Optional<User>> method){
return method.get()
.orElseThrow(() -> new UserNotFoundException(UserError.USER_NOT_FOUND));
}
Expand Down
Loading