Создание цепочки предикатов для фильтра в стриме

Есть REST сервис. В GET запросе могут присутствовать параметры: обычные на сравнение, дата "от", дата "до". Параметры могут быть в любой комбинации. Параметры даты формируют временной промежуток:

  • если нет даты "от" - то отбираются от самой первой (по времени) записи
  • если нет "до" - до самой то отбираются до самой последней (по времени) записи

Идея в том, чтобы создать фильтр для любой ситуации и использовать его в stream()

Есть такая реализация:

  private Specification<User> byFilter(Map<String, String> requestParams) {
    return requestParams
            .entrySet()
            .stream()
            .filter(param -> !param.getKey().equals(TIME_FROM) && !param.getKey().equals(TIME_TO))
            .map(entry -> byAttributeValue(entry.getKey(), entry.getValue()))
            .reduce(Specification::and).orElse(null);
  }

Репозиторий:

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

  List<User> findAllByOrderByTimeAsc();

  static Specification<User> byAttributeValue(String field, Object value) {
    return (user, query, cb) -> cb.equal(user.get(field), value);
  }

  Set<User> findByTimeBetween(Date startDate, Date endDate);

}

Смысл таков: если есть хоть один параметр по времени, то идет выборка по дате (много кода со связями, не представлено) потом выборка с использованием byFilter(), потом выборки сводятся; если нет - сразу выборка через byFilter().

Работает, но реализация не нравится. Кажется избыточной, не гибкой. Не получается додумать использование Specification, Predicate в stream().

Как в byFilter "прикрутить" фильтр по дате?

Будет здорово, если кто-нибудь даст толковое объяснение принципа работы кода

static Specification<User> byAttributeValue(String field, Object value) {
        return (user, query, cb) -> cb.equal(user.get(field), value);
      }

Ответы (0 шт):