Correct pagination

This commit is contained in:
René Pfeuffer
2018-06-06 08:44:32 +02:00
parent 7bc2c1479a
commit 2673756f8b
5 changed files with 78 additions and 16 deletions

View File

@@ -35,8 +35,9 @@ package sonia.scm;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import sonia.scm.util.Util;
import java.io.IOException;
import java.util.Collection;
import java.util.Comparator;
@@ -61,7 +62,7 @@ public interface Manager<T extends ModelObject, E extends Exception>
* @throws E
* @throws IOException
*/
public void refresh(T object) throws E, IOException;
void refresh(T object) throws E, IOException;
//~--- get methods ----------------------------------------------------------
@@ -73,7 +74,7 @@ public interface Manager<T extends ModelObject, E extends Exception>
*
* @return object with the given id
*/
public T get(String id);
T get(String id);
/**
* Returns a {@link java.util.Collection} of all objects in the store.
@@ -81,7 +82,7 @@ public interface Manager<T extends ModelObject, E extends Exception>
*
* @return all object in the store
*/
public Collection<T> getAll();
Collection<T> getAll();
/**
* Returns all object of the store sorted by the given {@link java.util.Comparator}
@@ -91,7 +92,7 @@ public interface Manager<T extends ModelObject, E extends Exception>
* @since 1.4
* @return all object of the store sorted by the given {@link java.util.Comparator}
*/
public Collection<T> getAll(Comparator<T> comparator);
Collection<T> getAll(Comparator<T> comparator);
/**
* Returns objects from the store which are starts at the given start
@@ -105,7 +106,7 @@ public interface Manager<T extends ModelObject, E extends Exception>
* @return objects from the store which are starts at the given
* start parameter
*/
public Collection<T> getAll(int start, int limit);
Collection<T> getAll(int start, int limit);
/**
* Returns objects from the store which are starts at the given start
@@ -121,5 +122,26 @@ public interface Manager<T extends ModelObject, E extends Exception>
* @return objects from the store which are starts at the given
* start parameter
*/
public Collection<T> getAll(Comparator<T> comparator, int start, int limit);
Collection<T> getAll(Comparator<T> comparator, int start, int limit);
/**
* Returns objects from the store divided into pages with the given page
* size for the given page number (zero based) and sorted by the given
* {@link java.util.Comparator}.
*
* @param comparator to sort the returned objects
* @param pageNumber the number of the page to be returned (zero based)
* @param pageSize the size of the pages
*
* @since 2.0
* @return {@link PageResult} with the objects from the store for the requested
* page. If the requested page number exceeds the existing pages, an
* empty page result is returned.
*/
default PageResult<T> getPage(Comparator<T> comparator, int pageNumber, int pageSize) {
Collection<T> entities = getAll(comparator, pageNumber * pageSize, pageSize + 1);
boolean hasMore = entities.size() > pageSize;
return new PageResult<>(Util.createSubCollection(entities, 0, pageSize), hasMore);
}
}

View File

@@ -0,0 +1,23 @@
package sonia.scm;
import java.util.Collection;
import java.util.Collections;
public class PageResult<T extends ModelObject> {
private final Collection<T> entities;
private final boolean hasMore;
public PageResult(Collection<T> entities, boolean hasMore) {
this.entities = entities;
this.hasMore = hasMore;
}
public Collection<T> getEntities() {
return Collections.unmodifiableCollection(entities);
}
public boolean hasMore() {
return hasMore;
}
}

View File

@@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory;
import sonia.scm.LastModifiedAware;
import sonia.scm.Manager;
import sonia.scm.ModelObject;
import sonia.scm.PageResult;
import sonia.scm.api.rest.RestExceptionResult;
import sonia.scm.util.AssertUtil;
import sonia.scm.util.HttpUtil;
@@ -588,6 +589,19 @@ public abstract class AbstractManagerResource<T extends ModelObject,
return items;
}
protected PageResult<T> fetchPage(String sortby, boolean desc, int pageNumber,
int pageSize) {
AssertUtil.assertPositive(pageNumber);
AssertUtil.assertPositive(pageSize);
if (Util.isEmpty(sortby)) {
// replace with something useful
sortby = "id";
}
return manager.getPage(createComparator(sortby, desc), pageNumber, pageSize);
}
//~--- get methods ----------------------------------------------------------
/**

View File

@@ -13,11 +13,12 @@ import static de.otto.edison.hal.Links.linkingTo;
public class UserCollectionDto extends HalRepresentation {
public UserCollectionDto(String baseUrl, NumberedPaging page, List<UserDto> users) {
super(linkingTo()
.with(page.links(
fromTemplate(baseUrl + "{?page,pageSize}"),
EnumSet.allOf(PagingRel.class)))
.build(),
super(
linkingTo()
.with(page.links(
fromTemplate(baseUrl + "{?page,pageSize}"),
EnumSet.allOf(PagingRel.class)))
.build(),
embeddedBuilder()
.with("users", users)
.build()

View File

@@ -6,6 +6,7 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import sonia.scm.PageResult;
import sonia.scm.api.rest.resources.AbstractManagerResource;
import sonia.scm.user.User;
import sonia.scm.user.UserException;
@@ -24,6 +25,7 @@ import static sonia.scm.api.v2.resources.ScmMediaType.USER;
@Singleton
@Produces(USER)
public class UserCollectionResource extends AbstractManagerResource<User, UserException> {
public static final int DEFAULT_PAGE_SIZE = 10;
private final UserDto2UserMapper dtoToUserMapper;
private final User2UserDtoMapper userToDtoMapper;
@@ -53,18 +55,18 @@ public class UserCollectionResource extends AbstractManagerResource<User, UserEx
@ResponseCode(code = 500, condition = "internal server error")
})
public Response getAll(@Context Request request, @Context UriInfo uriInfo, @DefaultValue("0")
@QueryParam("page") int page, @DefaultValue("10")
@QueryParam("page") int page, @DefaultValue("" + DEFAULT_PAGE_SIZE)
@QueryParam("pageSize") int pageSize, @QueryParam("sortby") String sortby,
@DefaultValue("false")
@QueryParam("desc") boolean desc) {
Collection<User> items = fetchItems(sortby, desc, page * pageSize, pageSize);
PageResult<User> pageResult = fetchPage(sortby, desc, page, pageSize);
LinkBuilder collectionLinkBuilder = new LinkBuilder(uriInfo, UserV2Resource.class, UserCollectionResource.class);
String baseUrl = collectionLinkBuilder.method("getUserCollectionResource").parameters().method("create").parameters().href();
List<UserDto> dtos = items.stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList());
List<UserDto> dtos = pageResult.getEntities().stream().map(user -> userToDtoMapper.userToUserDto(user, uriInfo)).collect(Collectors.toList());
return Response.ok(new UserCollectionDto(baseUrl, zeroBasedNumberedPaging(page, pageSize, true), dtos)).build();
return Response.ok(new UserCollectionDto(baseUrl, zeroBasedNumberedPaging(page, pageSize, pageResult.hasMore()), dtos)).build();
}
@POST