package com.ctp.cdi.query.builder.result; import java.util.Iterator; import java.util.List; import javax.persistence.FlushModeType; import javax.persistence.LockModeType; import javax.persistence.Query; import javax.persistence.metamodel.SingularAttribute; import com.ctp.cdi.query.QueryResult; import com.ctp.cdi.query.builder.OrderDirection; import com.ctp.cdi.query.builder.QueryBuilder; import com.ctp.cdi.query.builder.postprocessor.CountQueryPostProcessor; import com.ctp.cdi.query.builder.postprocessor.FirstResultPostProcessor; import com.ctp.cdi.query.builder.postprocessor.FlushModePostProcessor; import com.ctp.cdi.query.builder.postprocessor.HintPostProcessor; import com.ctp.cdi.query.builder.postprocessor.LockModePostProcessor; import com.ctp.cdi.query.builder.postprocessor.MaxResultPostProcessor; import com.ctp.cdi.query.builder.postprocessor.OrderByQueryStringPostProcessor; import com.ctp.cdi.query.handler.CdiQueryInvocationContext; import com.ctp.cdi.query.handler.QueryStringPostProcessor; public class DefaultQueryResult<T> implements QueryResult<T> { private final QueryBuilder builder; private final CdiQueryInvocationContext context; private int page = 0; private int pageSize = 10; public DefaultQueryResult(QueryBuilder builder, CdiQueryInvocationContext context) { this.builder = builder; this.context = context; } @Override public <X> QueryResult<T> orderAsc(SingularAttribute<T, X> attribute) { context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.ASC)); return this; } @Override public QueryResult<T> orderAsc(String attribute) { context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.ASC)); return this; } @Override public <X> QueryResult<T> orderDesc(SingularAttribute<T, X> attribute) { context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.DESC)); return this; } @Override public QueryResult<T> orderDesc(String attribute) { context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.DESC)); return this; } @Override public <X> QueryResult<T> changeOrder(final SingularAttribute<T, X> attribute) { changeOrder(new ChangeOrder() { @Override public boolean matches(OrderByQueryStringPostProcessor orderBy) { return orderBy.matches(attribute); } @Override public void addDefault() { orderAsc(attribute); } }); return this; } @Override public QueryResult<T> changeOrder(final String attribute) { changeOrder(new ChangeOrder() { @Override public boolean matches(OrderByQueryStringPostProcessor orderBy) { return orderBy.matches(attribute); } @Override public void addDefault() { orderAsc(attribute); } }); return this; } @Override public QueryResult<T> clearOrder() { for (Iterator<QueryStringPostProcessor> it = context.getQueryStringPostProcessors().iterator(); it.hasNext();) { if (it.next() instanceof OrderByQueryStringPostProcessor) { it.remove(); } } return this; } @Override public QueryResult<T> maxResults(int max) { context.addJpaQueryPostProcessor(new MaxResultPostProcessor(max)); pageSize = max; return this; } @Override public QueryResult<T> firstResult(int first) { context.addJpaQueryPostProcessor(new FirstResultPostProcessor(first)); return this; } @Override public QueryResult<T> lockMode(LockModeType lockMode) { context.addJpaQueryPostProcessor(new LockModePostProcessor(lockMode)); return this; } @Override public QueryResult<T> flushMode(FlushModeType flushMode) { context.addJpaQueryPostProcessor(new FlushModePostProcessor(flushMode)); return this; } @Override public QueryResult<T> hint(String hint, Object value) { context.addJpaQueryPostProcessor(new HintPostProcessor(hint, value)); return this; } @Override @SuppressWarnings("unchecked") public List<T> getResultList() { return ((Query) builder.execute(context)).getResultList(); } @Override @SuppressWarnings("unchecked") public T getSingleResult() { return (T) ((Query) builder.execute(context)).getSingleResult(); } @Override public long count() { CountQueryPostProcessor counter = new CountQueryPostProcessor(); context.addJpaQueryPostProcessor(counter); try { Long result = (Long) ((Query) builder.execute(context)).getSingleResult(); return result.intValue(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } finally { context.removeJpaQueryPostProcessor(counter); } } @Override public QueryResult<T> withPageSize(int pageSize) { return maxResults(pageSize); } @Override public QueryResult<T> toPage(int page) { this.page = page; return firstResult(pageSize * page); } @Override public QueryResult<T> nextPage() { page = page + 1; return firstResult(pageSize * page); } @Override public QueryResult<T> previousPage() { page = page > 0 ? page - 1 : page; return firstResult(pageSize * page); } @Override public int countPages() { return (int) Math.ceil((double) count() / pageSize); } @Override public int currentPage() { return page; } @Override public int pageSize() { return pageSize; } private <X> QueryResult<T> changeOrder(ChangeOrder changeOrder) { for (QueryStringPostProcessor processor : context.getQueryStringPostProcessors()) { if (processor instanceof OrderByQueryStringPostProcessor) { OrderByQueryStringPostProcessor orderBy = (OrderByQueryStringPostProcessor) processor; if (changeOrder.matches(orderBy)) { orderBy.changeDirection(); return this; } } } changeOrder.addDefault(); return this; } private static abstract class ChangeOrder { public abstract boolean matches(OrderByQueryStringPostProcessor orderBy); public abstract void addDefault(); } }