2
\$\begingroup\$

I'm trying to implement properly search functionality for database table. I tried this approach:

Controller:

    @GetMapping
    public Page<TransactionDTO> find(TransactionFilterDTO filter, Pageable page) {
        return searchRepository
                .findTransactionsByFilter(mapper.toFilter(filter), page)
                .map(mapper::toDTO);
    }

Filer DTO:

public class TransactionFilterDTO {

    private String name;

    private Integer id;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime from;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    private LocalDateTime to;
    ... // getters and setter
}

Search implementation:

@Repository
public class TransactionSearchRepositoryImpl implements TransactionSearchRepository {

    @Autowired
    private TransactionRepository transactionRepository;

    @Autowired
    private TransactionSpecification specification;

    @Override
    public Page<Transaction> findTransactionsByFilter(TransactionFilter filter, @Nullable Pageable page) {


        List<Transaction> transactions = transactionRepository
                .findAll(specification.getFilter(filter));

        int totalCount = transactions.size();

        if(page != null) {
           transactions = transactions
                   .stream()
                   .skip(page.getOffset())
                   .limit(page.getPageSize())
                   .collect(Collectors.toList());
        }

        return new PageImpl<>(transactions, page, totalCount);
    }
}

Repository:

public interface TransactionSearchRepository {

    Page<Transaction> findTransactionsByFilter(TransactionFilter filter, Pageable page);
}

Is there some better way to implement a search functionality? This solution is very ugly in my view.

\$\endgroup\$
2
\$\begingroup\$

In JPA you could use JpaSpecificationExecutor<T> in repository, with that you could utilize it's method.

TransactionRepository

public interface TransactionRepository extends JpaRepository<Transaction, Long>,
                                                JpaSpecificationExecutor<Transaction> {


}

If you look at the source of JpaSpecificationExecutor it has,

Page< T > findAll(@Nullable Specification<T> spec, Pageable pageable);

With that you just pass the specification and Pageable to return what you expected.

Specification

@AllArgsConstructor
class TransactionSpecification implements Specification<Transaction> {

       private TransactionFilter transactionFilter;

       @Override
        public Predicate toPredicate(Root<DataImport> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            // You could add multiple Predicates based on the transactionFilter
            return criteriaBuilder.equal(root.get("table_name"), "value");
        }
}

Controller

    @Autowired
    private TransactionRepository transactionRepository;

    @GetMapping
    public Page<TransactionDTO> find(TransactionFilterDTO filter, Pageable page) {
        TransactionFilter transactionFilter = mapper.toFilter(filter);
        return transactionRepository.findAll(new TransactionSpecification(transactionFilter), page);
    }

I am pretty late answering but you could give it a try

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.