diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/query/sort/StoreSorter.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/query/sort/StoreSorter.java index e3ca3f985..bbe3f18d5 100644 --- a/concourse-server/src/main/java/com/cinchapi/concourse/server/query/sort/StoreSorter.java +++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/query/sort/StoreSorter.java @@ -15,9 +15,14 @@ */ package com.cinchapi.concourse.server.query.sort; +import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; @@ -30,6 +35,7 @@ import com.cinchapi.concourse.lang.sort.Order; import com.cinchapi.concourse.lang.sort.OrderComponent; import com.cinchapi.concourse.server.storage.Store; +import com.google.common.collect.Lists; /** * A {@link StoreSorter} imposes an {@link Order} by value on a result set. The @@ -72,56 +78,88 @@ public final Stream>> sort( @Override public final Stream>> sort( Stream>> stream, @Nullable Long at) { - ArrayBuilder>>> comparators = ArrayBuilder - .builder(); - for (OrderComponent component : order.spec()) { + List spec = order.spec(); + if(spec.size() == 1) { + OrderComponent component = spec.get(0); String key = component.key(); - Timestamp timestamp = component.timestamp(); Direction direction = component.direction(); - Comparator>> $comparator = (e1, e2) -> { - long r1 = e1.getKey(); - long r2 = e2.getKey(); - Map d1 = e1.getValue(); - Map d2 = e2.getValue(); - V v1; - V v2; - if(timestamp == null) { - v1 = d1.get(key); - if(v1 == null) { - v1 = at != null ? lookup(key, r1, at) : lookup(key, r1); + Timestamp timestamp = component.timestamp(); + // TODO: check corner case of no timestamp provided, but there is an + // operation timestamp + // TODO: test + Collection> sorted = timestamp == null + ? store.browse(key).values() + : store.browse(key, timestamp.getMicros()).values(); + Map>> entries = stream + .collect(Collectors.toMap(Entry::getKey, entry -> entry)); + Stream> $; + if(direction == Direction.ASCENDING) { + $ = sorted.stream(); + } + else { + $ = Lists.reverse(new ArrayList<>(sorted)).stream(); + } + return $.flatMap(bucket -> bucket.stream()) + .map(record -> entries.get(record)) + .filter(entry -> entry != null); + } + else { + ArrayBuilder>>> comparators = ArrayBuilder + .builder(); + for (OrderComponent component : order.spec()) { + String key = component.key(); + Timestamp timestamp = component.timestamp(); + Direction direction = component.direction(); + Comparator>> $comparator = (e1, + e2) -> { + long r1 = e1.getKey(); + long r2 = e2.getKey(); + Map d1 = e1.getValue(); + Map d2 = e2.getValue(); + V v1; + V v2; + if(timestamp == null) { + v1 = d1.get(key); + if(v1 == null) { + v1 = at != null ? lookup(key, r1, at) + : lookup(key, r1); + } + v2 = d2.get(key); + if(v2 == null) { + v2 = at != null ? lookup(key, r2, at) + : lookup(key, r2); + } + } + else { + v1 = lookup(key, r1, timestamp.getMicros()); + v2 = lookup(key, r2, timestamp.getMicros()); + } + if(!Empty.ness().describes(v1) + && !Empty.ness().describes(v2)) { + // The coefficient is only applied when both values are + // non-empty. Otherwise, the empty value should float to + // the end of the sort, regardless of the specified + // direction + return direction.coefficient() * compare(v1, v2); + } + else if(!Empty.ness().describes(v1)) { + return -1; + } + else if(!Empty.ness().describes(v2)) { + return 1; } - v2 = d2.get(key); - if(v2 == null) { - v2 = at != null ? lookup(key, r2, at) : lookup(key, r2); + else { + return 0; } - } - else { - v1 = lookup(key, r1, timestamp.getMicros()); - v2 = lookup(key, r2, timestamp.getMicros()); - } - if(!Empty.ness().describes(v1) && !Empty.ness().describes(v2)) { - // The coefficient is only applied when both values are - // non-empty. Otherwise, the empty value should float to the - // end of the sort, regardless of the specified direction - return direction.coefficient() * compare(v1, v2); - } - else if(!Empty.ness().describes(v1)) { - return -1; - } - else if(!Empty.ness().describes(v2)) { - return 1; - } - else { - return 0; - } - }; - comparators.add($comparator); + }; + comparators.add($comparator); + } + comparators.add((e1, e2) -> e1.getKey().compareTo(e2.getKey())); + Comparator>> comparator = CompoundComparator + .of(comparators.build()); + return stream.sorted(comparator); } - comparators.add((e1, e2) -> e1.getKey().compareTo(e2.getKey())); - Comparator>> comparator = CompoundComparator - .of(comparators.build()); - return stream.sorted(comparator); } /**