io.mosip.pms.common.helper.SearchHelper Maven / Gradle / Ivy
package io.mosip.pms.common.helper;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import io.mosip.kernel.core.dataaccess.exception.DataAccessLayerException;
import io.mosip.kernel.core.util.DateUtils;
import io.mosip.pms.common.constant.FilterTypeEnum;
import io.mosip.pms.common.constant.OrderEnum;
import io.mosip.pms.common.constant.SearchErrorCode;
import io.mosip.pms.common.dto.Pagination;
import io.mosip.pms.common.dto.SearchDto;
import io.mosip.pms.common.dto.SearchFilter;
import io.mosip.pms.common.dto.SearchSort;
import io.mosip.pms.common.exception.RequestException;
/**
* Generating dynamic query for partnerManagementData based on the search filters.
*
* @author Tabish Khan
* @since 1.0.0
*/
@Repository
@Transactional(readOnly = true)
public class SearchHelper {
private static final String ENTITY_IS_NULL = "entity is null";
private static final String WILD_CARD_CHARACTER = "%";
private static final String DECOMISSION = "isDeleted";
private static final String IS_ACTIVE_COLUMN_NAME = "isActive";
/**
* Field for interface used to interact with the persistence context.
*/
@PersistenceContext
private EntityManager entityManager;
public Page search(EntityManager entityManager,Class entity, SearchDto searchDto) {
this.entityManager= entityManager;
return search(entity,searchDto);
}
/**
* Method to search and sort the partnerManagementData.
*
* @param entity the entity class for which search will be applied
* @param searchDto which contains the list of filters, sort and
* pagination
* @param optionalFilters filters to be considered as 'or' statements
*
* @return {@link Page} of entity
*/
public Page search(Class entity, SearchDto searchDto) {
long rows = 0l;
List result;
Objects.requireNonNull(entity, ENTITY_IS_NULL);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery selectQuery = criteriaBuilder.createQuery(entity);
CriteriaQuery countQuery = criteriaBuilder.createQuery(Long.class);
// root Query
Root rootQuery = selectQuery.from(entity);
// count query
countQuery.select(criteriaBuilder.count(countQuery.from(entity)));
// applying filters
if (!searchDto.getFilters().isEmpty())
filterQuery(criteriaBuilder, rootQuery, selectQuery, countQuery, searchDto.getFilters());
// applying sorting
if(!searchDto.getSort().isEmpty())
sortQuery(criteriaBuilder, rootQuery, selectQuery, searchDto.getSort());
try {
// creating executable query from select criteria query
TypedQuery executableQuery = entityManager.createQuery(selectQuery);
// creating executable query from count criteria query
TypedQuery countExecutableQuery = entityManager.createQuery(countQuery);
// getting the rows count
rows = countExecutableQuery.getSingleResult();
// adding pagination
paginationQuery(executableQuery, searchDto.getPagination());
// executing query and returning data
result = executableQuery.getResultList();
} catch (Exception hibernateException) {
if(hibernateException instanceof RequestException) {
throw new RequestException(((RequestException) hibernateException).getErrors());
}
throw new RequestException("PMS-MSD-394",
String.format(hibernateException.getMessage(), hibernateException.getLocalizedMessage()));
}
if(result.isEmpty()) {
throw new RequestException(SearchErrorCode.INVALID_COLUMN_VALUE.getErrorCode(),
String.format(SearchErrorCode.INVALID_COLUMN_VALUE.getErrorMessage()));
}
return new PageImpl<>(result,
PageRequest.of(searchDto.getPagination().getPageStart(), searchDto.getPagination().getPageFetch()),
rows);
}
/**
* Method to add the filters to the criteria query
*
* @param builder used to construct criteria queries
* @param root root type in the from clause,always refers entity
* @param selectQuery criteria select query
* @param countQuery criteria count query
* @param filters list of {@link SearchFilter}
*/
private void filterQuery(CriteriaBuilder builder, Root root, CriteriaQuery selectQuery,
CriteriaQuery countQuery, List filters) {
final List predicates = new ArrayList<>();
if (filters != null && !filters.isEmpty()) {
filters.stream().filter(this::validateFilters).map(i -> buildFilters(builder, root, i))
.filter(Objects::nonNull).collect(Collectors.toCollection(() -> predicates));
}
Predicate isDeletedTrue = builder.equal(root.get(DECOMISSION), Boolean.FALSE);
Predicate isDeletedNull = builder.isNull(root.get(DECOMISSION));
Predicate isDeleted = builder.or(isDeletedTrue, isDeletedNull);
predicates.add(isDeleted);
if (!predicates.isEmpty()) {
Predicate whereClause = builder.and(predicates.toArray(new Predicate[predicates.size()]));
selectQuery.where(whereClause);
countQuery.where(whereClause);
}
}
/**
* Method to build {@link Predicate} out the {@link SearchFilter}
*
* @param builder used to construct criteria queries
* @param root root type in the from clause,always refers entity
* @param filter search filter
* @return {@link Predicate}
*/
protected Predicate buildFilters(CriteriaBuilder builder, Root root, SearchFilter filter) {
String columnName = filter.getColumnName();
String value = filter.getValue();
String filterType = filter.getType();
if (FilterTypeEnum.CONTAINS.name().equalsIgnoreCase(filterType)) {
Expression lowerCase=null;
try {
lowerCase = builder.lower(root.get(columnName));
} catch (Exception e) {
throw new RequestException(SearchErrorCode.INVALID_COLUMN.getErrorCode(),
String.format(SearchErrorCode.INVALID_COLUMN.getErrorMessage(), columnName));
}
if (value.startsWith("*") && value.endsWith("*")) {
String replacedValue = (value.substring(1)).substring(0, value.length() - 2);
return builder.like(lowerCase,
builder.lower(builder.literal(WILD_CARD_CHARACTER + replacedValue + WILD_CARD_CHARACTER)));
} else if (value.startsWith("*")) {
String replacedValue = value.substring(1);
return builder.like(lowerCase, builder.lower(builder.literal(WILD_CARD_CHARACTER + replacedValue)));
} else {
return builder.like(lowerCase,
builder.lower(builder.literal(WILD_CARD_CHARACTER + value + WILD_CARD_CHARACTER)));
}
}
if (FilterTypeEnum.EQUALS.name().equalsIgnoreCase(filterType)) {
return buildPredicate(builder, root, columnName, value);
}
if (FilterTypeEnum.STARTSWITH.name().equalsIgnoreCase(filterType)) {
if (value.endsWith("*")) {
value = value.substring(0, value.length() - 1);
}
Expression lowerCase = null;
try {
lowerCase = builder.lower(root.get(columnName));
} catch (Exception e) {
throw new RequestException(SearchErrorCode.INVALID_COLUMN.getErrorCode(),
String.format(SearchErrorCode.INVALID_COLUMN.getErrorMessage(), columnName));
}
return builder.like(lowerCase, builder.lower(builder.literal(value + WILD_CARD_CHARACTER)));
}
if (FilterTypeEnum.BETWEEN.name().equalsIgnoreCase(filterType)) {
return setBetweenValue(builder, root, filter);
}
return null;
}
/**
* Method to add sorting statement in criteria query
*
* @param builder used to construct criteria query
* @param root root type in the from clause,always refers entity
* @param criteriaQuery query in which sorting to be added
* @param sortFilter by the query to be sorted
*/
private void sortQuery(CriteriaBuilder builder, Root root, CriteriaQuery criteriaQuery,
List sortFilter) {
if (sortFilter != null && !sortFilter.isEmpty()) {
List orders = sortFilter.stream().filter(this::validateSort).map(i -> {
Path
© 2015 - 2025 Weber Informatics LLC | Privacy Policy