From 6ddab435e650a47355e2840d0ca65d0088f2f437 Mon Sep 17 00:00:00 2001 From: Alexey Egorov Date: Wed, 22 Feb 2017 01:18:17 -0500 Subject: [PATCH] fix for #2106 enable NullsLast support in querydsl-collections orderBy() --- CHANGELOG.md | 2 ++ .../collections/DefaultQueryEngine.java | 4 +++- .../querydsl/collections/MultiComparator.java | 20 +++++++++-------- .../collections/MultiComparatorTest.java | 3 ++- .../com/querydsl/collections/OrderTest.java | 22 ++++++++++++++++--- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b8b0bb7f..b562a5ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ A huge thanks goes out to all contributors that made this release possible in th * **[@mp911de](https://github.com/mp911de)**, for working on the MongoDB Document API; * **[@daniel-shuy](https://github.com/daniel-shuy)**, for working on decoupling `querydsl-sql` from `joda-time:joda-time`; * **[@heesuk-ahn](https://github.com/heesuk-ahn)**, for working on improved Hibernate support and count query generation in `JPASQLQuery`; +* **[@harshtuna](https://github.com/harshtuna)**, for working on NullsLast ordering in `querydsl-collections`; * **[@jwgmeligmeyling](https://github.com/jwgmeligmeyling)**, **[@Shredder121](https://github.com/Shredder121)**, **[@johnktims](https://github.com/johnktims)**, **[@idosal](https://github.com/idosal)** and **[@robertandrewbain](https://github.com/robertandrewbain)**. #### New features @@ -34,6 +35,7 @@ A huge thanks goes out to all contributors that made this release possible in th does not have to be available at runtime and is not a transitive dependency. * [#658](https://github.com/querydsl/querydsl/issues/658) - Added `JPAExpressions#treat` which can be used to generate JPA 2.1 Treated path expressions. * [#2666](https://github.com/querydsl/querydsl/issues/2666) - More descriptive error message when using unsupported query features in JPA. +* [#2106](https://github.com/querydsl/querydsl/issues/2106) - Support NullsLast ordering in `querydsl-collections`. #### Bugfixes diff --git a/querydsl-collections/src/main/java/com/querydsl/collections/DefaultQueryEngine.java b/querydsl-collections/src/main/java/com/querydsl/collections/DefaultQueryEngine.java index bc8a42644..e09247cdf 100644 --- a/querydsl-collections/src/main/java/com/querydsl/collections/DefaultQueryEngine.java +++ b/querydsl-collections/src/main/java/com/querydsl/collections/DefaultQueryEngine.java @@ -214,13 +214,15 @@ public class DefaultQueryEngine implements QueryEngine { List> orderBy = metadata.getOrderBy(); Expression[] orderByExpr = new Expression[orderBy.size()]; boolean[] directions = new boolean[orderBy.size()]; + boolean[] nullsLast = new boolean[orderBy.size()]; for (int i = 0; i < orderBy.size(); i++) { orderByExpr[i] = (Expression) orderBy.get(i).getTarget(); directions[i] = orderBy.get(i).getOrder() == Order.ASC; + nullsLast[i] = orderBy.get(i).getNullHandling() == OrderSpecifier.NullHandling.NullsLast; } Expression expr = new ArrayConstructorExpression(Object[].class, orderByExpr); Evaluator orderEvaluator = evaluatorFactory.create(metadata, sources, expr); - list.sort(new MultiComparator(orderEvaluator, directions)); + list.sort(new MultiComparator(orderEvaluator, directions, nullsLast)); } private List project(QueryMetadata metadata, List> sources, List list) { diff --git a/querydsl-collections/src/main/java/com/querydsl/collections/MultiComparator.java b/querydsl-collections/src/main/java/com/querydsl/collections/MultiComparator.java index 5d64892f6..a68e3740b 100644 --- a/querydsl-collections/src/main/java/com/querydsl/collections/MultiComparator.java +++ b/querydsl-collections/src/main/java/com/querydsl/collections/MultiComparator.java @@ -23,7 +23,6 @@ import com.querydsl.core.util.NullSafeComparableComparator; * {@code MultiComparator} compares arrays * * @param element type - * * @author tiwe */ public class MultiComparator implements Comparator, Serializable { @@ -35,16 +34,19 @@ public class MultiComparator implements Comparator, Serializable { private final boolean[] asc; + private final boolean[] nullsLast; + private final transient Evaluator ev; - public MultiComparator(Evaluator ev, boolean[] directions) { + public MultiComparator(Evaluator ev, boolean[] directions, boolean[] nullsLast) { this.ev = ev; this.asc = directions.clone(); + this.nullsLast = nullsLast.clone(); } @Override public int compare(T o1, T o2) { - if (o1.getClass().isArray()) { + if (o1 instanceof Object[]) { return innerCompare(ev.evaluate((Object[]) o1), ev.evaluate((Object[]) o2)); } else { return innerCompare(ev.evaluate(o1), ev.evaluate(o2)); @@ -53,16 +55,16 @@ public class MultiComparator implements Comparator, Serializable { private int innerCompare(Object[] o1, Object[] o2) { for (int i = 0; i < o1.length; i++) { - int res; if (o1[i] == null) { - res = o2[i] == null ? 0 : -1; + return o2[i] == null ? 0 : nullsLast[i] ? 1 : -1; } else if (o2[i] == null) { - res = 1; + return nullsLast[i] ? -1 : 1; } else { + int res; res = naturalOrder.compare(o1[i], o2[i]); - } - if (res != 0) { - return asc[i] ? res : -res; + if (res != 0) { + return asc[i] ? res : -res; + } } } return 0; diff --git a/querydsl-collections/src/test/java/com/querydsl/collections/MultiComparatorTest.java b/querydsl-collections/src/test/java/com/querydsl/collections/MultiComparatorTest.java index a73221d6d..071487898 100644 --- a/querydsl-collections/src/test/java/com/querydsl/collections/MultiComparatorTest.java +++ b/querydsl-collections/src/test/java/com/querydsl/collections/MultiComparatorTest.java @@ -34,7 +34,8 @@ public class MultiComparatorTest { @Test public void test() { - MultiComparator comparator = new MultiComparator(evaluator, new boolean[]{true, true}); + MultiComparator comparator = new MultiComparator(evaluator, new boolean[]{true, true}, + new boolean[]{true, true}); assertTrue(comparator.compare(new Object[]{"a", "b"}, new Object[]{"a","c"}) < 0); assertTrue(comparator.compare(new Object[]{"b", "a"}, new Object[]{"a","b"}) > 0); assertTrue(comparator.compare(new Object[]{"b", "b"}, new Object[]{"b","b"}) == 0); diff --git a/querydsl-collections/src/test/java/com/querydsl/collections/OrderTest.java b/querydsl-collections/src/test/java/com/querydsl/collections/OrderTest.java index d46cd6d65..f515888e1 100644 --- a/querydsl-collections/src/test/java/com/querydsl/collections/OrderTest.java +++ b/querydsl-collections/src/test/java/com/querydsl/collections/OrderTest.java @@ -60,9 +60,25 @@ public class OrderTest extends AbstractQueryTest { @Test public void with_null() { - List cats = Arrays.asList(new Cat(), new Cat("Bob")); - assertEquals(cats, query().from(cat, cats).orderBy(cat.name.asc()).select(cat).fetch()); - assertEquals(Arrays.asList(cats.get(1), cats.get(0)), query().from(cat, cats).orderBy(cat.name.desc()).select(cat).fetch()); + Cat unknown = new Cat(); + Cat bob = new Cat("Bob"); + Cat alex = new Cat("Alex"); + List cats = Arrays.asList(alex, unknown, bob); + assertEquals(Arrays.asList(unknown, alex, bob), + query().from(cat, cats).orderBy(cat.name.asc()).select(cat).fetch()); + assertEquals(Arrays.asList(unknown, bob, alex), + query().from(cat, cats).orderBy(cat.name.desc()).select(cat).fetch()); + } + @Test + public void with_nulls_last() { + Cat unknown = new Cat(); + Cat bob = new Cat("Bob"); + Cat alex = new Cat("Alex"); + List cats = Arrays.asList(alex, unknown, bob); + assertEquals(Arrays.asList(bob, alex, unknown), + query().from(this.cat, cats).orderBy(this.cat.name.desc().nullsLast()).select(this.cat).fetch()); + assertEquals(Arrays.asList(alex, bob, unknown), + query().from(this.cat, cats).orderBy(this.cat.name.asc().nullsLast()).select(this.cat).fetch()); } }