Browse Source

Add support for sorting with backend data sources

Change-Id: I59767f8e197d3802110df4ad6da7581f101b6835
feature/vaadin8-book-vol2
Teemu Suo-Anttila 7 years ago
parent
commit
ea5b396391

+ 11
- 4
server/src/main/java/com/vaadin/tokka/server/communication/data/DataCommunicator.java View File

@@ -16,6 +16,7 @@
package com.vaadin.tokka.server.communication.data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -178,7 +179,9 @@ public class DataCommunicator<T> extends AbstractExtension {
private boolean reset = false;
private final Set<T> updatedData = new HashSet<T>();
private Range pushRows = Range.withLength(0, 40);

private Comparator<T> inMemorySorting;
private List<SortOrder<String>> backEndSorting = new ArrayList<>();

public DataCommunicator() {
addDataGenerator(handler);
@@ -200,13 +203,12 @@ public class DataCommunicator<T> extends AbstractExtension {
}

// FIXME: Sorting and Filtering with Backend
List<Object> sortOrders = Collections.emptyList();
Set<Object> filters = Collections.emptySet();

if (initial || reset) {
// FIXME: Rethink the size question.
int dataSourceSize = (int) getDataSource().apply(
new Query(0, Integer.MAX_VALUE, sortOrders, filters))
new Query(0, Integer.MAX_VALUE, backEndSorting, filters))
.count();
rpc.reset(dataSourceSize);
}
@@ -226,10 +228,9 @@ public class DataCommunicator<T> extends AbstractExtension {
}
rowsToPush = rowsToPush.skip(offset).limit(limit);
} else {
Query query = new Query(offset, limit, sortOrders, filters);
Query query = new Query(offset, limit, backEndSorting, filters);
rowsToPush = getDataSource().apply(query);
}

pushData(offset, rowsToPush);
}

@@ -392,6 +393,12 @@ public class DataCommunicator<T> extends AbstractExtension {
reset();
}

public void setBackEndSorting(List<SortOrder<String>> sortOrder) {
backEndSorting.clear();
backEndSorting.addAll(sortOrder);
reset();
}

