package fr.openwide.core.jpa.more.business.search.query; import java.util.Collection; import java.util.List; import javax.annotation.PostConstruct; import org.springframework.transaction.annotation.Transactional; import com.querydsl.core.QueryModifiers; import com.querydsl.core.types.CollectionExpression; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Path; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CollectionPath; import com.querydsl.core.types.dsl.ComparableExpression; import com.querydsl.core.types.dsl.SimpleExpression; import com.querydsl.jpa.impl.JPAQuery; import fr.openwide.core.jpa.more.business.sort.ISort; import fr.openwide.core.jpa.more.business.sort.SortUtils; public abstract class AbstractJpaSearchQuery<T, S extends ISort<OrderSpecifier<?>>> extends AbstractSearchQuery<T, S> /* NOT Serializable */ { private final EntityPath<T> entityPath; private JPAQuery<T> jpaQuery; private JPAQuery<T> finalJpaQuery; @SafeVarargs protected AbstractJpaSearchQuery(EntityPath<T> entityPath, S ... defaultSorts) { super(defaultSorts); this.entityPath = entityPath; } @PostConstruct private void init() { jpaQuery = new JPAQuery<T>(entityManager) .select(entityPath) .from(entityPath); } public <P> void innerJoin(CollectionExpression<?,P> target, Path<P> alias) { jpaQuery.innerJoin(target, alias); } // Junction appender // > Must protected void must(BooleanExpression booleanExpression) { if (booleanExpression != null) { jpaQuery.where(booleanExpression); } } protected void mustIfNotNull(JPAQuery<T> jpaQuery, BooleanExpression ... booleanExpressions) { for (BooleanExpression booleanExpression : booleanExpressions) { if (booleanExpression != null) { jpaQuery.where(booleanExpression); } } } // > Should protected void shouldIfNotNull(BooleanExpression ... booleanExpressions) { BooleanExpression condition = null; for (BooleanExpression booleanExpression : booleanExpressions) { if (condition == null) { condition = booleanExpression; } else { condition = condition.or(booleanExpression); } } if (condition != null) { jpaQuery.where(condition); } } // List and count /** * Allow to add filter before generating the full text query.<br /> * Sample: * <ul> * <li>must(matchIfGiven(qCompany.manager.organization, organization))</li> * <li>must(matchIfGiven(qCompany.status, CompanyStatus.ACTIVE))</li> * </ul> */ protected void addFilterBeforeFinalizeQuery() { // Nothing } private JPAQuery<T> getFinalQuery() { if (finalJpaQuery == null) { addFilterBeforeFinalizeQuery(); for (OrderSpecifier<?> orderSpecifier : SortUtils.getOrderSpecifierWithDefaults(sortMap, defaultSorts)) { jpaQuery.orderBy(orderSpecifier); } finalJpaQuery = jpaQuery; } return finalJpaQuery; } @Override @Transactional(readOnly = true) public final List<T> fullList() { return getQueryList(null, null).fetch(); } @Override @Transactional(readOnly = true) public final List<T> list(long offset, long limit) { return getQueryList(offset, limit).fetch(); } protected JPAQuery<T> getQueryList(Long offset, Long limit) { JPAQuery<T> finalQuery = getFinalQuery(); // Handle multiple calls to getQueryList() finalQuery.restrict(QueryModifiers.EMPTY); if (offset != null) { finalQuery.offset(offset); } if (limit != null) { finalQuery.limit(limit); } return finalQuery; } @Override @Transactional(readOnly = true) public long count() { return getFinalQuery().fetchCount(); } // Query factory // > Match if given protected <P extends Comparable<?>> BooleanExpression matchIfGiven(SimpleExpression<P> simpleExpression, P value) { if (value != null) { return simpleExpression.eq(value); } return null; } // > Contains if given protected <E, Q extends SimpleExpression<? super E>> BooleanExpression containsIfGiven(CollectionPath<E, Q> collectionPath, E value) { if (value != null) { return collectionPath.contains(value); } return null; } // > Match one if given protected <P extends Comparable<?>> BooleanExpression matchOneIfGiven(SimpleExpression<P> simpleExpression, Collection<? extends P> possibleValues) { if (possibleValues != null && !possibleValues.isEmpty()) { return simpleExpression.in(possibleValues); } return null; } // > Match all if given protected <P extends Comparable<?>> BooleanExpression matchAllIfGiven(SimpleExpression<P> simpleExpression, Collection<? extends P> possibleValues) { if (possibleValues != null && !possibleValues.isEmpty()) { BooleanExpression rootExpression = null; for (P possibleValue : possibleValues) { if (rootExpression == null) { rootExpression = simpleExpression.eq(possibleValue); } else { rootExpression = rootExpression.and(simpleExpression.eq(possibleValue)); } } return rootExpression; } return null; } // > Match range if given protected <P extends Comparable<?>> BooleanExpression matchRangeIfGiven(ComparableExpression<P> comparableExpression, P minValue, P maxValue) { if (minValue != null && maxValue != null) { return comparableExpression.between(minValue, maxValue); } else if (minValue != null) { return comparableExpression.goe(minValue); } else if (maxValue != null) { return comparableExpression.loe(maxValue); } return null; } protected <P extends Comparable<?>> BooleanExpression matchExclusiveRangeIfGiven(ComparableExpression<P> comparableExpression, P minValue, P maxValue) { if (minValue != null && maxValue != null) { return comparableExpression.gt(minValue).and(comparableExpression.lt(maxValue)); } else if (minValue != null) { return comparableExpression.gt(minValue); } else if (maxValue != null) { return comparableExpression.lt(maxValue); } return null; } }