/**
* Copyright (c)2010-2011 Enterprise Website Content Management System(EWCMS), All rights reserved.
* EWCMS PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
* http://www.ewcms.com
*/
package com.ewcms.common.query.jpa;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
public class EntityQueryTemplate implements Predicatesable,QueryTemplateable{
private static final int NO_SETTING = -1;
private EntityManager em;
private CriteriaBuilder builder;
private Root<?> root;
private CriteriaQuery<Object> criteria;
private List<Predicate> predicates = new ArrayList<Predicate>();
private List<Selection<?>> selections = new ArrayList<Selection<?>>();
private List<Order> orders = new ArrayList<Order>();
private int startPosition = NO_SETTING;
private int maxResults = NO_SETTING;
public EntityQueryTemplate(EntityManager em,Class<?> entityClass) {
this.em = em;
this.builder = em.getCriteriaBuilder();
this.criteria = builder.createQuery();
this.root = criteria.from(entityClass);
}
void pushPredicate(final Predicate predicate) {
predicates.add(predicate);
}
Predicate popPredicate() {
if (predicates.isEmpty()) {
return null;
}
Predicate predicate = predicates.get(predicates.size() - 1);
predicates.remove(predicate);
return predicate;
}
<E> Path<E> get(final String name){
if(name.indexOf(".") > -1){
String attrs[] = name.split("\\.");
From<?,?> join = root;
for(int i = 0 ; i < attrs.length - 1; i++){
join = join.join(attrs[i]);
}
return join.get(attrs[attrs.length-1]);
}else{
return root.get(name);
}
}
public EntityQueryTemplate select(String name){
selections.add(root.get(name));
return this;
}
public EntityQueryTemplate select(SelectCallback callback){
selections.add(callback.select(builder, root));
return this;
}
public EntityQueryTemplate multiselect(String... names){
for(String name : names){
selections.add(root.get(name));
}
return this;
}
@Override
public EntityQueryTemplate eq(final String name, final Object value) {
pushPredicate(builder.equal(get(name), value));
return this;
}
@Override
public EntityQueryTemplate notEq(final String name, final Object value) {
pushPredicate(builder.notEqual(get(name), value));
return this;
}
@Override
public EntityQueryTemplate gt(final String name, final Number value) {
Path<Number> path = get(name);
pushPredicate(builder.gt(path, value));
return this;
}
@Override
public EntityQueryTemplate ge(final String name, final Number value) {
Path<Number> path = get(name);
pushPredicate(builder.ge(path, value));
return this;
}
@Override
public EntityQueryTemplate lt(final String name, final Number value) {
Path<Number> path = get(name);
pushPredicate(builder.lt(path, value));
return this;
}
@Override
public EntityQueryTemplate le(final String name, final Number value) {
Path<Number> path = get(name);
pushPredicate(builder.le(path, value));
return this;
}
private String likePatter(final String patter, final String value) {
return String.format(patter, value);
}
@Override
public EntityQueryTemplate likeStart(final String name, final String value) {
Path<String> path = get(name);
String patter = likePatter("%s%%", value);
pushPredicate(builder.like(path, patter));
return this;
}
@Override
public EntityQueryTemplate likeAnywhere(final String name, final String value) {
Path<String> path = get(name);
String patter = likePatter("%%%s%%", value);
pushPredicate(builder.like(path, patter));
return this;
}
@Override
public EntityQueryTemplate likeEnd(final String name, final String value) {
Path<String> path = get(name);
String patter = likePatter("%%%s", value);
pushPredicate(builder.like(path, patter));
return this;
}
@Override
public <Y extends Comparable<? super Y>> EntityQueryTemplate between(final String name, final Y lo, final Y hi) {
Path<Y> path = get(name);
pushPredicate(builder.between(path, lo, hi));
return this;
}
@Override
public EntityQueryTemplate in(final String name, final Collection<?> value) {
pushPredicate(builder.in(get(name)).value(value));
return this;
}
@Override
public EntityQueryTemplate in(final String name, final Object[] value) {
return in(name, Arrays.asList(value));
}
@Override
public EntityQueryTemplate isNull(final String name) {
pushPredicate(builder.isNull(get(name)));
return this;
}
@Override
public EntityQueryTemplate isNotNull(final String name) {
pushPredicate(builder.isNotNull(get(name)));
return this;
}
@Override
public EntityQueryTemplate and() {
while ( predicates.size()>1 ) {
and(this);
}
return this;
}
@Override
public EntityQueryTemplate and(final Predicatesable query) {
Predicate x = popPredicate();
Predicate y = popPredicate();
if (x != null && y != null) {
pushPredicate(builder.and(x, y));
}
return this;
}
@Override
public EntityQueryTemplate or() {
while (predicates.size()>1) {
or(this);
}
return this;
}
@Override
public EntityQueryTemplate or(final Predicatesable query) {
Predicate x = popPredicate();
Predicate y = popPredicate();
if (x != null && y != null) {
pushPredicate(builder.or(x, y));
}
return this;
}
@Override
public EntityQueryTemplate not(final Predicatesable query) {
Predicate x = popPredicate();
if (x != null) {
pushPredicate(builder.not(x));
}
return this;
}
public EntityQueryTemplate orderAsc(final String name) {
orders.add(builder.asc(get(name)));
return this;
}
public EntityQueryTemplate orderDesc(final String name) {
orders.add(builder.desc(get(name)));
return this;
}
@Override
public EntityQueryTemplate setFirstResult(int startPosition){
this.startPosition = startPosition;
return this;
}
@Override
public EntityQueryTemplate setMaxResults(int maxResults){
this.maxResults = maxResults;
return this;
}
protected void buildSelect(CriteriaQuery<Object> c){
if(selections.isEmpty()){
c.select(root);
}else{
if(selections.size() == 1){
c.select(selections.get(0));
}else{
c.select(builder.array(selections.toArray(new Selection<?>[selections.size()])));
}
}
}
protected void buildWhere(CriteriaQuery<Object> c){
if(!predicates.isEmpty()){
and();
c.where(predicates.get(0));
}
}
protected void buildOrder(CriteriaQuery<Object> c){
c.orderBy(orders);
}
@Override
public Object getResultSingle(){
buildSelect(criteria);
buildWhere(criteria);
buildOrder(criteria);
return em.createQuery(criteria).getSingleResult();
}
@Override
public List<Object> getResultList(){
buildSelect(criteria);
buildWhere(criteria);
buildOrder(criteria);
TypedQuery<Object> query = em.createQuery(criteria);
if(startPosition != NO_SETTING){
query.setFirstResult(startPosition);
}
if(maxResults != NO_SETTING){
query.setMaxResults(maxResults);
}
return query.getResultList();
}
@Override
public <T> T execute(QueryTemplateCallback<T> callback){
return callback.doInQuery(em);
}
}