aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main
diff options
context:
space:
mode:
authorLeif Åstrand <legioth@gmail.com>2017-01-17 16:22:55 +0200
committerDenis <denis@vaadin.com>2017-01-17 16:22:55 +0200
commit83b16a8ee742b676bd8ac8ef48e62b8fd64326e3 (patch)
tree23321774daa70bf2faf41be546fbae169b5dcf61 /server/src/main
parent487cb4ea0c5e51e7a9b85d6bbb6ab9200f6772f7 (diff)
downloadvaadin-framework-83b16a8ee742b676bd8ac8ef48e62b8fd64326e3.tar.gz
vaadin-framework-83b16a8ee742b676bd8ac8ef48e62b8fd64326e3.zip
Make data providers statefull with regards to default sort orders (#8247)
* Make data providers statefull with regards to default sort orders This is one of many steps towards #8245
Diffstat (limited to 'server/src/main')
-rw-r--r--server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java89
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ListDataProvider.java185
2 files changed, 180 insertions, 94 deletions
diff --git a/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java b/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
index 5f789e8a55..3606a99ade 100644
--- a/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
@@ -16,13 +16,15 @@
package com.vaadin.data.provider;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.vaadin.server.SerializableFunction;
import com.vaadin.server.SerializableToIntFunction;
-import com.vaadin.shared.Registration;
/**
* A {@link DataProvider} for any back end.
@@ -34,6 +36,8 @@ import com.vaadin.shared.Registration;
*/
public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> {
+ private List<SortOrder<String>> sortOrders = new ArrayList<>();
+
private final SerializableFunction<Query<T, F>, Stream<T>> request;
private final SerializableToIntFunction<Query<T, F>> sizeCallback;
@@ -57,46 +61,71 @@ public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> {
@Override
public Stream<T> fetch(Query<T, F> query) {
- return request.apply(query);
+ return request.apply(mixInSortOrders(query));
}
@Override
public int size(Query<T, F> query) {
- return sizeCallback.applyAsInt(query);
+ return sizeCallback.applyAsInt(mixInSortOrders(query));
+ }
+
+ private Query<T, F> mixInSortOrders(Query<T, F> query) {
+ Set<String> sortedPropertyNames = query.getSortOrders().stream()
+ .map(SortOrder::getSorted).collect(Collectors.toSet());
+
+ List<SortOrder<String>> combinedSortOrders = Stream
+ .concat(query.getSortOrders().stream(),
+ sortOrders.stream()
+ .filter(order -> !sortedPropertyNames
+ .contains(order.getSorted())))
+ .collect(Collectors.toList());
+
+ return new Query<>(query.getOffset(), query.getLimit(),
+ combinedSortOrders, query.getInMemorySorting(),
+ query.getFilter().orElse(null));
}
/**
- * Sets a default sorting order to the data provider.
+ * Sets a list of sort orders to use as the default sorting for this data
+ * provider. This overrides the sorting set by any other method that
+ * manipulates the default sorting of this data provider.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrder(SortOrder)
*
* @param sortOrders
- * a list of sorting information containing field ids and
- * directions
- * @return new data provider with modified sorting
+ * a list of sort orders to set, not <code>null</code>
*/
- @SuppressWarnings("serial")
- public BackEndDataProvider<T, F> sortingBy(
- List<SortOrder<String>> sortOrders) {
- BackEndDataProvider<T, F> parent = this;
- return new BackEndDataProvider<T, F>(query -> {
- List<SortOrder<String>> queryOrder = new ArrayList<>(
- query.getSortOrders());
- queryOrder.addAll(sortOrders);
- return parent.fetch(new Query<>(query.getOffset(), query.getLimit(),
- queryOrder, query.getInMemorySorting(),
- query.getFilter().orElse(null)));
- }, sizeCallback) {
-
- @Override
- public Registration addDataProviderListener(
- DataProviderListener listener) {
- return parent.addDataProviderListener(listener);
- }
+ public void setSortOrders(List<SortOrder<String>> sortOrders) {
+ this.sortOrders = Objects.requireNonNull(sortOrders,
+ "Sort orders cannot be null");
+ refreshAll();
+ }
- @Override
- public void refreshAll() {
- parent.refreshAll();
- }
- };
+ /**
+ * Sets a single sort order to use as the default sorting for this data
+ * provider. This overrides the sorting set by any other method that
+ * manipulates the default sorting of this data provider.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrders(List)
+ *
+ * @param sortOrder
+ * a sort order to set, or <code>null</code> to clear any
+ * previously set sort orders
+ */
+ public void setSortOrder(SortOrder<String> sortOrder) {
+ if (sortOrder == null) {
+ setSortOrders(Collections.emptyList());
+ } else {
+ setSortOrders(Collections.singletonList(sortOrder));
+ }
}
@Override
diff --git a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
index c6860c26cc..e1c8e8867c 100644
--- a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
@@ -19,11 +19,12 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
-import java.util.function.Function;
import java.util.stream.Stream;
+import com.vaadin.data.ValueProvider;
+import com.vaadin.server.SerializableComparator;
import com.vaadin.server.SerializablePredicate;
-import com.vaadin.shared.Registration;
+import com.vaadin.shared.data.sort.SortDirection;
/**
* {@link DataProvider} wrapper for {@link Collection}s. This class does not
@@ -36,7 +37,7 @@ public class ListDataProvider<T>
extends AbstractDataProvider<T, SerializablePredicate<T>>
implements AppendableFilterDataProvider<T, SerializablePredicate<T>> {
- private Comparator<T> sortOrder = null;
+ private SerializableComparator<T> sortOrder = null;
private final Collection<T> backend;
/**
@@ -55,26 +56,6 @@ public class ListDataProvider<T>
sortOrder = null;
}
- /**
- * Chaining constructor for making modified {@link ListDataProvider}s. This
- * Constructor is used internally for making sorted and filtered variants of
- * a base data provider with actual data.
- * <p>
- * No protective copy is made of the list, and changes in the provided
- * backing Collection will be visible via this data provider. The caller
- * should copy the list if necessary.
- *
- * @param items
- * the backend data from the original list data provider
- * @param sortOrder
- * a {@link Comparator} providing the needed sorting order
- *
- */
- protected ListDataProvider(Collection<T> items, Comparator<T> sortOrder) {
- this(items);
- this.sortOrder = sortOrder;
- }
-
@Override
public Stream<T> fetch(Query<T, SerializablePredicate<T>> query) {
Stream<T> stream = backend.stream()
@@ -92,64 +73,140 @@ public class ListDataProvider<T>
return stream.skip(query.getOffset()).limit(query.getLimit());
}
+ @Override
+ public boolean isInMemory() {
+ return true;
+ }
+
+ @Override
+ public int size(Query<T, SerializablePredicate<T>> query) {
+ return (int) backend.stream()
+ .filter(t -> query.getFilter().orElse(p -> true).test(t))
+ .count();
+ }
+
/**
- * Creates a new list data provider based on this list data provider with
- * the given sort order.
+ * Sets the comparator to use as the default sorting for this data provider.
+ * This overrides the sorting set by any other method that manipulates the
+ * default sorting of this data provider.
* <p>
- * <b>NOTE</b>: this data provider is not modified in any way.
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrder(ValueProvider, SortDirection)
+ * @see #addSortComparator(SerializableComparator)
*
* @param sortOrder
- * a {@link Comparator} providing the needed sorting order
- * @return new data provider with modified sorting
+ * a comparator to use, or <code>null</code> to clear any
+ * previously set sort order
*/
- @SuppressWarnings("serial")
- public ListDataProvider<T> sortingBy(Comparator<T> sortOrder) {
- ListDataProvider<T> parent = this;
- return new ListDataProvider<T>(backend, sortOrder) {
-
- @Override
- public Registration addDataProviderListener(
- DataProviderListener listener) {
- return parent.addDataProviderListener(listener);
- }
-
- @Override
- public void refreshAll() {
- parent.refreshAll();
- }
- };
+ public void setSortComparator(SerializableComparator<T> sortOrder) {
+ this.sortOrder = sortOrder;
+ refreshAll();
}
/**
- * Creates a new list data provider based on this list data provider with
- * the given sort order.
+ * Sets the property and direction to use as the default sorting for this
+ * data provider. This overrides the sorting set by any other method that
+ * manipulates the default sorting of this data provider.
* <p>
- * <b>NOTE</b>: this data provider is not modified in any way.
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortComparator(SerializableComparator)
+ * @see #addSortOrder(ValueProvider, SortDirection)
+ *
+ * @param valueProvider
+ * the value provider that defines the property do sort by, not
+ * <code>null</code>
+ * @param sortDirection
+ * the sort direction to use, not <code>null</code>
+ */
+ public <V extends Comparable<? super V>> void setSortOrder(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ setSortComparator(propertyComparator(valueProvider, sortDirection));
+ }
+
+ /**
+ * Adds a comparator to the default sorting for this data provider. If no
+ * default sorting has been defined, then the provided comparator will be
+ * used as the default sorting. If a default sorting has been defined, then
+ * the provided comparator will be used to determine the ordering of items
+ * that are considered equal by the previously defined default sorting.
* <p>
- * This method is a short-hand for
- * {@code sortingBy(Comparator.comparing(sortOrder))}.
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortComparator(SerializableComparator)
+ * @see #addSortOrder(ValueProvider, SortDirection)
*
* @param sortOrder
- * function to sort by, not {@code null}
- * @param <U>
- * the type of the Comparable sort key
- * @return new data provider with modified sorting
+ * a comparator to add, not <code>null</code>
*/
- public <U extends Comparable<? super U>> ListDataProvider<T> sortingBy(
- Function<T, U> sortOrder) {
- return sortingBy(Comparator.comparing(sortOrder));
+ public void addSortComparator(SerializableComparator<T> sortOrder) {
+ Objects.requireNonNull(sortOrder, "Sort order to add cannot be null");
+
+ SerializableComparator<T> originalComparator = this.sortOrder;
+ if (originalComparator == null) {
+ setSortComparator(sortOrder);
+ } else {
+ setSortComparator((a, b) -> {
+ int result = originalComparator.compare(a, b);
+ if (result == 0) {
+ result = sortOrder.compare(a, b);
+ }
+ return result;
+ });
+ }
}
- @Override
- public boolean isInMemory() {
- return true;
+ /**
+ * Adds a property and direction to the default sorting for this data
+ * provider. If no default sorting has been defined, then the provided sort
+ * order will be used as the default sorting. If a default sorting has been
+ * defined, then the provided sort order will be used to determine the
+ * ordering of items that are considered equal by the previously defined
+ * default sorting.
+ * <p>
+ * The default sorting is used if the query defines no sorting. The default
+ * sorting is also used to determine the ordering of items that are
+ * considered equal by the sorting defined in the query.
+ *
+ * @see #setSortOrder(ValueProvider, SortDirection)
+ * @see #addSortComparator(SerializableComparator)
+ *
+ * @param valueProvider
+ * the value provider that defines the property do sort by, not
+ * <code>null</code>
+ * @param sortDirection
+ * the sort direction to use, not <code>null</code>
+ */
+ public <V extends Comparable<? super V>> void addSortOrder(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ addSortComparator(propertyComparator(valueProvider, sortDirection));
}
- @Override
- public int size(Query<T, SerializablePredicate<T>> query) {
- return (int) backend.stream()
- .filter(t -> query.getFilter().orElse(p -> true).test(t))
- .count();
+ private static <V extends Comparable<? super V>, T> SerializableComparator<T> propertyComparator(
+ ValueProvider<T, V> valueProvider, SortDirection sortDirection) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+ Objects.requireNonNull(sortDirection, "Sort direction cannot be null");
+
+ Comparator<V> comparator = getNaturalSortComparator(sortDirection);
+
+ return (a, b) -> comparator.compare(valueProvider.apply(a),
+ valueProvider.apply(b));
+ }
+
+ private static <V extends Comparable<? super V>> Comparator<V> getNaturalSortComparator(
+ SortDirection sortDirection) {
+ Comparator<V> comparator = Comparator.naturalOrder();
+ if (sortDirection == SortDirection.DESCENDING) {
+ comparator = comparator.reversed();
+ }
+ return comparator;
}
@Override