summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <legioth@gmail.com>2017-01-19 08:56:06 +0200
committerDenis <denis@vaadin.com>2017-01-19 08:56:06 +0200
commit67d69c8d5d6bb066c792cfaa65f2b68f6ec8cc2b (patch)
tree731f29b398ea52cd31677dcf97645169ac901c05
parentc99a911278fcf058679aefc841c25a3cdf59d74a (diff)
downloadvaadin-framework-67d69c8d5d6bb066c792cfaa65f2b68f6ec8cc2b.tar.gz
vaadin-framework-67d69c8d5d6bb066c792cfaa65f2b68f6ec8cc2b.zip
Allow setting filters directly in ListDataProvider (#8267)
* Allow setting filters directly in ListDataProvider This is one of many steps towards #8245
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ListDataProvider.java169
-rw-r--r--server/src/test/java/com/vaadin/data/provider/DataProviderTestBase.java4
-rw-r--r--server/src/test/java/com/vaadin/data/provider/ListDataProviderTest.java112
3 files changed, 280 insertions, 5 deletions
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 e1c8e8867c..3d021dc0e6 100644
--- a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
@@ -38,6 +38,9 @@ public class ListDataProvider<T>
implements AppendableFilterDataProvider<T, SerializablePredicate<T>> {
private SerializableComparator<T> sortOrder = null;
+
+ private SerializablePredicate<T> filter;
+
private final Collection<T> backend;
/**
@@ -58,8 +61,7 @@ public class ListDataProvider<T>
@Override
public Stream<T> fetch(Query<T, SerializablePredicate<T>> query) {
- Stream<T> stream = backend.stream()
- .filter(t -> query.getFilter().orElse(p -> true).test(t));
+ Stream<T> stream = getFilteredStream(query);
Optional<Comparator<T>> comparing = Stream
.of(query.getInMemorySorting(), sortOrder)
@@ -80,9 +82,22 @@ public class ListDataProvider<T>
@Override
public int size(Query<T, SerializablePredicate<T>> query) {
- return (int) backend.stream()
- .filter(t -> query.getFilter().orElse(p -> true).test(t))
- .count();
+ return (int) getFilteredStream(query).count();
+ }
+
+ private Stream<T> getFilteredStream(
+ Query<T, SerializablePredicate<T>> query) {
+ Stream<T> stream = backend.stream();
+
+ // Apply our own filters first so that query filters never see the items
+ // that would already have been filtered out
+ if (filter != null) {
+ stream = stream.filter(filter);
+ }
+
+ stream = query.getFilter().map(stream::filter).orElse(stream);
+
+ return stream;
}
/**
@@ -209,6 +224,150 @@ public class ListDataProvider<T>
return comparator;
}
+ /**
+ * Sets a filter to be applied to all queries. The filter replaces any
+ * filter that has been set or added previously.
+ *
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(SerializablePredicate)
+ *
+ * @param filter
+ * the filter to set, or <code>null</code> to remove any set
+ * filters
+ */
+ public void setFilter(SerializablePredicate<T> filter) {
+ this.filter = filter;
+ refreshAll();
+ }
+
+ /**
+ * Adds a filter to be applied to all queries. The filter will be used in
+ * addition to any filter that has been set or added previously.
+ *
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ * @see #setFilter(SerializablePredicate)
+ *
+ * @param filter
+ * the filter to add, not <code>null</code>
+ */
+ public void addFilter(SerializablePredicate<T> filter) {
+ Objects.requireNonNull(filter, "Filter cannot be null");
+
+ if (this.filter == null) {
+ setFilter(filter);
+ } else {
+ SerializablePredicate<T> oldFilter = this.filter;
+ setFilter(item -> oldFilter.test(item) && filter.test(item));
+ }
+ }
+
+ /**
+ * Removes any filter that has been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ */
+ public void clearFilters() {
+ setFilter(null);
+ }
+
+ /**
+ * Sets a filter for an item property. The filter replaces any filter that
+ * has been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param valueFilter
+ * filter for testing the property value, not <code>null</code>
+ */
+ public <V> void setFilter(ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ setFilter(createValueProviderFilter(valueProvider, valueFilter));
+ }
+
+ /**
+ * Adds a filter for an item property. The filter will be used in addition
+ * to any filter that has been set or added previously.
+ *
+ * @see #addFilter(SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param valueFilter
+ * filter for testing the property value, not <code>null</code>
+ */
+ public <V> void addFilter(ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+ Objects.requireNonNull(valueFilter, "Value filter cannot be null");
+
+ addFilter(createValueProviderFilter(valueProvider, valueFilter));
+ }
+
+ private static <T, V> SerializablePredicate<T> createValueProviderFilter(
+ ValueProvider<T, V> valueProvider,
+ SerializablePredicate<V> valueFilter) {
+ return item -> valueFilter.test(valueProvider.apply(item));
+ }
+
+ /**
+ * Sets a filter that requires an item property to have a specific value.
+ * The property value and the provided value are compared using
+ * {@link Object#equals(Object)}. The filter replaces any filter that has
+ * been set or added previously.
+ *
+ * @see #setFilter(SerializablePredicate)
+ * @see #setFilter(ValueProvider, SerializablePredicate)
+ * @see #addFilterByValue(ValueProvider, Object)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param requiredValue
+ * the value that the property must have for the filter to pass
+ */
+ public <V> void setFilterByValue(ValueProvider<T, V> valueProvider,
+ V requiredValue) {
+ setFilter(createEqualsFilter(valueProvider, requiredValue));
+ }
+
+ /**
+ * Adds a filter that requires an item property to have a specific value.
+ * The property value and the provided value are compared using
+ * {@link Object#equals(Object)}.The filter will be used in addition to any
+ * filter that has been set or added previously.
+ *
+ * @see #setFilterByValue(ValueProvider, Object)
+ * @see #addFilter(SerializablePredicate)
+ * @see #addFilter(ValueProvider, SerializablePredicate)
+ *
+ * @param valueProvider
+ * value provider that gets the property value, not
+ * <code>null</code>
+ * @param requiredValue
+ * the value that the property must have for the filter to pass
+ */
+ public <V> void addFilterByValue(ValueProvider<T, V> valueProvider,
+ V requiredValue) {
+ addFilter(createEqualsFilter(valueProvider, requiredValue));
+ }
+
+ private static <T, V> SerializablePredicate<T> createEqualsFilter(
+ ValueProvider<T, V> valueProvider, V requiredValue) {
+ Objects.requireNonNull(valueProvider, "Value provider cannot be null");
+
+ return item -> Objects.equals(valueProvider.apply(item), requiredValue);
+ }
+
@Override
public SerializablePredicate<T> combineFilters(
SerializablePredicate<T> filter1,
diff --git a/server/src/test/java/com/vaadin/data/provider/DataProviderTestBase.java b/server/src/test/java/com/vaadin/data/provider/DataProviderTestBase.java
index ccbb0b0c1a..9d1115d2af 100644
--- a/server/src/test/java/com/vaadin/data/provider/DataProviderTestBase.java
+++ b/server/src/test/java/com/vaadin/data/provider/DataProviderTestBase.java
@@ -186,4 +186,8 @@ public abstract class DataProviderTestBase<D extends DataProvider<StrBean, Seria
Assert.assertEquals("Unexpected number of matches for 'Foo'", 36,
dataProvider.size(new Query<>(fooFilter)));
}
+
+ protected long sizeWithUnfilteredQuery() {
+ return dataProvider.fetch(new Query<>()).count();
+ }
}
diff --git a/server/src/test/java/com/vaadin/data/provider/ListDataProviderTest.java b/server/src/test/java/com/vaadin/data/provider/ListDataProviderTest.java
index ad7c3b1f46..e10c071c41 100644
--- a/server/src/test/java/com/vaadin/data/provider/ListDataProviderTest.java
+++ b/server/src/test/java/com/vaadin/data/provider/ListDataProviderTest.java
@@ -120,6 +120,118 @@ public class ListDataProviderTest
Assert.assertEquals(new StrBean("Foo", 91, 2), threeFirstItems.get(2));
}
+ @Test
+ public void setFilter() {
+ dataProvider.setFilter(item -> item.getValue().equals("Foo"));
+
+ Assert.assertEquals(36, sizeWithUnfilteredQuery());
+
+ dataProvider.setFilter(item -> !item.getValue().equals("Foo"));
+
+ Assert.assertEquals(
+ "Previous filter should be reset when setting a new one", 64,
+ sizeWithUnfilteredQuery());
+
+ dataProvider.setFilter(null);
+
+ Assert.assertEquals("Setting filter to null should remove all filters",
+ 100, sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void setFilter_valueProvider() {
+ dataProvider.setFilter(StrBean::getValue, "Foo"::equals);
+
+ Assert.assertEquals(36, sizeWithUnfilteredQuery());
+
+ dataProvider.setFilter(StrBean::getValue,
+ value -> !value.equals("Foo"));
+
+ Assert.assertEquals(
+ "Previous filter should be reset when setting a new one", 64,
+ sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void setFilterEquals() {
+ dataProvider.setFilterByValue(StrBean::getValue, "Foo");
+
+ Assert.assertEquals(36, sizeWithUnfilteredQuery());
+
+ dataProvider.setFilterByValue(StrBean::getValue, "Bar");
+
+ Assert.assertEquals(23, sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void addFilter_withPreviousFilter() {
+ dataProvider.setFilterByValue(StrBean::getValue, "Foo");
+
+ dataProvider.addFilter(item -> item.getId() > 50);
+
+ Assert.assertEquals("Both filters should be used", 17,
+ sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void addFilter_noPreviousFilter() {
+ dataProvider.addFilter(item -> item.getId() > 50);
+
+ Assert.assertEquals(48, sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void addFilter_valueProvider() {
+ dataProvider.setFilter(item -> item.getId() > 50);
+
+ dataProvider.addFilter(StrBean::getValue, "Foo"::equals);
+
+ Assert.assertEquals("Both filters should be used", 17,
+ sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void addFilterEquals() {
+ dataProvider.setFilter(item -> item.getId() > 50);
+
+ dataProvider.addFilterByValue(StrBean::getValue, "Foo");
+
+ Assert.assertEquals("Both filters should be used", 17,
+ sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void addFilter_firstAddedUsedFirst() {
+ dataProvider.addFilter(item -> false);
+ dataProvider.addFilter(item -> {
+ Assert.fail("This filter should never be invoked");
+ return true;
+ });
+
+ Assert.assertEquals(0, sizeWithUnfilteredQuery());
+ }
+
+ @Test
+ public void combineProviderAndQueryFilters() {
+ dataProvider.addFilterByValue(StrBean::getValue, "Foo");
+
+ int size = dataProvider.size(new Query<>(item -> item.getId() > 50));
+
+ Assert.assertEquals("Both filters should be used", 17, size);
+ }
+
+ @Test
+ public void providerFilterBeforeQueryFilter() {
+ dataProvider.setFilter(item -> false);
+
+ int size = dataProvider.size(new Query<>(item -> {
+ Assert.fail("This filter should never be invoked");
+ return true;
+ }));
+
+ Assert.assertEquals(0, size);
+ }
+
@Override
protected void setSortOrder(List<SortOrder<String>> sortOrder,
Comparator<StrBean> comp) {