refactoring sort

This commit is contained in:
anhefti 2019-01-26 22:11:19 +01:00
parent 8e9cf8741d
commit 2dcba3a0da
10 changed files with 105 additions and 104 deletions

View file

@ -18,17 +18,11 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
public final class Page<T> {
public enum SortOrder {
ASCENDING,
DESCENDING
}
public static final String ATTR_NAMES_ONLY = "names_only";
public static final String ATTR_NUMBER_OF_PAGES = "number_of_pages";
public static final String ATTR_PAGE_NUMBER = "page_number";
public static final String ATTR_PAGE_SIZE = "page_size";
public static final String ATTR_SORT_BY = "sort_by";
public static final String ATTR_SORT_ORDER = "sort_order";
public static final String ATTR_SORT = "sort";
public static final String ATTR_CONTENT = "content";
@JsonProperty(ATTR_NUMBER_OF_PAGES)
@ -37,10 +31,8 @@ public final class Page<T> {
public final Integer pageNumber;
@JsonProperty(ATTR_PAGE_SIZE)
public final Integer pageSize;
@JsonProperty(ATTR_SORT_BY)
public final String sortBy;
@JsonProperty(ATTR_SORT_ORDER)
public final SortOrder sortOrder;
@JsonProperty(ATTR_SORT)
public final String sort;
@JsonProperty(ATTR_CONTENT)
public final List<T> content;
@ -49,16 +41,14 @@ public final class Page<T> {
public Page(
@JsonProperty(ATTR_NUMBER_OF_PAGES) final Integer numberOfPages,
@JsonProperty(ATTR_PAGE_NUMBER) final Integer pageNumber,
@JsonProperty(ATTR_SORT_BY) final String sortBy,
@JsonProperty(ATTR_SORT_ORDER) final SortOrder sortOrder,
@JsonProperty(ATTR_SORT) final String sort,
@JsonProperty(ATTR_CONTENT) final Collection<T> content) {
this.numberOfPages = numberOfPages;
this.pageNumber = pageNumber;
this.content = Utils.immutableListOf(content);
this.pageSize = content.size();
this.sortBy = sortBy;
this.sortOrder = sortOrder;
this.sort = sort;
}
public Integer getNumberOfPages() {
@ -73,16 +63,15 @@ public final class Page<T> {
return this.pageSize;
}
public String getSortBy() {
return this.sortBy;
}
public SortOrder getSortOrder() {
return this.sortOrder;
}
public Collection<T> getContent() {
return this.content;
}
@Override
public String toString() {
return "Page [numberOfPages=" + this.numberOfPages + ", pageNumber=" + this.pageNumber + ", pageSize="
+ this.pageSize
+ ", sort=" + this.sort + ", content=" + this.content + "]";
}
}

View file

@ -35,6 +35,32 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamic
@WebServiceProfile
public class PaginationService {
public enum SortOrder {
ASCENDING("+"),
DESCENDING("-");
public final String prefix;
private SortOrder(final String prefix) {
this.prefix = prefix;
}
public static SortOrder getSortOrder(final String sort) {
return (sort != null && sort.startsWith(DESCENDING.prefix))
? SortOrder.DESCENDING
: SortOrder.ASCENDING;
}
public static String getSortColumn(final String sort) {
return (sort == null)
? null
: (sort.startsWith(SortOrder.ASCENDING.prefix) || sort.startsWith(SortOrder.DESCENDING.prefix))
? sort.substring(1)
: sort;
}
}
private final int defaultPageSize;
private final int maxPageSize;
@ -77,19 +103,15 @@ public class PaginationService {
if (PageHelper.getLocalPage() != null) {
return;
}
setPagination(1, this.maxPageSize, null, Page.SortOrder.ASCENDING, null);
setPagination(1, this.maxPageSize, null, null);
}
public void setDefaultLimit() {
setPagination(1, this.maxPageSize, null, Page.SortOrder.ASCENDING, null);
setPagination(1, this.maxPageSize, null, null);
}
public void setDefaultLimit(final String sortBy, final SqlTable table) {
setPagination(1, this.maxPageSize, sortBy, Page.SortOrder.ASCENDING, table);
}
public void setDefaultLimit(final String sortBy, final Page.SortOrder sortOrder, final SqlTable table) {
setPagination(1, this.maxPageSize, sortBy, sortOrder, table);
public void setDefaultLimit(final String sort, final SqlTable table) {
setPagination(1, this.maxPageSize, sort, table);
}
public int getPageNumber(final Integer pageNumber) {
@ -109,20 +131,23 @@ public class PaginationService {
public com.github.pagehelper.Page<Object> setPagination(
final Integer pageNumber,
final Integer pageSize,
final String sortBy,
final Page.SortOrder sortOrder,
final String sort,
final SqlTable table) {
final com.github.pagehelper.Page<Object> startPage =
PageHelper.startPage(getPageNumber(pageNumber), getPageSize(pageSize), true, true, false);
if (table != null) {
final String sortColumnName = verifySortColumnName(sortBy, table);
final String sortColumnName = verifySortColumnName(sort, table);
if (StringUtils.isNoneBlank(sortColumnName)) {
if (sortOrder == Page.SortOrder.DESCENDING) {
PageHelper.orderBy(sortColumnName + " DESC");
} else {
PageHelper.orderBy(sortColumnName);
switch (SortOrder.getSortOrder(sort)) {
case DESCENDING: {
PageHelper.orderBy(sortColumnName + " DESC");
break;
}
default: {
PageHelper.orderBy(sortColumnName);
}
}
}
}
@ -133,28 +158,31 @@ public class PaginationService {
public <T extends Entity> Result<Page<T>> getPage(
final Integer pageNumber,
final Integer pageSize,
final String sortBy,
final Page.SortOrder sortOrder,
final String sort,
final SqlTable table,
final Supplier<Result<Collection<T>>> delegate) {
return Result.tryCatch(() -> {
final com.github.pagehelper.Page<Object> page =
setPagination(pageNumber, pageSize, sortBy, sortOrder, table);
setPagination(pageNumber, pageSize, sort, table);
final Collection<T> pageList = delegate.get().getOrThrow();
return new Page<>(page.getPages(), page.getPageNum(), sortBy, sortOrder, pageList);
return new Page<>(page.getPages(), page.getPageNum(), sort, pageList);
});
}
private String verifySortColumnName(final String sortBy, final SqlTable table) {
private String verifySortColumnName(final String sort, final SqlTable table) {
if (StringUtils.isBlank(sortBy)) {
if (StringUtils.isBlank(sort)) {
return this.defaultSortColumn.get(table.name());
}
final Map<String, String> mapping = this.sortColumnMapping.get(table.name());
if (mapping != null) {
return mapping.get(sortBy);
final String sortColumn = SortOrder.getSortColumn(sort);
if (StringUtils.isBlank(sortColumn)) {
return this.defaultSortColumn.get(table.name());
}
return mapping.get(sortColumn);
}
return this.defaultSortColumn.get(table.name());

View file

@ -12,7 +12,6 @@ import java.util.Collection;
import java.util.Set;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
@ -21,23 +20,14 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
public interface LmsAPITemplate {
enum OrderBy {
NAME,
FROM,
TO
}
LmsSetup lmsSetup();
LmsSetupTestResult testLmsSetup();
Collection<QuizData> getQuizzes(String name, Long from, OrderBy orderBy, SortOrder sortOrder);
Page<QuizData> getQuizzesPage(
Page<QuizData> getQuizzes(
String name,
Long from,
OrderBy orderBy,
SortOrder sortOrder,
String sort,
int pageNumber,
int pageSize);

View file

@ -10,19 +10,20 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.model.user.ExamineeAccountDetails;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
public class MockupLmsAPITemplate implements LmsAPITemplate {
@ -78,12 +79,21 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
}
}
@Override
public Collection<QuizData> getQuizzes(
final String name,
final Long from,
final OrderBy orderBy,
final SortOrder sortOrder) {
final String sort) {
final int orderFactor = (SortOrder.getSortOrder(sort) == SortOrder.DESCENDING)
? -1
: 1;
final String _sort = SortOrder.getSortColumn(sort);
final Comparator<QuizData> comp = (_sort != null)
? (_sort.equals(QuizData.FILTER_ATTR_START_TIME))
? (q1, q2) -> q1.startTime.compareTo(q2.startTime) * orderFactor
: (q1, q2) -> q1.name.compareTo(q2.name) * orderFactor
: (q1, q2) -> q1.name.compareTo(q2.name) * orderFactor;
return this.mockups.stream()
.filter(mockup -> (name != null)
@ -91,22 +101,22 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
: true && (from != null)
? mockup.startTime.getMillis() >= from
: true)
.sorted(comp)
.collect(Collectors.toList());
}
@Override
public Page<QuizData> getQuizzesPage(
public Page<QuizData> getQuizzes(
final String name,
final Long from,
final OrderBy orderBy,
final SortOrder sortOrder,
final String sort,
final int pageNumber,
final int pageSize) {
final int startIndex = pageNumber * pageSize;
final int endIndex = startIndex + pageSize;
int index = 0;
final Collection<QuizData> quizzes = getQuizzes(name, from, orderBy, sortOrder);
final Collection<QuizData> quizzes = getQuizzes(name, from, sort);
final int numberOfPages = quizzes.size() / pageSize;
final Iterator<QuizData> iterator = quizzes.iterator();
final List<QuizData> pageContent = new ArrayList<>();
@ -118,7 +128,7 @@ public class MockupLmsAPITemplate implements LmsAPITemplate {
index++;
}
return new Page<>(numberOfPages, pageNumber, orderBy.name(), sortOrder, pageContent);
return new Page<>(numberOfPages, pageNumber, sort, pageContent);
}
@Override

View file

@ -67,15 +67,13 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
checkReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
sort,
UserRecordDynamicSqlSupport.userRecord,
() -> this.activatableEntityDAO.all(institutionId, true)).getOrThrow();
}
@ -92,15 +90,13 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
checkReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
sort,
UserRecordDynamicSqlSupport.userRecord,
() -> this.activatableEntityDAO.all(institutionId, false)).getOrThrow();
}

View file

@ -98,8 +98,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder,
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
@RequestParam final MultiValueMap<String, String> allRequestParams) {
checkReadPrivilege(institutionId);
@ -111,8 +110,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
sort,
getSQLTableOfEntity(),
() -> getAll(filterMap)).getOrThrow();
}

View file

@ -36,7 +36,6 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
@ -44,6 +43,7 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
@ -109,8 +109,7 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder,
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
@RequestParam final MultiValueMap<String, String> allRequestParams) {
checkReadPrivilege(institutionId);
@ -118,10 +117,10 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
// NOTE: several attributes for sorting may be originated by the QuizData from LMS not by the database
// of the SEB Server. Therefore in the case we have no or the default sorting we can use the
// native PaginationService within MyBatis and SQL. For the other cases we need an in-line sorting and paging
if (StringUtils.isBlank(sortBy) ||
this.paginationService.isNativeSortingSupported(ExamRecordDynamicSqlSupport.examRecord, sortBy)) {
if (StringUtils.isBlank(sort) ||
this.paginationService.isNativeSortingSupported(ExamRecordDynamicSqlSupport.examRecord, sort)) {
return super.getAll(institutionId, pageNumber, pageSize, sortBy, sortOrder, allRequestParams);
return super.getAll(institutionId, pageNumber, pageSize, sort, allRequestParams);
} else {
@ -136,7 +135,8 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
final List<Exam> exams = new ArrayList<>(
this.examDAO.allMatching(new FilterMap(allRequestParams)).getOrThrow());
if (!StringUtils.isBlank(sortBy)) {
if (!StringUtils.isBlank(sort)) {
final String sortBy = SortOrder.getSortColumn(sort);
if (sortBy.equals(QuizData.QUIZ_ATTR_NAME)) {
Collections.sort(exams, (exam1, exam2) -> exam1.name.compareTo(exam2.name));
}
@ -145,15 +145,14 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
}
}
if (SortOrder.DESCENDING == sortOrder) {
if (SortOrder.DESCENDING == SortOrder.getSortOrder(sort)) {
Collections.reverse(exams);
}
return new Page<>(
exams.size() / pSize,
pageNum,
sortBy,
sortOrder,
sort,
exams.subList(pageNum * pSize, pageNum * pSize + pSize));
}
}

View file

@ -17,16 +17,13 @@ import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.Page.SortOrder;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate.OrderBy;
@WebServiceProfile
@RestController
@ -58,8 +55,7 @@ public class QuizImportController {
@RequestParam(name = QuizData.FILTER_ATTR_START_TIME, required = false) final String startTime,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String orderBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final String sortOrder) {
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
final LmsAPITemplate lmsAPITemplate = this.lmsAPIService
.createLmsAPITemplate(lmsSetupId)
@ -70,13 +66,10 @@ public class QuizImportController {
PrivilegeType.READ_ONLY,
lmsAPITemplate.lmsSetup().institutionId);
return lmsAPITemplate.getQuizzesPage(
return lmsAPITemplate.getQuizzes(
nameLike,
Utils.dateTimeStringToTimestamp(startTime, null),
Result.tryCatch(() -> OrderBy.valueOf(orderBy))
.getOrElse(OrderBy.NAME),
Result.tryCatch(() -> SortOrder.valueOf(sortOrder))
.getOrElse(SortOrder.ASCENDING),
sort,
(pageNumber != null)
? pageNumber
: 1,

View file

@ -70,15 +70,13 @@ public class UserActivityLogController {
@RequestParam(name = UserActivityLog.FILTER_ATTR_ENTITY_TYPES, required = false) final String entityTypes,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT_BY, required = false) final String sortBy,
@RequestParam(name = Page.ATTR_SORT_ORDER, required = false) final Page.SortOrder sortOrder) {
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
checkBaseReadPrivilege(institutionId);
return this.paginationService.getPage(
pageNumber,
pageSize,
sortBy,
sortOrder,
sort,
UserRecordDynamicSqlSupport.userRecord,
() -> _getAll(institutionId, userId, from, to, activityTypes, entityTypes)).getOrThrow();
}

View file

@ -244,7 +244,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception {
final String token = getSebAdminAccess();
final Page<UserInfo> userInfos = this.jsonMapper.readValue(
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?sort_order=DESCENDING")
this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?sort=-")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())
@ -323,7 +323,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
userInfos = this.jsonMapper.readValue(
this.mockMvc
.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT
+ "?page_number=1&page_size=3&sort_order=DESCENDING&institutionId=2")
+ "?page_number=1&page_size=3&sort=-&institutionId=2")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk())