PersonSearchRepositoryImpl.java

package com.tradecloud.repository.impl;

import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.party.Employee;
import com.tradecloud.domain.party.EmployeeRole;
import com.tradecloud.domain.party.base.Person;
import com.tradecloud.dto.company.PersonSearch;
import com.tradecloud.repository.GeneralRepository;
import com.tradecloud.repository.PersonSearchRepository;
import com.tradecloud.repository.SearchMetaParams;
import com.tradecloud.repository.base.impl.RepositoryBaseImpl;
import com.tradecloud.repository.company.CompanySearchRepositoryImpl;
import org.apache.log4j.Logger;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class PersonSearchRepositoryImpl extends RepositoryBaseImpl<Person, PersonSearch> implements PersonSearchRepository {

    private static final long serialVersionUID = 1L;

    private static final String LIKE = "%";

    private static Logger log = Logger.getLogger(CompanySearchRepositoryImpl.class);

    @Autowired
    private GeneralRepository generalRepository;

    @SuppressWarnings("unchecked")
    @Override
    public List<Person> search(PersonSearch search) {
        javax.persistence.criteria.CriteriaBuilder cb = getSession().getCriteriaBuilder();
        CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
        Root<Employee> root = cq.from(Employee.class);

        List<Predicate> predicates = buildPredicates(cb, root, search);

        cq.select(root)
                .where(predicates.toArray(new Predicate[0]))
                .distinct(true);
        SearchMetaParams metaParams = search.getSearchMetaParams();

        cq.orderBy(cb.asc(root.get("lastName")));
        Query<Employee> query = getSessionCustom().createQuery(cq);
        if (metaParams != null && metaParams.isPaged()) {
            query.setFirstResult(metaParams.getRowIndex());
            query.setMaxResults(metaParams.getRowCount());

        }
        return query.getResultList().stream().map(emp -> ((Employee) emp)).collect(Collectors.toList());
    }

    @Override
    public long count(PersonSearch search) {
        javax.persistence.criteria.CriteriaBuilder cb = getSessionCustom().getCriteriaBuilder();
        CriteriaQuery<Long> cq = cb.createQuery(Long.class);
        Root<Employee> root = cq.from(Employee.class);
        List<Predicate> predicates = buildPredicates(cb, root, search);

        cq.select(cb.countDistinct(root))  // count distinct persons
                .where(predicates.toArray(new Predicate[0]));

        return getSessionCustom().createQuery(cq).getSingleResult();
    }

    private List<Predicate> buildPredicates(javax.persistence.criteria.CriteriaBuilder cb, Root<Employee> root,
                                            PersonSearch search) {
        List<Predicate> predicates = new ArrayList<>();

        // active
        if (search.getActive() != null) {
            predicates.add(cb.equal(root.get("active"), search.getActive()));
        }

        // firstName ilike
        if (search.getFirstName() != null && !search.getFirstName().trim().isEmpty()) {
            predicates.add(cb.like(cb.lower(root.get("firstName")),
                    "%" + search.getFirstName().toLowerCase() + "%"));
        }

        // lastName ilike
        if (search.getLastName() != null && !search.getLastName().trim().isEmpty()) {
            predicates.add(cb.like(cb.lower(root.get("lastName")),
                    "%" + search.getLastName().toLowerCase() + "%"));
        }

        // email ilike
        if (search.getEmail() != null && !search.getEmail().trim().isEmpty()) {
            predicates.add(cb.like(cb.lower(root.get("email")),
                    "%" + search.getEmail().toLowerCase() + "%"));
        }

        // roles (ManyToMany join with EmployeeRole)
        if (search.getRoles() != null && !search.getRoles().isEmpty()) {
            Join<Person, EmployeeRole> rolesJoin = root.join("employeeRoles", JoinType.INNER);
            predicates.add(rolesJoin.get("code").in(search.getRoles()));
        }

        // organisationalUnit
        if (search.getOrganisationalUnit() != null) {
            Join<Person, OrganisationalUnit> orgJoin = root.join("organisationalUnit", JoinType.LEFT);

            List<Predicate> orgPredicates = new ArrayList<>();
            for (OrganisationalUnit child : search.getOrganisationalUnit().getChildren()) {
                if (search.isLiteSearch()) {
                    orgPredicates.add(cb.equal(orgJoin.get("code"), child.getCode()));
                }
            }
            orgPredicates.add(cb.equal(orgJoin.get("code"), search.getOrganisationalUnit().getCode()));
            predicates.add(cb.or(orgPredicates.toArray(new Predicate[0])));
        }

        return predicates;
    }

}