Commit 12d758a8 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge branch '299-pagination' into 'main'

Resolve "Pagination"

Closes #299

See merge request grin-global/grin-global-server!398
parents d055331c 24117e31
...@@ -18,8 +18,11 @@ package org.gringlobal.api.v1; ...@@ -18,8 +18,11 @@ package org.gringlobal.api.v1;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
...@@ -185,7 +188,7 @@ public class Pagination { ...@@ -185,7 +188,7 @@ public class Pagination {
*/ */
public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize) { public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize) {
return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(DEFAULT_SORT_DIRECTION), return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(DEFAULT_SORT_DIRECTION),
getSortProperties(DEFAULT_SORT_PROPERTIES)))); getSortProperties(DEFAULT_SORT_PROPERTIES))));
} }
/** /**
...@@ -198,7 +201,7 @@ public class Pagination { ...@@ -198,7 +201,7 @@ public class Pagination {
*/ */
public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize, final Direction defaultDir, final String... defaultSort) { public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize, final Direction defaultDir, final String... defaultSort) {
return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(defaultDir), return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(defaultDir),
getSortProperties(defaultSort)))); getSortProperties(defaultSort))));
} }
/** /**
...@@ -211,7 +214,7 @@ public class Pagination { ...@@ -211,7 +214,7 @@ public class Pagination {
*/ */
public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize, final Direction[] defaultDirs, final String... defaultSort) { public Pageable toPageRequest(final int maxPageSize, final int defaultPageSize, final Direction[] defaultDirs, final String... defaultSort) {
return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(defaultDirs), return PageRequest.of(p == null ? 0 : p, Integer.min(l == null ? defaultPageSize : l, maxPageSize), Sort.by(getSortOrders(getDirections(defaultDirs),
getSortProperties(defaultSort)))); getSortProperties(defaultSort))));
} }
/** /**
...@@ -228,6 +231,26 @@ public class Pagination { ...@@ -228,6 +231,26 @@ public class Pagination {
return PageRequest.of(0, maxPageSize, sort); return PageRequest.of(0, maxPageSize, sort);
} }
/**
* Add sorting by parameterName acs to the given pageable.
*
* @param page the page for adding sort
* @param paramNames the names of parameters for adding
* @return the updated pageable
*/
public static Pageable addSortByParams(Pageable page, Set<String> paramNames) {
if (CollectionUtils.isNotEmpty(paramNames) && page.isPaged() && page.getSort().isSorted()) {
Sort sort = page.getSort();
for(String paramName : paramNames) {
if (StringUtils.isNotBlank(paramName) && sort.getOrderFor(paramName) == null) {
sort = sort.and(Sort.by(Direction.ASC, paramName));
}
}
return PageRequest.of(page.getPageNumber(), page.getPageSize(), sort);
}
return page;
}
/** /**
* To page request. * To page request.
* *
......
...@@ -20,10 +20,12 @@ import java.lang.reflect.ParameterizedType; ...@@ -20,10 +20,12 @@ import java.lang.reflect.ParameterizedType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
...@@ -33,6 +35,7 @@ import org.genesys.filerepository.service.RepositoryService; ...@@ -33,6 +35,7 @@ import org.genesys.filerepository.service.RepositoryService;
import org.gringlobal.api.exception.InvalidApiUsageException; import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.exception.NotFoundElement; import org.gringlobal.api.exception.NotFoundElement;
import org.gringlobal.api.v1.MultiOp; import org.gringlobal.api.v1.MultiOp;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.model.AuditedModel; import org.gringlobal.model.AuditedModel;
import org.gringlobal.model.LazyLoading; import org.gringlobal.model.LazyLoading;
import org.gringlobal.service.CRUDService; import org.gringlobal.service.CRUDService;
...@@ -51,6 +54,7 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -51,6 +54,7 @@ import org.springframework.transaction.annotation.Transactional;
import com.querydsl.core.types.dsl.NumberPath; import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.util.ReflectionUtils;
/** /**
* The basic FilteredCRUDServiceImpl. * The basic FilteredCRUDServiceImpl.
...@@ -79,10 +83,20 @@ public abstract class CRUDServiceImpl<T extends EmptyModel, R extends JpaReposit ...@@ -79,10 +83,20 @@ public abstract class CRUDServiceImpl<T extends EmptyModel, R extends JpaReposit
@PersistenceContext @PersistenceContext
protected EntityManager entityManager; protected EntityManager entityManager;
protected Set<String> idSortParams = new HashSet<>();
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
// JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager); // JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager);
// this.builder = new PathBuilderFactory().create(domainClass); // this.builder = new PathBuilderFactory().create(domainClass);
idSortParams = getIdSortParams();
}
protected Set<String> getIdSortParams() {
var modelClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Set<String> idParamNames = new HashSet<>();
ReflectionUtils.doWithFields(modelClass, field -> idParamNames.add(field.getName()), field -> field.getAnnotation(Id.class) != null);
return idParamNames;
} }
// Until .lazyLoad() was in an interface // Until .lazyLoad() was in an interface
...@@ -191,6 +205,7 @@ public abstract class CRUDServiceImpl<T extends EmptyModel, R extends JpaReposit ...@@ -191,6 +205,7 @@ public abstract class CRUDServiceImpl<T extends EmptyModel, R extends JpaReposit
*/ */
@Override @Override
public Page<T> list(Pageable page) { public Page<T> list(Pageable page) {
page = Pagination.addSortByParams(page, idSortParams);
return repository.findAll(page); return repository.findAll(page);
} }
......
...@@ -19,6 +19,7 @@ import java.lang.reflect.ParameterizedType; ...@@ -19,6 +19,7 @@ import java.lang.reflect.ParameterizedType;
import org.genesys.blocks.model.EmptyModel; import org.genesys.blocks.model.EmptyModel;
import org.genesys.blocks.model.filters.EmptyModelFilter; import org.genesys.blocks.model.filters.EmptyModelFilter;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.custom.elasticsearch.SearchException; import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.service.ElasticsearchService; import org.gringlobal.service.ElasticsearchService;
import org.gringlobal.service.FilteredCRUDService; import org.gringlobal.service.FilteredCRUDService;
...@@ -59,6 +60,7 @@ public abstract class FilteredCRUDServiceImpl<E extends EmptyModel, F extends Em ...@@ -59,6 +60,7 @@ public abstract class FilteredCRUDServiceImpl<E extends EmptyModel, F extends Em
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
idSortParams = getIdSortParams();
} }
@Override @Override
...@@ -67,6 +69,8 @@ public abstract class FilteredCRUDServiceImpl<E extends EmptyModel, F extends Em ...@@ -67,6 +69,8 @@ public abstract class FilteredCRUDServiceImpl<E extends EmptyModel, F extends Em
} }
protected Page<E> list(Class<E> clazz, F filter, Pageable page, String... boostFields) throws SearchException { protected Page<E> list(Class<E> clazz, F filter, Pageable page, String... boostFields) throws SearchException {
page = Pagination.addSortByParams(page, idSortParams);
if (filter instanceof IFullTextFilter) { if (filter instanceof IFullTextFilter) {
IFullTextFilter ftf = (IFullTextFilter) filter; IFullTextFilter ftf = (IFullTextFilter) filter;
// if (ftf.isFulltextQuery() && elasticsearchService != null) { // This could be quietly ignoring full-test search // if (ftf.isFulltextQuery() && elasticsearchService != null) { // This could be quietly ignoring full-test search
......
...@@ -19,6 +19,7 @@ import java.util.List; ...@@ -19,6 +19,7 @@ import java.util.List;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.custom.elasticsearch.SearchException; import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.CooperatorOwnedLang; import org.gringlobal.model.CooperatorOwnedLang;
import org.gringlobal.model.SysLang; import org.gringlobal.model.SysLang;
...@@ -61,6 +62,7 @@ public abstract class FilteredTranslatedCRUDServiceImpl<E extends TranslatedCoop ...@@ -61,6 +62,7 @@ public abstract class FilteredTranslatedCRUDServiceImpl<E extends TranslatedCoop
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
idSortParams = getIdSortParams();
} }
@Override @Override
...@@ -86,6 +88,7 @@ public abstract class FilteredTranslatedCRUDServiceImpl<E extends TranslatedCoop ...@@ -86,6 +88,7 @@ public abstract class FilteredTranslatedCRUDServiceImpl<E extends TranslatedCoop
@Override @Override
public Page<T> listFiltered(F filter, Pageable page) throws SearchException { public Page<T> listFiltered(F filter, Pageable page) throws SearchException {
page = Pagination.addSortByParams(page, idSortParams);
return translationSupport.list(filter, page); return translationSupport.list(filter, page);
} }
......
...@@ -39,6 +39,7 @@ import org.springframework.http.MediaType; ...@@ -39,6 +39,7 @@ import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithUserDetails; import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.Set; import java.util.Set;
/** /**
...@@ -217,9 +218,53 @@ public class TaxonomyControllerTest extends AbstractApiV1Test { ...@@ -217,9 +218,53 @@ public class TaxonomyControllerTest extends AbstractApiV1Test {
@Test @Test
public void filterTaxonomySpeciesTest() throws Exception { public void filterTaxonomySpeciesTest() throws Exception {
var savedSpecies1 =addTaxonomySpeciesToDB(); var verifiedDate = new Date();
var savedSpecies2 = addTaxonomySpeciesToDB(); TaxonomySpecies taxonomySpecies = new TaxonomySpecies();
assertThat(speciesRepository.count(), is(2L)); taxonomySpecies.setIsFormaHybrid(FALSE);
taxonomySpecies.setIsNamePending(TRUE);
taxonomySpecies.setIsSpecificHybrid(FALSE);
taxonomySpecies.setIsSubspecificHybrid(FALSE);
taxonomySpecies.setIsSubvarietalHybrid(FALSE);
taxonomySpecies.setIsVarietalHybrid(FALSE);
taxonomySpecies.setSpeciesName("species");
taxonomySpecies.setSpeciesAuthority(null);
taxonomySpecies.setSubspeciesName(null);
taxonomySpecies.setSubspeciesAuthority(null);
taxonomySpecies.setTaxonomyGenus(addTaxonomyGenusToDB("Genus"));
taxonomySpecies.setNameVerifiedDate(verifiedDate);
TaxonomySpecies taxonomySpecies2 = new TaxonomySpecies();
taxonomySpecies2.setIsFormaHybrid(FALSE);
taxonomySpecies2.setIsNamePending(TRUE);
taxonomySpecies2.setIsSpecificHybrid(FALSE);
taxonomySpecies2.setIsSubspecificHybrid(FALSE);
taxonomySpecies2.setIsSubvarietalHybrid(FALSE);
taxonomySpecies2.setIsVarietalHybrid(FALSE);
taxonomySpecies2.setSpeciesName("species");
taxonomySpecies2.setSpeciesAuthority(null);
taxonomySpecies2.setSubspeciesName(null);
taxonomySpecies2.setSubspeciesAuthority(null);
taxonomySpecies2.setTaxonomyGenus(addTaxonomyGenusToDB("Genus"));
taxonomySpecies2.setNameVerifiedDate(verifiedDate);
TaxonomySpecies taxonomySpecies3 = new TaxonomySpecies();
taxonomySpecies3.setIsFormaHybrid(FALSE);
taxonomySpecies3.setIsNamePending(TRUE);
taxonomySpecies3.setIsSpecificHybrid(FALSE);
taxonomySpecies3.setIsSubspecificHybrid(FALSE);
taxonomySpecies3.setIsSubvarietalHybrid(FALSE);
taxonomySpecies3.setIsVarietalHybrid(FALSE);
taxonomySpecies3.setSpeciesName("species");
taxonomySpecies3.setSpeciesAuthority(null);
taxonomySpecies3.setSubspeciesName(null);
taxonomySpecies3.setSubspeciesAuthority(null);
taxonomySpecies3.setTaxonomyGenus(addTaxonomyGenusToDB("Genus"));
taxonomySpecies3.setNameVerifiedDate(verifiedDate);
var savedSpecies1 = taxonomySpeciesRepository.save(taxonomySpecies);
var savedSpecies2 = taxonomySpeciesRepository.save(taxonomySpecies2);
var savedSpecies3 = taxonomySpeciesRepository.save(taxonomySpecies3);
assertThat(speciesRepository.count(), is(3L));
TaxonomySpeciesFilter filter = new TaxonomySpeciesFilter(); TaxonomySpeciesFilter filter = new TaxonomySpeciesFilter();
filter.id = Set.of(savedSpecies2.getId()); filter.id = Set.of(savedSpecies2.getId());
...@@ -255,6 +300,27 @@ public class TaxonomyControllerTest extends AbstractApiV1Test { ...@@ -255,6 +300,27 @@ public class TaxonomyControllerTest extends AbstractApiV1Test {
.andExpect(jsonPath("$.content[0].id", is(savedSpecies1.getId().intValue()))) .andExpect(jsonPath("$.content[0].id", is(savedSpecies1.getId().intValue())))
; ;
/*@formatter:on*/ /*@formatter:on*/
filter = new TaxonomySpeciesFilter();
/*@formatter:off*/
mockMvc
.perform(post(TaxonomyController.SpeciesController.API_URL + "/filter?d=ASC&s=nameVerifiedDate")
.content(verboseMapper.writeValueAsString(filter))
.contentType(MediaType.APPLICATION_JSON))
.andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", not(nullValue())))
.andExpect(jsonPath("$.totalElements", is(3)))
.andExpect(jsonPath("$.content").isArray())
.andExpect(jsonPath("$.content[0].id", is(savedSpecies1.getId().intValue())))
.andExpect(jsonPath("$.content[1].id", is(savedSpecies2.getId().intValue())))
.andExpect(jsonPath("$.content[2].id", is(savedSpecies3.getId().intValue())))
.andExpect(jsonPath("$.sort[1].property", is("id")))
.andExpect(jsonPath("$.sort[1].direction", is("ASC")))
;
/*@formatter:on*/
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment