package au.com.vaadinutils.dao; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.Tuple; import javax.persistence.metamodel.SingularAttribute; import au.com.vaadinutils.dao.JpaBaseDao.Condition; /** * Sometimes it is faster to run multiple queries returning the same entity than * it is to run a single (potentially slow) query with multiple joins and * clauses. This class can be used to group the queries and return the results * from them in a single set. * * Usage example: * * <pre> * <code> * final JpaDslTupleBuilderGroup<TblSalesCustCallItem> queryGroup = new JpaDslTupleBuilderGroup<>( * TblSalesCustCallItem.class); * queryGroup.multiselect(TblSalesCustCallItem_.iid); * queryGroup.setCommon(new JpaDslTupleBuilderGroupCommon<TblSalesCustCallItem>() * { * @Override * public void conditionsWillBeAdded(JpaDslTupleBuilder<TblSalesCustCallItem> builder, * List<Condition<TblSalesCustCallItem>> conditions) * { * conditions.add(builder.eq(TblSalesCustCallItem_.contact, contact)); * } * }); * * queryGroup.addItem(new JpaDslTupleBuilderGroupItem<TblSalesCustCallItem>() * { * @Override * public void conditionsWillBeAdded(JpaDslTupleBuilder<TblSalesCustCallItem> builder, * List<Condition<TblSalesCustCallItem>> conditions) * { * conditions.add(builder.eq(TblSalesCustCallItem_.salesperson, salesperson)); * } * }); * * final List<Long> itemIds = new ArrayList<>(); * for (Tuple result : queryGroup.getResults()) * { * itemIds.add(queryGroup.get(result, TblSalesCustCallItem_.iid)); * } * </code> * </pre> * */ public class JpaDslTupleBuilderGroup<E> { private List<JpaDslTupleBuilderGroupItem<E>> builders = new ArrayList<>(); private JpaDslTupleBuilderGroupCommon<E> common; private Class<E> entityClass; private List<Tuple> results = new ArrayList<>(); private boolean distinct = false; private Map<SingularAttribute<E, ?>, Integer> multiselects = new LinkedHashMap<>(); private int positionCounter = 0; private List<JpaDslOrder> orders = new ArrayList<>(); public JpaDslTupleBuilderGroup(final Class<E> entityClass) { this.entityClass = entityClass; } public void addItem(JpaDslTupleBuilderGroupItem<E> builder) { builders.add(builder); } public interface JpaDslTupleBuilderGroupItem<E> { public void conditionsWillBeAdded(final JpaDslTupleBuilder<E> builder, final List<Condition<E>> conditions); } public void setCommon(JpaDslTupleBuilderGroupCommon<E> common) { this.common = common; } public interface JpaDslTupleBuilderGroupCommon<E> { public void conditionsWillBeAdded(final JpaDslTupleBuilder<E> builder, final List<Condition<E>> conditions); } public <T> void multiselect(SingularAttribute<E, T> attribute) { multiselects.put(attribute, positionCounter++); } public <T> T get(final Tuple tuple, final SingularAttribute<E, T> attribute) { final Integer tuplePosition = multiselects.get(attribute); return tuple.get(tuplePosition, attribute.getBindableJavaType()); } public Object get(final Tuple tuple, final String alias) { // IllegalArgumentException will be thrown if tuple doesn't exist in // query // If this is the case then just return null try { return tuple.get(alias); } catch (IllegalArgumentException e) { return null; } } public List<Tuple> getResults() { if (builders.size() > 0) { for (JpaDslTupleBuilderGroupItem<E> builder : builders) { results.addAll(makeQuery(builder)); } } else { results.addAll(makeQuery(null)); } return results; } private List<Tuple> makeQuery(final JpaDslTupleBuilderGroupItem<E> builder) { final JpaDslTupleBuilder<E> q = new JpaDslTupleBuilder<E>(entityClass); for (Entry<SingularAttribute<E, ?>, Integer> multiselect : multiselects.entrySet()) { q.multiselect(multiselect.getKey()); } final List<Condition<E>> conditions = new LinkedList<>(); if (common != null) { common.conditionsWillBeAdded(q, conditions); } if (builder != null) { builder.conditionsWillBeAdded(q, conditions); } if (distinct) { q.distinct(); } q.where(conditions); for (JpaDslOrder order : orders) { q.orderBy(order.getField(), order.getAscending()); } return q.getResultList(); } public void distinct() { distinct = true; } public void orderBy(final String field, final boolean ascending) { orders.add(new JpaDslOrder(field, ascending)); } }