diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-07-11 09:02:11 +0300 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2016-07-12 11:02:41 +0000 |
commit | a3c0378df7d066cde9b1d321bcd8bf9f26a21b34 (patch) | |
tree | 9d4d2a8e49b3e635d879404ccd6f297ba2e60b13 | |
parent | ba228972ae734f3f596edb7a2382b0df19a1db9c (diff) | |
download | vaadin-framework-a3c0378df7d066cde9b1d321bcd8bf9f26a21b34.tar.gz vaadin-framework-a3c0378df7d066cde9b1d321bcd8bf9f26a21b34.zip |
Add basic sorting implementation and API
Change-Id: Ic1fded7f26e3f63c234c6e5bebf8f8fed22e6365
10 files changed, 142 insertions, 43 deletions
diff --git a/server/src/main/java/com/vaadin/tokka/server/communication/data/DataCommunicator.java b/server/src/main/java/com/vaadin/tokka/server/communication/data/DataCommunicator.java index 0a9e3f34c7..24cb803306 100644 --- a/server/src/main/java/com/vaadin/tokka/server/communication/data/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/tokka/server/communication/data/DataCommunicator.java @@ -171,14 +171,14 @@ public class DataCommunicator<T> extends AbstractExtension { protected ActiveDataHandler handler = new ActiveDataHandler(); protected DataCommunicatorClientRpc rpc; - protected DataSource<T> dataSource; + protected DataSource<T, ?> dataSource; private DataKeyMapper<T> keyMapper; private boolean reset = false; private final Set<T> updatedData = new HashSet<T>(); private Range pushRows = Range.withLength(0, 40); - public DataCommunicator(DataSource<T> dataSource) { + public DataCommunicator(DataSource<T, ?> dataSource) { addDataGenerator(handler); this.dataSource = dataSource; rpc = getRpcProxy(DataCommunicatorClientRpc.class); diff --git a/server/src/main/java/com/vaadin/tokka/server/communication/data/DataSource.java b/server/src/main/java/com/vaadin/tokka/server/communication/data/DataSource.java index 01257bf755..1587200c91 100644 --- a/server/src/main/java/com/vaadin/tokka/server/communication/data/DataSource.java +++ b/server/src/main/java/com/vaadin/tokka/server/communication/data/DataSource.java @@ -33,10 +33,19 @@ import com.vaadin.tokka.event.Registration; * @param <T> * data type */ -public interface DataSource<T> extends Function<Object, Stream<T>>, +public interface DataSource<T, SORT> extends Function<Object, Stream<T>>, Serializable { /** + * Sets a default sorting order to the data source. + * + * @param sortOrder + * an object providing the needed sorting information + * @return new data source with modified sorting + */ + DataSource<T, SORT> sortingBy(SORT sortOrder); + + /** * This method creates a new {@link InMemoryDataSource} from a given * Collection. The InMemoryDataSource creates a protective List copy of all * the contents in the Collection. diff --git a/server/src/main/java/com/vaadin/tokka/server/communication/data/InMemoryDataSource.java b/server/src/main/java/com/vaadin/tokka/server/communication/data/InMemoryDataSource.java index 5f743e2ca1..7b4b84e5b9 100644 --- a/server/src/main/java/com/vaadin/tokka/server/communication/data/InMemoryDataSource.java +++ b/server/src/main/java/com/vaadin/tokka/server/communication/data/InMemoryDataSource.java @@ -17,6 +17,7 @@ package com.vaadin.tokka.server.communication.data; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; @@ -27,7 +28,7 @@ import java.util.stream.Stream; * @param <T> * data type */ -public class InMemoryDataSource<T> implements DataSource<T> { +public class InMemoryDataSource<T> implements DataSource<T, Comparator<T>> { // FIXME: Missing Query object private Function<Object, Stream<T>> request; @@ -44,8 +45,26 @@ public class InMemoryDataSource<T> implements DataSource<T> { request = query -> backend.stream(); } + /** + * Chaining constructor for making modified {@link InMemoryDataSource}s. + * This Constructor is used internally for making sorted and filtered + * variants of a base data source with actual data. + * + * @param request + * request for the new data source + */ + protected InMemoryDataSource(Function<Object, Stream<T>> request) { + this.request = request; + } + @Override public Stream<T> apply(Object query) { return request.apply(query); } + + @Override + public DataSource<T, Comparator<T>> sortingBy(Comparator<T> sortOrder) { + return new InMemoryDataSource<T>(q -> request.apply(q) + .sorted(sortOrder)); + } } diff --git a/server/src/main/java/com/vaadin/tokka/ui/components/Listing.java b/server/src/main/java/com/vaadin/tokka/ui/components/Listing.java index 103d7b5b2e..38962c7446 100644 --- a/server/src/main/java/com/vaadin/tokka/ui/components/Listing.java +++ b/server/src/main/java/com/vaadin/tokka/ui/components/Listing.java @@ -35,7 +35,7 @@ public interface Listing<T> extends Serializable { * @param data * data source */ - void setDataSource(DataSource<T> data); + void setDataSource(DataSource<T, ?> data); /** * Sets the options available for this Listing. @@ -62,7 +62,7 @@ public interface Listing<T> extends Serializable { * * @return data source */ - DataSource<T> getDataSource(); + DataSource<T, ?> getDataSource(); /** * Gets the {@link SelectionModel} for this Listing. diff --git a/server/src/main/java/com/vaadin/tokka/ui/components/grid/Grid.java b/server/src/main/java/com/vaadin/tokka/ui/components/grid/Grid.java index 1d81a0b8a1..3536f7b6e5 100644 --- a/server/src/main/java/com/vaadin/tokka/ui/components/grid/Grid.java +++ b/server/src/main/java/com/vaadin/tokka/ui/components/grid/Grid.java @@ -26,7 +26,7 @@ import com.vaadin.tokka.ui.components.AbstractListing; public class Grid<T> extends AbstractListing<T> { - private DataSource<T> dataSource; + private DataSource<T, ?> dataSource; private Map<String, Column<T, ?>> columns = new LinkedHashMap<>(); public Grid() { @@ -34,13 +34,13 @@ public class Grid<T> extends AbstractListing<T> { } @Override - public void setDataSource(DataSource<T> data) { + public void setDataSource(DataSource<T, ?> data) { this.dataSource = data; setDataCommunicator(new DataCommunicator<>(data)); } @Override - public DataSource<T> getDataSource() { + public DataSource<T, ?> getDataSource() { return dataSource; } diff --git a/server/src/main/java/com/vaadin/tokka/ui/components/nativeselect/NativeSelect.java b/server/src/main/java/com/vaadin/tokka/ui/components/nativeselect/NativeSelect.java index dd54016521..0c18f78287 100644 --- a/server/src/main/java/com/vaadin/tokka/ui/components/nativeselect/NativeSelect.java +++ b/server/src/main/java/com/vaadin/tokka/ui/components/nativeselect/NativeSelect.java @@ -28,7 +28,7 @@ import elemental.json.JsonObject; public class NativeSelect<T> extends AbstractListing<T> { - private DataSource<T> dataSource; + private DataSource<T, ?> dataSource; private Function<T, String> nameProvider = T::toString; public NativeSelect() { @@ -47,13 +47,13 @@ public class NativeSelect<T> extends AbstractListing<T> { }); } - public NativeSelect(DataSource<T> dataSource) { + public NativeSelect(DataSource<T, ?> dataSource) { this(); setDataSource(dataSource); } @Override - public void setDataSource(DataSource<T> data) { + public void setDataSource(DataSource<T, ?> data) { dataSource = data; if (dataSource != null) { setDataCommunicator(new DataCommunicator<>(dataSource)); @@ -63,7 +63,7 @@ public class NativeSelect<T> extends AbstractListing<T> { } @Override - public DataSource<T> getDataSource() { + public DataSource<T, ?> getDataSource() { return dataSource; } } diff --git a/server/src/test/java/com/vaadin/tokka/data/datasource/InMemoryDataSourceTest.java b/server/src/test/java/com/vaadin/tokka/data/datasource/InMemoryDataSourceTest.java index 092f70b395..bd3c26f540 100644 --- a/server/src/test/java/com/vaadin/tokka/data/datasource/InMemoryDataSourceTest.java +++ b/server/src/test/java/com/vaadin/tokka/data/datasource/InMemoryDataSourceTest.java @@ -2,10 +2,11 @@ package com.vaadin.tokka.data.datasource; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -import java.util.stream.Stream; +import java.util.stream.Collectors; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -14,30 +15,12 @@ import com.vaadin.tokka.server.communication.data.InMemoryDataSource; public class InMemoryDataSourceTest { - private static class StrBean { - - private String value; - - public StrBean(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - } - private InMemoryDataSource<StrBean> dataSource; private List<StrBean> data; @Before public void setUp() { - data = createData(); + data = StrBean.generateRandomBeans(100); dataSource = DataSource.create(data); } @@ -46,10 +29,47 @@ public class InMemoryDataSourceTest { dataSource.apply(null).forEach(str -> assertTrue(data.contains(str))); } - private List<StrBean> createData() { - List<StrBean> list = new ArrayList<>(); - Stream.of("Foo", "Bar", "Baz").map(StrBean::new).forEach(list::add); - return list; + @Test + public void testSortByComparatorListsDiffer() { + Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue) + .thenComparing(StrBean::getRandomNumber) + .thenComparing(StrBean::getId); + List<StrBean> list = dataSource.sortingBy(comp).apply(null) + .collect(Collectors.toList()); + + // First value in data is { Xyz, 10, 100 } which should be last in list + Assert.assertNotEquals("First value should not match", data.get(0), + list.get(0)); + + data.sort(comp); + for (int i = 0; i < data.size(); ++i) { + Assert.assertEquals("Sorting result differed", data.get(i), + list.get(i)); + } } + @Test + public void testDefatulSortWithSpecifiedPostSort() { + Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue) + .thenComparing(Comparator.comparing(StrBean::getId).reversed()); + List<StrBean> list = dataSource.sortingBy(comp).apply(null) + // The sort here should come e.g from a Component + .sorted(Comparator.comparing(StrBean::getRandomNumber)) + .collect(Collectors.toList()); + + for (int i = 1; i < list.size(); ++i) { + StrBean prev = list.get(i - 1); + StrBean cur = list.get(i); + // Test specific sort + Assert.assertTrue(prev.getRandomNumber() <= cur.getRandomNumber()); + + if (prev.getRandomNumber() == cur.getRandomNumber()) { + // Test default sort + Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0); + if (prev.getValue().equals(cur.getValue())) { + Assert.assertTrue(prev.getId() > cur.getId()); + } + } + } + } } diff --git a/server/src/test/java/com/vaadin/tokka/data/datasource/StrBean.java b/server/src/test/java/com/vaadin/tokka/data/datasource/StrBean.java new file mode 100644 index 0000000000..419955f380 --- /dev/null +++ b/server/src/test/java/com/vaadin/tokka/data/datasource/StrBean.java @@ -0,0 +1,49 @@ +package com.vaadin.tokka.data.datasource; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +class StrBean implements Serializable { + + private static String[] values = new String[] { "Foo", "Bar", "Baz" }; + + private String value; + private final int id; + private final int randomNumber; + + public StrBean(String value, int id, int randomNumber) { + this.value = value; + this.id = id; + this.randomNumber = randomNumber; + } + + public String getValue() { + return value; + } + + public int getId() { + return id; + } + + public int getRandomNumber() { + return randomNumber; + } + + public static List<StrBean> generateRandomBeans(int max) { + List<StrBean> data = new ArrayList<StrBean>(); + Random r = new Random(13337); + data.add(new StrBean("Xyz", 10, max)); + for (int i = 0; i < max - 1; ++i) { + data.add(new StrBean(values[r.nextInt(values.length)], i, r + .nextInt(10))); + } + return data; + } + + @Override + public String toString() { + return "{ " + value + ", " + randomNumber + ", " + id + " }"; + } +}
\ No newline at end of file diff --git a/server/src/test/java/com/vaadin/tokka/ui/components/AbstractListingTest.java b/server/src/test/java/com/vaadin/tokka/ui/components/AbstractListingTest.java index 242b5519df..c8051e0b1e 100644 --- a/server/src/test/java/com/vaadin/tokka/ui/components/AbstractListingTest.java +++ b/server/src/test/java/com/vaadin/tokka/ui/components/AbstractListingTest.java @@ -29,16 +29,16 @@ public class AbstractListingTest { AbstractListing<String> testComponent = new AbstractListing<String>() { - DataSource<String> data; + DataSource<String, ?> data; @Override - public void setDataSource(DataSource<String> data) { + public void setDataSource(DataSource<String, ?> data) { this.data = data; setDataCommunicator(new DataCommunicator<>(data)); } @Override - public DataSource<String> getDataSource() { + public DataSource<String, ?> getDataSource() { return data; } }; diff --git a/uitest/src/main/java/com/vaadin/tokka/tests/components/ListingTestUI.java b/uitest/src/main/java/com/vaadin/tokka/tests/components/ListingTestUI.java index a66ab31fda..4d2417ab9d 100644 --- a/uitest/src/main/java/com/vaadin/tokka/tests/components/ListingTestUI.java +++ b/uitest/src/main/java/com/vaadin/tokka/tests/components/ListingTestUI.java @@ -1,6 +1,7 @@ package com.vaadin.tokka.tests.components; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Random; @@ -80,7 +81,7 @@ public class ListingTestUI extends AbstractTestUI { .getSelectionModel().getSelected() .forEach(s -> Notification.show(s)))); hLayout.addComponent(new Button("Random select", e -> { - DataSource<String> ds = select.getDataSource(); + DataSource<String, ?> ds = select.getDataSource(); int skip = r.nextInt((int) ds.apply(null).count()); ds.apply(null).skip(skip).findFirst() .ifPresent(select.getSelectionModel()::select); @@ -100,7 +101,8 @@ public class ListingTestUI extends AbstractTestUI { grid.addColumn("String Value", Bean::getValue); grid.addColumn("Integer Value", Bean::getIntVal); grid.addColumn("toString", Bean::toString); - grid.setDataSource(DataSource.create(Bean.generateRandomBeans())); + grid.setDataSource(DataSource.create(Bean.generateRandomBeans()) + .sortingBy(Comparator.comparing(Bean::getValue))); addComponent(new Button("Toggle Grid Selection", new Button.ClickListener() { |