Skip to content

Instantly share code, notes, and snippets.

@dmitrygusev
Created May 31, 2016 11:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmitrygusev/1ff2d8f6d6f363595b73b581016c7733 to your computer and use it in GitHub Desktop.
Save dmitrygusev/1ff2d8f6d6f363595b73b581016c7733 to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.mysema.query.BooleanBuilder;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Order;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.expr.ComparableExpression;
import com.mysema.query.types.expr.NumberExpression;
public class QueryHelper
{
/**
* Implementing pagination with seek method
* http://use-the-index-luke.com/no-offset
*/
public static PredicateDecorator getSeekPredicate(List<Pair<Order, Expression<?>>> fields, List<Comparable<?>> values)
{
// where f1 < a
// or (f1 = a and f2 < b)
// or (f1 = a and f2 = b and f3 < c)
return predicate -> {
List<Predicate> expressions = new ArrayList<>();
for (int i = 0; i < fields.size(); i++)
{
Expression<?> left = fields.get(i).getValue();
Comparable<?> right = values.get(i);
BooleanBuilder condition = new BooleanBuilder(
fields.get(i).getKey() == Order.DESC
? lt(left, right)
: gt(left, right));
for (int j = 0; j < fields.size(); j++)
{
Expression<?> field = fields.get(j).getValue();
Comparable<?> value = values.get(j);
if (j < i)
{
condition.and(eq(field, value));
}
else
{
expressions.add(condition);
break;
}
}
}
predicate.andAnyOf(expressions.toArray(new Predicate[0]));
};
}
@SuppressWarnings({ "unchecked" })
private static <T extends Comparable<?>, A extends Number & Comparable<Number>> Predicate lt(Expression<?> left, Comparable<?> right)
{
if (left instanceof ComparableExpression)
{
return ((ComparableExpression<T>) left).lt((T) right);
}
if (left instanceof NumberExpression)
{
return ((NumberExpression<A>) left).lt((A) right);
}
throw new IllegalArgumentException(String.valueOf(left));
}
@SuppressWarnings({ "unchecked" })
private static <T extends Comparable<?>, A extends Number & Comparable<Number>> Predicate gt(Expression<?> left, Comparable<?> right)
{
if (left instanceof ComparableExpression)
{
return ((ComparableExpression<T>) left).gt((T) right);
}
if (left instanceof NumberExpression)
{
return ((NumberExpression<A>) left).gt((A) right);
}
throw new IllegalArgumentException(String.valueOf(left));
}
@SuppressWarnings({ "unchecked" })
private static <T extends Comparable<?>, A extends Number & Comparable<Number>> Predicate eq(Expression<?> left, Comparable<?> right)
{
if (left instanceof ComparableExpression)
{
return ((ComparableExpression<T>) left).eq((T) right);
}
if (left instanceof NumberExpression)
{
return ((NumberExpression<A>) left).eq((A) right);
}
throw new IllegalArgumentException(String.valueOf(left));
}
}
import com.mysema.query.jpa.JPQLQuery;
import com.mysema.query.jpa.impl.JPAQuery;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Order;
import org.joda.time.DateTime;
// ...
DateTime after = ...;
Long lastId = ...;
// ...
List<Pair<Order, Expression<?>>> fields = new ArrayList<>();
List<Comparable<?>> values = new ArrayList<>();
if (after != null)
{
fields.add(Pair.of(Order.ASC, myEntity.createdAt));
values.add(after.toDate());
}
if (lastId != null)
{
fields.add(Pair.of(Order.ASC, myEntity.id));
values.add(lastId);
}
JPQLQuery query = builder
.decorate(QueryHelper.getSeekPredicate(fields, values))
.build()
.orderBy(myEntity.createdAt.asc(), myEntity.id.asc());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment