package au.com.vaadinutils.dao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;
import com.google.common.base.Preconditions;
import au.com.vaadinutils.dao.JpaBaseDao.Condition;
/**
*
* @author rsutton
*
* @param <E>
* - Entity Type the Query is based on
* @param <R>
* - Return Type - usually the same as the Entity Type, but in the
* case of a Tuple query then it would be Tuple
*/
public abstract class JpaDslAbstract<E, R>
{
public abstract class AbstractCondition<Z> implements Condition<Z>
{
@Override
public Condition<Z> and(final Condition<Z> c1)
{
return new AbstractCondition<Z>()
{
@Override
public Predicate getPredicates()
{
return builder.and(AbstractCondition.this.getPredicates(), c1.getPredicates());
}
};
}
@Override
public Condition<Z> or(final Condition<Z> c1)
{
return new AbstractCondition<Z>()
{
@Override
public Predicate getPredicates()
{
return builder.or(AbstractCondition.this.getPredicates(), c1.getPredicates());
}
};
}
}
public static final class TypedPath<E, V>
{
final Path<V> path;
public TypedPath(Path<V> path2)
{
this.path = path2;
}
}
protected CriteriaBuilder builder;
private Integer limit = null;
Predicate predicate = null;
private Integer startPosition = null;
protected CriteriaQuery<R> criteria;
protected Class<E> entityClass;
/**
* used to check that the entityManager doesn't shift under our feet!!!
*/
final private EntityManager dontUseThis = EntityManagerProvider.getEntityManager();
List<Order> orders = new LinkedList<>();
protected Root<E> root;
Map<JoinBuilder<E, ?>, Join<E, ?>> joins2 = new HashMap<>();
boolean isJpaContainerDelegate;
public Condition<E> and(final Condition<E> c1)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.and(c1.getPredicates());
}
};
}
@SuppressWarnings("unchecked")
public Condition<E> and(final Condition<E>... conditions)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
final List<Predicate> predicates = new ArrayList<>(conditions.length);
for (Condition<E> condition : conditions)
{
predicates.add(condition.getPredicates());
}
return builder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
}
public Condition<E> and(final Condition<E> c1, final Condition<E> c2)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.and(c1.getPredicates(), c2.getPredicates());
}
};
}
public <K> Expression<String> asString(final JoinBuilder<E, K> join, SingularAttribute<K, ?> field)
{
return getJoin(join).get(field).as(String.class);
}
public Expression<String> asString(SingularAttribute<E, ?> field)
{
return root.get(field).as(String.class);
}
public <V extends Comparable<? super V>> Condition<E> between(final JoinBuilder<E, ? super V> joinBuilder,
final SingularAttribute<? super V, Date> field, final Date start, final Date end)
{
return new AbstractCondition<E>()
{
@SuppressWarnings(
{ "unchecked", "rawtypes" })
@Override
public Predicate getPredicates()
{
return builder.between(getJoin(joinBuilder).get((SingularAttribute) field), start, end);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> between(final SingularAttribute<? super E, V> field,
final V start, final V end)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.between(root.get(field), start, end);
}
};
}
public <T> Expression<T> coalesce(final SingularAttribute<E, T> attribute1,
final SingularAttribute<E, T> attribute2)
{
return builder.coalesce(root.get(attribute1), root.get(attribute2));
}
public Expression<String> concat(Expression<String> concat, Expression<String> trim)
{
return builder.concat(concat, trim);
}
public Expression<String> concat(Expression<String> trim, String string)
{
return builder.concat(trim, string);
}
public Long count()
{
CriteriaQuery<Long> query = builder.createQuery(Long.class);
if (predicate != null)
{
query.where(predicate);
}
query.select(builder.count(root));
return getEntityManager().createQuery(query).getSingleResult();
}
public <K, T> Expression<Long> count(final JoinBuilder<E, K> join, final SingularAttribute<K, T> attribute)
{
return builder.count(getJoin(join).get(attribute));
}
public <K, T> Expression<Long> count(final SingularAttribute<E, T> attribute)
{
return builder.count(root.get(attribute));
}
public Long countDistinct()
{
CriteriaQuery<Long> query = builder.createQuery(Long.class);
if (predicate != null)
{
query.where(predicate);
}
query.select(builder.countDistinct(root));
return getEntityManager().createQuery(query).getSingleResult();
}
/**
* WARNING, order will not be honoured by this method
*
* @return
*/
public int delete()
{
Preconditions.checkArgument(orders.size() == 0, "Order is not supported for delete");
CriteriaDelete<E> deleteCriteria = builder.createCriteriaDelete(entityClass);
root = deleteCriteria.getRoot();
if (predicate != null)
{
deleteCriteria.where(predicate);
}
Query query = getEntityManager().createQuery(deleteCriteria);
if (limit != null)
{
query.setMaxResults(limit);
}
if (startPosition != null)
{
query.setFirstResult(startPosition);
}
int result = query.executeUpdate();
getEntityManager().getEntityManagerFactory().getCache().evict(entityClass);
return result;
}
public JpaDslAbstract<E, R> distinct()
{
criteria.distinct(true);
return this;
}
public Expression<Number> divide(final Path<? extends Number> path1, final Path<? extends Number> path2)
{
return builder.quot(path1, path2);
}
public <T extends Number> Expression<Number> divide(final SingularAttribute<E, T> attribute,
final Path<? extends Number> path2)
{
return builder.quot(get(attribute), path2);
}
public Condition<E> eq(final Expression<String> expression, final String value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(expression, value);
}
};
}
public <J, V> Condition<E> eq(final JoinBuilder<E, J> join, final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(getJoin(join).get(field), value);
}
};
}
public <J, V> Condition<E> eq(final ListAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return equal(joinAttribute, joinType, field, value);
}
public <J> Condition<E> eq(ListAttribute<E, J> field, J value)
{
return equal(field, value);
}
public <J, V> Condition<E> eq(final SetAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return equal(joinAttribute, joinType, field, value);
}
public <J> Condition<E> eq(SetAttribute<E, J> field, J value)
{
return equal(field, value);
}
public <J> Condition<E> eq(SingularAttribute<? super E, J> field, J value)
{
return equal(field, value);
}
public <J, V> Condition<E> eq(final SingularAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return equal(joinAttribute, joinType, field, value);
}
public <J, V> Condition<E> equal(final ListAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.equal(join.get(field), value);
}
};
}
public <L> Condition<E> equal(final ListAttribute<E, L> field, final L value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(root.get(field), value);
}
};
}
public <J, V> Condition<E> equal(final SetAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.equal(join.get(field), value);
}
};
}
public <L> Condition<E> equal(final SetAttribute<E, L> field, final L value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(root.get(field), value);
}
};
}
public <J, V> Condition<E> equal(final SingularAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.equal(join.get(field), value);
}
};
}
public <L> Condition<E> equal(final SingularAttribute<? super E, L> field, final L value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(root.get(field), value);
}
};
}
public <J> AbstractCondition<E> exists(final JpaDslSubqueryBuilder<E, J> subquery)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.exists(subquery.getSubQuery());
}
};
}
public <L> JpaDslAbstract<E, R> fetch(ListAttribute<E, L> field, JoinType type)
{
root.fetch(field, type);
return this;
}
/**
* specify that JPA should fetch child entities in a single query!
*
* @param field
* @return
*/
public <L> JpaDslAbstract<E, R> fetch(SingularAttribute<E, L> field)
{
root.fetch(field, JoinType.LEFT);
return this;
}
public <L> JpaDslAbstract<E, R> fetch(SingularAttribute<E, L> field, JoinType type)
{
root.fetch(field, type);
return this;
}
/**
* for use with vaadin JPAContainer queryDelegate
*
* @param criteriaBuilder
* @param query
* @param predicates
*/
public void filtersWillBeAdded(List<Predicate> predicates)
{
Preconditions.checkArgument(isJpaContainerDelegate, "You must call isJpaContainerDelegate first!");
// the query wouldn't be built with the vaadinContainer's query object
// if you didn't call isJpaContainerDelegate.
if (predicate != null)
{
predicates.add(predicate);
}
}
public <K, T> Path<T> get(final JoinBuilder<E, K> join, final SingularAttribute<K, T> attribute)
{
return getJoin(join).get(attribute);
}
public <T> Path<T> get(final SingularAttribute<E, T> attribute)
{
return root.get(attribute);
}
/**
* it's very important that we don't retain a reference to the
* entitymanager, as when you instance this class and then use it in a
* closure you will end up trying to access a closed entitymanager
*
* @return
*/
protected EntityManager getEntityManager()
{
final EntityManager em = EntityManagerProvider.getEntityManager();
Preconditions.checkNotNull(em,
"Entity manager has not been initialized, " + "if you are using a worker thread you will have to call "
+ "EntityManagerProvider.createEntityManager()");
Preconditions.checkState(dontUseThis == em,
"The entity manager has changed since this class was instanced, this is very bad. "
+ "This class should be instanced and used strickly within the scope of a "
+ "single request/entitymanager");
Preconditions.checkState(em.isOpen(),
"The entity manager is closed, this can happen if you instance this class "
+ "and then use it in a closure when the closure gets called on a "
+ "separate thread or servlet request");
return em;
}
@SuppressWarnings("unchecked")
protected <K> Join<E, K> getJoin(JoinBuilder<E, K> joinBuilder)
{
Join<E, K> join = (Join<E, K>) joins2.get(joinBuilder);
if (join == null)
{
join = joinBuilder.getJoin(root, builder);
joins2.put(joinBuilder, join);
}
return join;
}
private <J> Join<E, J> getJoin(ListAttribute<? super E, J> joinAttribute, JoinType joinType)
{
JoinBuilder<E, J> jb = join(joinAttribute, joinType);
return getJoin(jb);
}
private <J> Join<E, J> getJoin(SetAttribute<? super E, J> joinAttribute, JoinType joinType)
{
JoinBuilder<E, J> jb = join(joinAttribute, joinType);
return getJoin(jb);
}
private <J> Join<E, J> getJoin(SingularAttribute<? super E, J> joinAttribute, JoinType joinType)
{
JoinBuilder<E, J> jb = join(joinAttribute, joinType);
return getJoin(jb);
}
public List<R> getResultList()
{
return prepareQuery().getResultList();
}
public R getSingleResult()
{
limit(1);
return prepareQuery().getSingleResult();
}
public R getSingleResultOrNull()
{
limit(1);
List<R> resultList = prepareQuery().getResultList();
if (resultList.size() == 0)
{
return null;
}
return resultList.get(0);
}
public <V extends Comparable<? super V>> Condition<E> greaterThan(final SingularAttribute<E, V> field,
final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.greaterThan(root.get(field), value);
}
};
}
public <J> Condition<E> greaterThanOrEqualTo(final JoinBuilder<E, J> join, final SingularAttribute<J, Date> field,
final Date value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.greaterThanOrEqualTo(getJoin(join).get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> greaterThanOrEqualTo(
final ListAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.greaterThanOrEqualTo(join.get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> greaterThanOrEqualTo(
final SetAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.greaterThanOrEqualTo(join.get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> greaterThanOrEqualTo(
final SingularAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.greaterThanOrEqualTo(join.get(field), value);
}
};
}
public <V extends Comparable<? super V>> Condition<E> greaterThanOrEqualTo(final SingularAttribute<E, V> field,
final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.greaterThanOrEqualTo(root.get(field), value);
}
};
}
public <V extends Comparable<? super V>> Condition<E> greaterThanOrEqualTo(final TypedPath<E, V> field,
final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.greaterThanOrEqualTo(field.path, value);
}
};
}
public JpaDslAbstract<E, R> groupBy(Expression<?>... expressions)
{
criteria.groupBy(expressions);
return this;
}
public <V> Condition<E> gtEq(final JoinBuilder<E, V> joinBuilder, final SingularAttribute<V, Date> field,
final Date value)
{
return greaterThanOrEqualTo(joinBuilder, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> gtEq(final ListAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return greaterThanOrEqualTo(joinAttribute, joinType, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> gtEq(final SetAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return greaterThanOrEqualTo(joinAttribute, joinType, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> gtEq(final SingularAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return greaterThanOrEqualTo(joinAttribute, joinType, field, value);
}
public Condition<E> gtEq(SingularAttribute<E, Date> field, Date value)
{
return greaterThanOrEqualTo(field, value);
}
public <V, K> Condition<E> in(final JoinBuilder<E, V> join, final SingularAttribute<V, K> attribute,
final Collection<K> values)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return getJoin(join).get(attribute).in(values);
}
};
}
public <V> Condition<E> in(final SetAttribute<E, V> attribute, final Collection<V> values)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return root.get(attribute).in(values);
}
};
}
public <V> Condition<E> in(final SetAttribute<E, V> agents, final V agent)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return root.get(agents).in(agent);
}
};
}
public <V> Condition<E> in(final SingularAttribute<E, V> attribute, final Collection<V> values)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
if (values.isEmpty())
{
throw new RuntimeException("Empty set supplied for IN clause");
}
return root.get(attribute).in(values);
}
};
}
public <V> Condition<E> in(final SingularAttribute<E, V> attribute, final V[] values)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return root.get(attribute).in(values);
}
};
}
public Condition<E> isEmptyString(final SingularAttribute<E, String> attribute)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.or(builder.isNull(root.get(attribute)),
builder.equal(builder.length(root.get(attribute)), 0));
}
};
}
public <L, J> Condition<E> isNotNull(final JoinBuilder<E, L> join, final SingularAttribute<L, J> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNotNull(getJoin(join).get(field));
}
};
}
public <L> Condition<E> isNotNull(final SingularAttribute<E, L> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNotNull(root.get(field));
}
};
}
public Condition<E> isNull(final Condition<E> condition)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNull(condition.getPredicates());
}
};
}
public <L, J> Condition<E> isNull(final JoinBuilder<E, L> join, final SingularAttribute<L, J> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNull(getJoin(join).get(field));
}
};
}
public <L> Condition<E> isNull(final SingularAttribute<E, L> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNull(root.get(field));
}
};
}
public <K> Condition<E> isNull(final TypedPath<E, K> path)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isNull(path.path);
}
};
}
public <L> Condition<E> isTrue(final JoinBuilder<E, L> join, final SingularAttribute<L, Boolean> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isTrue(getJoin(join).get(field));
}
};
}
public Condition<E> isTrue(final SingularAttribute<E, Boolean> field)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.isTrue(root.get(field));
}
};
}
public <K> JoinBuilder<E, K> join(final ListAttribute<? super E, K> attribute)
{
return new JoinBuilder<>(attribute, JoinType.INNER, false);
}
public <K> JoinBuilder<E, K> join(final ListAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, false);
}
public <K> JoinBuilder<E, K> join(final SetAttribute<? super E, K> attribute)
{
return new JoinBuilder<>(attribute, JoinType.INNER, false);
}
public <K> JoinBuilder<E, K> join(final SetAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, false);
}
public <K> JoinBuilder<E, K> join(final SingularAttribute<? super E, K> attribute)
{
return new JoinBuilder<>(attribute, JoinType.INNER, false);
}
public <K> JoinBuilder<E, K> join(final SingularAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, false);
}
public <K> JoinBuilder<E, K> joinFetch(final ListAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, true);
}
public <K> JoinBuilder<E, K> joinFetch(final SetAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, true);
}
public <K> JoinBuilder<E, K> joinFetch(final SingularAttribute<? super E, K> attribute, JoinType type)
{
return new JoinBuilder<>(attribute, type, true);
}
public <J> Condition<E> joinLike(final SingularAttribute<E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, String> field, final String value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.like(join.get(field), value);
}
};
}
public <K> JoinBuilder<E, K> leftJoin(final SingularAttribute<? super E, K> attribute)
{
return new JoinBuilder<>(attribute, JoinType.LEFT, false);
}
public <J, V extends Comparable<? super V>> Condition<E> lessThan(
final SingularAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.lessThan(join.get(field), value);
}
};
}
public <V extends Comparable<? super V>> Condition<E> lessThan(final SingularAttribute<? super E, V> field,
final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.lessThan(root.get(field), value);
}
};
}
public <J> Condition<E> lessThanOrEqualTo(final JoinBuilder<E, J> join, final SingularAttribute<J, Date> field,
final Date value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.lessThanOrEqualTo(getJoin(join).get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> lessThanOrEqualTo(
final ListAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.lessThanOrEqualTo(join.get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> lessThanOrEqualTo(
final SetAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.lessThanOrEqualTo(join.get(field), value);
}
};
}
public <J, V extends Comparable<? super V>> Condition<E> lessThanOrEqualTo(
final SingularAttribute<? super E, J> joinAttribute, final JoinType joinType,
final SingularAttribute<J, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
Join<E, J> join = getJoin(joinAttribute, joinType);
return builder.lessThanOrEqualTo(join.get(field), value);
}
};
}
public <V extends Comparable<? super V>> Condition<E> lessThanOrEqualTo(final SingularAttribute<E, V> field,
final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.lessThanOrEqualTo(root.get(field), value);
}
};
}
public <V extends Comparable<? super V>> Condition<E> lessThanOrEqualTo(final TypedPath<E, V> field, final V value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.lessThanOrEqualTo(field.path, value);
}
};
}
public Condition<E> like(final Expression<String> concat, final String value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.like(concat, value);
}
};
}
public <V> Condition<E> like(final JoinBuilder<E, V> join, final SingularAttribute<V, String> attribute,
final String pattern)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.like(getJoin(join).get(attribute), pattern);
}
};
}
public Condition<E> like(final SingularAttribute<? super E, String> field, final String value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.like(root.get(field), value);
}
};
}
public JpaDslAbstract<E, R> limit(int limit)
{
this.limit = limit;
return this;
}
public Condition<E> lt(SingularAttribute<? super E, Date> field, Date value)
{
return lessThan(field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> lt(final SingularAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return lessThan(joinAttribute, joinType, field, value);
}
public <V> Condition<E> ltEq(final JoinBuilder<E, V> joinBuilder, final SingularAttribute<V, Date> field,
final Date value)
{
return lessThanOrEqualTo(joinBuilder, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> ltEq(final ListAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return lessThanOrEqualTo(joinAttribute, joinType, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> ltEq(final SetAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return lessThanOrEqualTo(joinAttribute, joinType, field, value);
}
public <J, V extends Comparable<? super V>> Condition<E> ltEq(final SingularAttribute<? super E, J> joinAttribute,
final JoinType joinType, final SingularAttribute<J, V> field, final V value)
{
return lessThanOrEqualTo(joinAttribute, joinType, field, value);
}
public Condition<E> ltEq(SingularAttribute<E, Date> field, Date value)
{
return lessThanOrEqualTo(field, value);
}
public <T extends Number> Expression<T> max(final SingularAttribute<E, T> attribute)
{
return builder.max(root.get(attribute));
}
public <J> AbstractCondition<E> not(final Condition<E> condition)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.not(condition.getPredicates());
}
};
}
public <J, L> Condition<E> notEqual(final JoinBuilder<E, J> join, final SingularAttribute<J, L> field,
final L value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.notEqual(getJoin(join).get(field), value);
}
};
}
public <L> Condition<E> notEqual(final SingularAttribute<E, L> field, final L value)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.notEqual(root.get(field), value);
}
};
}
public <J> AbstractCondition<E> notExists(final JpaDslSubqueryBuilder<E, J> subquery)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.not(builder.exists(subquery.getSubQuery()));
}
};
}
// Useful when building dynamic queries
public Condition<E> oneEqualsOne()
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.equal(builder.literal(1), 1);
}
};
}
@SuppressWarnings("unchecked")
public Condition<E> or(final Condition<E>... conditions)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
final List<Predicate> predicates = new ArrayList<>(conditions.length);
for (Condition<E> condition : conditions)
{
predicates.add(condition.getPredicates());
}
return builder.or(predicates.toArray(new Predicate[predicates.size()]));
}
};
}
public Condition<E> or(final Condition<E> c1, final Condition<E> c2)
{
return new AbstractCondition<E>()
{
@Override
public Predicate getPredicates()
{
return builder.or(c1.getPredicates(), c2.getPredicates());
}
};
}
public <K, V> JpaDslAbstract<E, R> orderBy(JoinBuilder<E, K> join, SingularAttribute<K, V> field, boolean asc)
{
if (asc)
{
orders.add(builder.asc(getJoin(join).get(field)));
}
else
{
orders.add(builder.desc(getJoin(join).get(field)));
}
return this;
}
public JpaDslAbstract<E, R> orderBy(SingularAttribute<E, ?> field, boolean asc)
{
if (asc)
{
orders.add(builder.asc(root.get(field)));
}
else
{
orders.add(builder.desc(root.get(field)));
}
return this;
}
public JpaDslAbstract<E, R> orderBy(String field, boolean asc)
{
List<String> attributes = Arrays.asList(field.split("\\."));
Path<Object> path = null;
for (String attribute : attributes)
{
if (path == null)
{
path = root.get(attribute);
}
else
{
path = path.get(attribute);
}
}
if (asc)
{
orders.add(builder.asc(path));
}
else
{
orders.add(builder.desc(path));
}
return this;
}
public <V, J> TypedPath<E, V> path(SingularAttribute<? super E, J> partA, SingularAttribute<J, V> partB)
{
return new TypedPath<>(root.get(partA).get(partB));
}
TypedQuery<R> prepareQuery()
{
if (predicate != null)
{
criteria.where(predicate);
}
if (orders.size() > 0)
{
criteria.orderBy(orders);
}
TypedQuery<R> query = getEntityManager().createQuery(criteria);
if (limit != null)
{
query.setMaxResults(limit);
}
if (startPosition != null)
{
query.setFirstResult(startPosition);
}
return query;
}
public JpaDslAbstract<E, R> startPosition(int startPosition)
{
this.startPosition = startPosition;
return this;
}
public <J> JpaDslSubqueryBuilder<E, J> subQuery(Class<J> target)
{
return new JpaDslSubqueryBuilder<>(target, criteria, root);
}
public <T extends Number> Expression<T> sum(final SingularAttribute<E, T> attribute)
{
return builder.sum(root.get(attribute));
}
public <K> Expression<String> trim(JoinBuilder<E, K> join, SingularAttribute<K, String> attribute)
{
return builder.trim(getJoin(join).get(attribute));
}
public Expression<String> trim(final SingularAttribute<E, String> attribute)
{
return builder.trim(root.get(attribute));
}
/**
* WARNING, order will not be honoured by this method
*
* @param attribute
* @param value
*
* @return
*/
public <F extends Object> int update(Map<SingularAttribute<E, F>, F> updatemap)
{
Preconditions.checkArgument(orders.size() == 0, "Order is not supported for delete");
CriteriaUpdate<E> updateCriteria = builder.createCriteriaUpdate(entityClass);
root = updateCriteria.getRoot();
if (predicate != null)
{
updateCriteria.where(predicate);
for (Entry<SingularAttribute<E, F>, F> update : updatemap.entrySet())
{
updateCriteria.set(update.getKey(), update.getValue());
}
}
Query query = getEntityManager().createQuery(updateCriteria);
if (limit != null)
{
query.setMaxResults(limit);
}
if (startPosition != null)
{
query.setFirstResult(startPosition);
}
int result = query.executeUpdate();
getEntityManager().getEntityManagerFactory().getCache().evict(entityClass);
return result;
}
/**
* WARNING, order will not be honoured by this method
*
* @param attribute
* @param value
*
* @return
*/
public <F> int update(SingularAttribute<E, F> attribute, F value)
{
Preconditions.checkArgument(orders.size() == 0, "Order is not supported for delete");
CriteriaUpdate<E> updateCriteria = builder.createCriteriaUpdate(entityClass);
root = updateCriteria.getRoot();
if (predicate != null)
{
updateCriteria.where(predicate);
updateCriteria.set(attribute, value);
}
Query query = getEntityManager().createQuery(updateCriteria);
if (limit != null)
{
query.setMaxResults(limit);
}
if (startPosition != null)
{
query.setFirstResult(startPosition);
}
int result = query.executeUpdate();
getEntityManager().getEntityManagerFactory().getCache().evict(entityClass);
return result;
}
public JpaDslAbstract<E, R> where(Condition<E> condition)
{
predicate = condition.getPredicates();
return this;
}
@SuppressWarnings("unchecked")
public JpaDslAbstract<E, R> where(final Condition<E>... conditions)
{
final List<Predicate> predicates = new ArrayList<>(conditions.length);
for (Condition<E> condition : conditions)
{
predicates.add(condition.getPredicates());
}
predicate = builder.and(predicates.toArray(new Predicate[predicates.size()]));
return this;
}
public JpaDslAbstract<E, R> where(final List<Condition<E>> conditions)
{
final List<Predicate> predicates = new ArrayList<>(conditions.size());
for (Condition<E> condition : conditions)
{
predicates.add(condition.getPredicates());
}
predicate = builder.and(predicates.toArray(new Predicate[predicates.size()]));
return this;
}
}