/**
* Creates a {@link DataKeyMapper} to use with this DataCommunicator.
* <p>

+ 3
- 3
server/src/main/java/com/vaadin/tokka/server/communication/data/Query.java View File

@@ -30,7 +30,7 @@ public class Query implements Serializable {

private final int offset;
private final int limit;
private final List<Object> sortOrders;
private final List<SortOrder<String>> sortOrders;
private final Set<Object> filters;

/**
@@ -57,7 +57,7 @@ public class Query implements Serializable {
* @param filters
* filtering for fetching
*/
public Query(int offset, int limit, List<Object> sortOrders,
public Query(int offset, int limit, List<SortOrder<String>> sortOrders,
Set<Object> filters) {
this.offset = offset;
this.limit = limit;
@@ -91,7 +91,7 @@ public class Query implements Serializable {
*
* @return list of sort orders
*/
public List<Object> getSortOrders() {
public List<SortOrder<String>> getSortOrders() {
return sortOrders;
}


+ 39
- 0
server/src/main/java/com/vaadin/tokka/server/communication/data/SortOrder.java View File

@@ -0,0 +1,39 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tokka.server.communication.data;

import java.io.Serializable;

import com.vaadin.shared.data.sort.SortDirection;

public class SortOrder<T> implements Serializable {

private T sorted;
private SortDirection direction;

public SortOrder(T sorted, SortDirection direction) {
this.sorted = sorted;
this.direction = direction;
}

public T getSorted() {
return sorted;
}

public SortDirection getDirection() {
return direction;
}
}

+ 22
- 0
server/src/main/java/com/vaadin/tokka/ui/components/grid/Column.java View File

@@ -15,13 +15,18 @@
*/
package com.vaadin.tokka.ui.components.grid;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.vaadin.server.AbstractExtension;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.tokka.data.DataProviderConstants;
import com.vaadin.shared.tokka.ui.components.grid.ColumnState;
import com.vaadin.tokka.server.communication.data.SortOrder;
import com.vaadin.tokka.server.communication.data.TypedDataGenerator;

import elemental.json.Json;
@@ -31,6 +36,7 @@ public class Column<T, V> extends AbstractExtension implements
TypedDataGenerator<T> {

private Function<T, V> getter;
private Function<SortDirection, Stream<SortOrder<String>>> sortOrderProvider;

Column(String caption, Function<T, V> getter) {
this.getter = getter;
@@ -109,4 +115,20 @@ public class Column<T, V> extends AbstractExtension implements
};
return sortDirection == SortDirection.ASCENDING ? c : c.reversed();
}

public Column<T, V> setSortProperty(String... properties) {
sortOrderProvider = dir -> Arrays.asList(properties).stream()
.map(s -> new SortOrder<>(s, dir));
return this;
}

public Column<T, V> setSortBuilder(
Function<SortDirection, Stream<SortOrder<String>>> provider) {
sortOrderProvider = provider;
return this;
}

public List<SortOrder<String>> getSortOrder(SortDirection direction) {
return sortOrderProvider.apply(direction).collect(Collectors.toList());
}
}

+ 44
- 23
server/src/main/java/com/vaadin/tokka/ui/components/grid/Grid.java View File

@@ -15,24 +15,27 @@
*/
package com.vaadin.tokka.ui.components.grid;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.tokka.ui.components.grid.GridServerRpc;
import com.vaadin.tokka.server.communication.data.DataSource;
import com.vaadin.tokka.server.communication.data.KeyMapper;
import com.vaadin.tokka.server.communication.data.SingleSelection;
import com.vaadin.tokka.server.communication.data.SortOrder;
import com.vaadin.tokka.ui.components.AbstractListing;

public class Grid<T> extends AbstractListing<T> {

private KeyMapper<Column<T, ?>> columnKeys = new KeyMapper<>();
private Set<Column<T, ?>> columnSet = new HashSet<>();
private List<SortOrder<Column<T, ?>>> sortOrder = new ArrayList<>();

public Grid() {
setSelectionModel(new SingleSelection<T>());
@@ -40,34 +43,23 @@ public class Grid<T> extends AbstractListing<T> {

@Override
public void setSortOrder(List<String> columnIds,
List<SortDirection> sortDirections) {
assert columnIds.size() == sortDirections.size() : "Column and sort direction counts don't match.";
List<SortDirection> directions) {
assert columnIds.size() == directions.size() : "Column and sort direction counts don't match.";
sortOrder.clear();
if (columnIds.size() == 0) {
// Somehow there's suddenly no sort order anymore..
getDataCommunicator().setBackEndSorting(
Collections.emptyList());
getDataCommunicator().setInMemorySorting(null);
return;
}

if (getDataCommunicator().getDataSource().isInMemory()) {
Comparator<T> c = columnKeys.get(columnIds.get(0))
.getComparator(sortDirections.get(0));
for (int i = 1; i < columnIds.size(); ++i) {
c = c.thenComparing(columnKeys.get(columnIds.get(i))
.getComparator(sortDirections.get(i)));
}
getDataCommunicator().setInMemorySorting(c);
} else {
Map<Column<T, ?>, SortDirection> sortOrder = new LinkedHashMap<>();
for (int i = 0; i < columnIds.size(); ++i) {
sortOrder.put(columnKeys.get(columnIds.get(i)),
sortDirections.get(i));
}
// FIXME: Handle the sortOrder map so DataSource can
// understand
sortOrder.forEach((col, dir) -> System.err
.println("Sorting column: " + col.getCaption()
+ " to " + dir));
for (int i = 0; i < columnIds.size(); ++i) {
Column<T, ?> column = columnKeys.get(columnIds.get(i));
sortOrder.add(new SortOrder<>(column, directions.get(i)));
}

updateSortOrder();
}
});
}
@@ -90,4 +82,33 @@ public class Grid<T> extends AbstractListing<T> {
column.remove();
}
}

@Override
public void setDataSource(DataSource<T, ?> data) {
super.setDataSource(data);
updateSortOrder();
}

protected void updateSortOrder() {
if (getDataCommunicator().getDataSource() == null) {
return;
}

if (getDataCommunicator().getDataSource().isInMemory()) {
Comparator<T> comparator = sortOrder
.stream()
.map(order -> order.getSorted().getComparator(
order.getDirection()))
.reduce((x, y) -> 0, Comparator::thenComparing);
getDataCommunicator().setInMemorySorting(comparator);
} else {
List<SortOrder<String>> sortProperties = new ArrayList<>();
sortOrder
.stream()
.map(order -> order.getSorted().getSortOrder(
order.getDirection()))
.forEach(sortProperties::addAll);
getDataCommunicator().setBackEndSorting(sortProperties);
}
}
}

+ 71
- 6
uitest/src/main/java/com/vaadin/tokka/tests/components/GridSortable.java View File

@@ -1,23 +1,88 @@
package com.vaadin.tokka.tests.components;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.tokka.server.communication.data.DataSource;
import com.vaadin.tokka.server.communication.data.InMemoryDataSource;
import com.vaadin.tokka.ui.components.grid.Grid;
import com.vaadin.ui.Button;

public class GridSortable extends AbstractTestUI {

private static class CustomDataSource extends InMemoryDataSource<Bean> {

private static List<Bean> list = Arrays.asList(new Bean("Foo", 100),
new Bean("Bar", 200), new Bean("Bar", 100));
private static Map<String, Comparator<Bean>> comparators = new HashMap<>();

static {
comparators.put("value", Comparator.comparing(Bean::getValue));
comparators.put("intVal", Comparator.comparing(Bean::getIntVal));
}

public CustomDataSource() {
super(
query -> {
Stream<Bean> beans = list.stream();

Comparator<Bean> comparator = query
.getSortOrders()
.stream()
.map(s -> {
Comparator<Bean> c = comparators.get(s
.getSorted());
if (c == null) {
throw new IllegalArgumentException(
"Could not sort by '"
+ s.getSorted() + "'");
}
return s.getDirection() == SortDirection.ASCENDING ? c
: c.reversed();
})
.reduce((x, y) -> 0, Comparator::thenComparing);

return beans.sorted(comparator);
});
}

@Override
public boolean isInMemory() {
return false;
}
}

private InMemoryDataSource<Bean> dataSource;

@Override
protected void setup(VaadinRequest request) {
Grid<Bean> grid = new Grid<Bean>();
grid.addColumn("Sortable String", Bean::getValue);
grid.addColumn("Sortable Integer", Bean::getIntVal);
grid.addColumn("Not sortable toString()", Bean::toString).setSortable(
false);
grid.addColumn("Sortable String", Bean::getValue).setSortProperty(
"value");
grid.addColumn("Sortable Integer", Bean::getIntVal).setSortProperty(
"intVal");
grid.addColumn("Not sortable toString()", Bean::toString)
.setSortable(false).setSortProperty("Not Sortable.");

grid.setDataSource(DataSource.create(new Bean("Foo", 0), new Bean(
"Bar", 1), new Bean("Bar", 0)));
dataSource = DataSource.create(new Bean("Foo", 0), new Bean("Bar", 1),
new Bean("Bar", 0));
grid.setDataSource(dataSource);

addComponent(grid);

addComponent(new Button("Change DataSource", e -> {
if (grid.getDataSource() != dataSource) {
grid.setDataSource(dataSource);
} else {
grid.setDataSource(new CustomDataSource());
}
}));
}
}

Loading…
Cancel
Save