───────┬────────────────────────────────────────────────────────────────────────
       File: src/main//java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java
───────┼────────────────────────────────────────────────────────────────────────
   1    package jp.ac.kobe_u.cs.itspecialist.todoapp.service;
   2    
   3    import java.util.Date;
   4    import java.util.HashMap;
   5    import java.util.List;
   6    import java.util.Map;
   7    import java.util.function.BiFunction;
   8    import java.util.function.Function;
   9    
  10    import org.springframework.beans.factory.annotation.Autowired;
  11    import org.springframework.data.util.Pair;
  12    import org.springframework.stereotype.Service;
  13    
  14    import jp.ac.kobe_u.cs.itspecialist.todoapp.dto.ToDoForm;
  15    import jp.ac.kobe_u.cs.itspecialist.todoapp.entity.ToDo;
  16    import jp.ac.kobe_u.cs.itspecialist.todoapp.exception.ToDoAppException;
  17    import jp.ac.kobe_u.cs.itspecialist.todoapp.repository.ToDoRepository;
  18    
  19    @Service
  20    public class ToDoService {
  21        @Autowired
  22        MemberService mService;
  23        @Autowired
  24        ToDoRepository tRepo;
  25        /**
  26         * ToDoを作成する (C)
  27         * @param mid 作成者
  28         * @param form フォーム
  29         * @return
  30         */
  31        public ToDo createToDo(String mid, ToDoForm form) {
  32            mService.getMember(mid); //実在メンバーか確認
  33            ToDo todo = form.toEntity();
  34            todo.setMid(mid);
  35            return tRepo.save(todo);
  36        }
  37    
  38        /**
  39         * ToDoを1つ取得する (R)
  40         * @param seq
  41         * @return
  42         */
  43        public ToDo getToDo(Long seq) {
  44            ToDo todo = tRepo.findById(seq).orElseThrow(
  45                () -> new ToDoAppException(ToDoAppException.NO_SUCH_TODO_EXISTS, 
  46                seq + ": No such ToDo exists")
  47            );
  48            return todo;
  49        }
  50    
  51        /**
  52         * あるメンバーのToDoリストを取得する (R)
  53         * @param mid
  54         * @return
  55         */
  56        public List<ToDo> getToDoList(String mid, String sortBy, String order) {
  57            BiFunction<String, Boolean, List<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order),
  58                    (memberId, doneFlag) -> tRepo.findByMidAndDone(memberId, doneFlag));
  59            return finder.apply(mid, false);
  60        }
  61        /**
  62         * あるメンバーのDoneリストを取得する (R)
  63         * @param mid
  64         * @return
  65         */
  66        public List<ToDo> getDoneList(String mid, String sortBy, String order) {
  67            BiFunction<String, Boolean, List<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order),
  68                    (memberId, doneFlag) -> tRepo.findByMidAndDone(memberId, doneFlag));
  69            return finder.apply(mid, true);
  70        }
  71    
  72        private final Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> midAndDoneFinder = generateMidAndDoneFinder();
  73        private Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> generateMidAndDoneFinder() {
  74            Map<Pair<String, String>, BiFunction<String, Boolean, List<ToDo>>> map = new HashMap<>();
  75            map.put(Pair.of("seq", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderBySeqAsc(mid, done));
  76            map.put(Pair.of("seq", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderBySeqDesc(mid, done));
  77            map.put(Pair.of("title", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByTitleAsc(mid, done));
  78            map.put(Pair.of("title", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByTitleDesc(mid, done));
  79            map.put(Pair.of("created_at", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByCreatedAtAsc(mid, done));
  80            map.put(Pair.of("created_at", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByCreatedAtDesc(mid, done));
  81            map.put(Pair.of("done_at", "asc"), (mid, done) -> tRepo.findByMidAndDoneOrderByDoneAtAsc(mid, done));
  82            map.put(Pair.of("done_at", "desc"), (mid, done) -> tRepo.findByMidAndDoneOrderByDoneAtDesc(mid, done));
  83            return map;
  84        }
  85    
  86        /**
  87         * 全員のToDoリストを取得する (R)
  88         * @return
  89         */
  90        public List<ToDo> getToDoList(String sortBy, String order) {
  91            Function<Boolean, List<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order),
  92                    (doneFlag) -> tRepo.findByDone(doneFlag));
  93            return finder.apply(false);
  94        }
  95    
  96        /**
  97         * 全員のDoneリストを取得する (R)
  98         * @return
  99         */
 100        public List<ToDo> getDoneList(String sortBy, String order) {
 101            Function<Boolean, List<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order),
 102                    (doneFlag) -> tRepo.findByDone(doneFlag));
 103            return finder.apply(true);
 104        }
 105    
 106    
 107        private final Map<Pair<String, String>, Function<Boolean, List<ToDo>>> doneFinder = generateDoneFinder();
 108        private Map<Pair<String, String>, Function<Boolean, List<ToDo>>> generateDoneFinder() {
 109            Map<Pair<String, String>, Function<Boolean, List<ToDo>>> map = new HashMap<>();
 110            map.put(Pair.of("seq", "asc"), (doneFlag) -> tRepo.findByDoneOrderBySeqAsc(doneFlag));
 111            map.put(Pair.of("seq", "desc"), (doneFlag) -> tRepo.findByDoneOrderBySeqDesc(doneFlag));
 112            map.put(Pair.of("title", "asc"), (doneFlag) -> tRepo.findByDoneOrderByTitleAsc(doneFlag));
 113            map.put(Pair.of("title", "desc"), (doneFlag) -> tRepo.findByDoneOrderByTitleDesc(doneFlag));
 114            map.put(Pair.of("mid", "asc"), (doneFlag) -> tRepo.findByDoneOrderByMidAsc(doneFlag));
 115            map.put(Pair.of("mid", "desc"), (doneFlag) -> tRepo.findByDoneOrderByMidDesc(doneFlag));
 116            map.put(Pair.of("created_at", "asc"), (doneFlag) -> tRepo.findByDoneOrderByCreatedAtAsc(doneFlag));
 117            map.put(Pair.of("created_at", "desc"), (doneFlag) -> tRepo.findByDoneOrderByCreatedAtDesc(doneFlag));
 118            map.put(Pair.of("done_at", "asc"), (doneFlag) -> tRepo.findByDoneOrderByDoneAtAsc(doneFlag));
 119            map.put(Pair.of("done_at", "desc"), (doneFlag) -> tRepo.findByDoneOrderByDoneAtDesc(doneFlag));
 120            return map;
 121        }
 122    
 123        /**
 124         * ToDoを完了する
 125         * @param mid 完了者
 126         * @param seq 完了するToDoの番号
 127         * @return
 128         */
 129        public ToDo done(String mid, Long seq) {
 130            ToDo todo = getToDo(seq);
 131            //Doneの認可を確認する.他人のToDoを閉めたらダメ.
 132            if (!mid.equals(todo.getMid())) {
 133                throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 
 134                + ": Cannot done other's todo of " + todo.getMid());
 135            }
 136            todo.setDone(true);
 137            todo.setDoneAt(new Date());
 138            return tRepo.save(todo);
 139        }
 140    
 141        /**
 142         * ToDoを更新する
 143         * @param mid 更新者
 144         * @param seq 更新するToDo番号
 145         * @param form 更新フォーム
 146         * @return
 147         */
 148        public ToDo updateToDo(String mid, Long seq, ToDoForm form) {
 149            ToDo todo = getToDo(seq);
 150            //Doneの認可を確認する.他人のToDoを更新したらダメ.
 151            if (!mid.equals(todo.getMid())) {
 152                throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 
 153                + ": Cannot update other's todo of " + todo.getMid());
 154            }
 155            todo.setTitle(form.getTitle()); //タイトルを更新
 156            return tRepo.save(todo);
 157        }
 158    
 159        /**
 160         * ToDoを削除する
 161         * @param mid 削除者
 162         * @param seq 削除するToDo番号
 163         */
 164        public void deleteToDo(String mid, Long seq) {
 165            ToDo todo = getToDo(seq);
 166            //Doneの認可を確認する.他人のToDoを削除したらダメ.
 167            if (!mid.equals(todo.getMid())) {
 168                throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 
 169                + ": Cannot delete other's todo of " + todo.getMid());
 170            }
 171            tRepo.deleteById(seq);
 172        }
 173    
 174    
 175    
 176    }
───────┴────────────────────────────────────────────────────────────────────────