Search in sources :

Example 1 with DefaultKeysetPage

use of com.blazebit.persistence.DefaultKeysetPage in project blaze-persistence by Blazebit.

the class PaginatedTypedQueryImpl method getResultList.

private PagedList<X> getResultList(int queryFirstResult, int firstRow, long totalSize) {
    if (idQuery != null) {
        idQuery.setMaxResults(pageSize);
        if (forceFirstResult || keysetMode == KeysetMode.NONE) {
            idQuery.setFirstResult(firstRow);
        } else {
            idQuery.setFirstResult(0);
        }
        List<?> ids = idQuery.getResultList();
        if (ids.isEmpty()) {
            KeysetPage newKeysetPage = null;
            if (keysetMode == KeysetMode.NEXT) {
                // When we scroll over the last page to a non existing one, we reuse the current keyset
                newKeysetPage = keysetPage;
            }
            long size;
            if (withCount && totalSize == -1) {
                size = getTotalCount();
            } else {
                size = totalSize;
            }
            if (boundedCount) {
                if (keysetMode == KeysetMode.NEXT) {
                    size = Math.max(size, keysetPage.getFirstResult() + keysetPage.getMaxResults());
                } else if (forceFirstResult || keysetMode == KeysetMode.NONE) {
                    size = Math.max(size, firstRow);
                }
            }
            return new PagedArrayList<X>(newKeysetPage, size, queryFirstResult, pageSize);
        }
        Serializable[] lowest = null;
        Serializable[] highest = null;
        Serializable[][] keysets = null;
        if (needsNewIdList) {
            if (keysetToSelectIndexMapping != null) {
                int keysetPageSize = pageSize - highestOffset;
                int size = Math.min(ids.size(), keysetPageSize);
                int lowestIndex;
                int highestIndex;
                // Swap keysets as we have inverse ordering when going to the previous page
                if (keysetMode == KeysetMode.PREVIOUS) {
                    lowestIndex = size - 1;
                    highestIndex = 0;
                } else {
                    lowestIndex = 0;
                    highestIndex = size - 1;
                }
                if (ids.get(0) instanceof Object[]) {
                    if (withExtractAllKeysets) {
                        keysets = new Serializable[size][];
                        for (int i = 0; i < size; i++) {
                            keysets[i] = KeysetPaginationHelper.extractKey((Object[]) ids.get(i), keysetToSelectIndexMapping, keysetSuffix);
                        }
                        lowest = keysets[lowestIndex];
                        highest = keysets[highestIndex];
                    } else {
                        lowest = KeysetPaginationHelper.extractKey((Object[]) ids.get(lowestIndex), keysetToSelectIndexMapping, keysetSuffix);
                        highest = KeysetPaginationHelper.extractKey((Object[]) ids.get(highestIndex), keysetToSelectIndexMapping, keysetSuffix);
                    }
                } else {
                    if (withExtractAllKeysets) {
                        keysets = new Serializable[size][];
                        for (int i = 0; i < size; i++) {
                            keysets[i] = new Serializable[] { (Serializable) (ids.get(i)) };
                        }
                        lowest = keysets[lowestIndex];
                        highest = keysets[highestIndex];
                    } else {
                        lowest = new Serializable[] { (Serializable) ids.get(lowestIndex) };
                        highest = new Serializable[] { (Serializable) ids.get(highestIndex) };
                    }
                }
                // Swap keysets as we have inverse ordering when going to the previous page
                if (keysetMode == KeysetMode.PREVIOUS) {
                    if (withExtractAllKeysets) {
                        // Reverse the keysets
                        Serializable[] tmp;
                        for (int i = 0, mid = size >> 1, j = size - 1; i < mid; i++, j--) {
                            tmp = keysets[i];
                            keysets[i] = keysets[j];
                            keysets[j] = tmp;
                        }
                    }
                }
            }
            // extract count
            if (inlinedCountQuery) {
                Object[] first = (Object[]) ids.get(0);
                totalSize = (long) first[first.length - 1];
            }
            List<Object> newIds = new ArrayList<Object>(ids.size());
            if (identifierCount > 1) {
                for (int i = 0; i < ids.size(); i++) {
                    Object[] tuple = (Object[]) ids.get(i);
                    Object newId = new Object[identifierCount];
                    System.arraycopy(tuple, 0, newId, 0, identifierCount);
                    newIds.add(newId);
                }
            } else {
                for (int i = 0; i < ids.size(); i++) {
                    Object o = ids.get(i);
                    if (o instanceof Object[]) {
                        newIds.add(((Object[]) o)[0]);
                    } else {
                        newIds.add(o);
                    }
                }
            }
            ids = newIds;
        } else if (inlinedCountQuery) {
            Object[] first = (Object[]) ids.get(0);
            int newSize = first.length - 1;
            totalSize = (long) first[first.length - 1];
            // If this would have been a non-object array type without the count query, we must unwrap the result
            List<Object> newIds = new ArrayList<>(ids.size());
            if (newSize == 1) {
                for (int i = 0; i < ids.size(); i++) {
                    newIds.add(((Object[]) ids.get(i))[0]);
                }
            } else {
                for (int i = 0; i < ids.size(); i++) {
                    Object[] tuple = (Object[]) ids.get(i);
                    Object newId = new Object[newSize];
                    System.arraycopy(tuple, 0, newId, 0, newSize);
                    newIds.add(newId);
                }
            }
            ids = newIds;
        }
        if (identifierCount > 1) {
            StringBuilder parameterNameBuilder = new StringBuilder(AbstractCommonQueryBuilder.ID_PARAM_NAME.length() + 10);
            parameterNameBuilder.append(AbstractCommonQueryBuilder.ID_PARAM_NAME).append('_');
            int start = parameterNameBuilder.length();
            Object[] empty = ids.size() < pageSize ? new Object[identifierCount] : null;
            for (int i = 0; i < pageSize; i++) {
                Object[] tuple;
                if (ids.size() > i) {
                    tuple = (Object[]) ids.get(i);
                } else {
                    tuple = empty;
                }
                for (int j = 0; j < identifierCount; j++) {
                    parameterNameBuilder.setLength(start);
                    parameterNameBuilder.append(j).append('_').append(i);
                    objectQuery.setParameter(parameterNameBuilder.toString(), tuple[j]);
                }
            }
        } else {
            objectQuery.setParameter(AbstractCommonQueryBuilder.ID_PARAM_NAME, ids);
        }
        KeysetPage newKeyset = null;
        if (keysetToSelectIndexMapping != null) {
            newKeyset = new DefaultKeysetPage(firstRow, pageSize, lowest, highest, keysets);
        }
        totalSize = Math.max(totalSize, firstRow + ids.size());
        List<X> queryResultList = objectQuery.getResultList();
        PagedList<X> pagedResultList = new PagedArrayList<X>(queryResultList, newKeyset, totalSize, queryFirstResult, pageSize);
        return pagedResultList;
    } else {
        if (!inlinedIdQuery) {
            objectQuery.setMaxResults(pageSize);
            if (forceFirstResult || keysetMode == KeysetMode.NONE) {
                objectQuery.setFirstResult(firstRow);
            } else {
                objectQuery.setFirstResult(0);
            }
        }
        List<X> result = objectQuery.getResultList();
        if (result.isEmpty()) {
            KeysetPage newKeysetPage = null;
            if (keysetMode == KeysetMode.NEXT) {
                // When we scroll over the last page to a non existing one, we reuse the current keyset
                newKeysetPage = keysetPage;
            }
            if (totalSize == -1) {
                if (inlinedCountQuery && firstRow == 0) {
                    totalSize = 0L;
                } else if (withCount) {
                    totalSize = getTotalCount();
                }
            }
            if (boundedCount) {
                if (keysetMode == KeysetMode.NEXT) {
                    totalSize = Math.max(totalSize, keysetPage.getFirstResult() + keysetPage.getMaxResults());
                } else if (forceFirstResult || keysetMode == KeysetMode.NONE) {
                    totalSize = Math.max(totalSize, firstRow);
                }
            }
            return new PagedArrayList<X>(newKeysetPage, totalSize, queryFirstResult, pageSize);
        }
        if (keysetMode == KeysetMode.PREVIOUS) {
            Collections.reverse(result);
        }
        KeysetPage newKeyset = null;
        if (keysetToSelectIndexMapping != null) {
            if (objectBuilder == null) {
                // extract count
                if (inlinedCountQuery) {
                    Object[] first = (Object[]) result.get(0);
                    totalSize = (long) first[first.length - 1];
                    // If this would have been a non-object array type without the count query, we must unwrap the result
                    if (first.length == 2) {
                        List<X> newResult = new ArrayList<>(result.size());
                        for (int i = 0; i < result.size(); i++) {
                            newResult.add((X) ((Object[]) result.get(i))[0]);
                        }
                        result = newResult;
                    }
                }
            } else if (objectBuilder instanceof KeysetExtractionObjectBuilder<?>) {
                KeysetExtractionObjectBuilder<?> keysetExtractionObjectBuilder = (KeysetExtractionObjectBuilder<?>) objectBuilder;
                Serializable[] lowest = keysetExtractionObjectBuilder.getLowest();
                Serializable[] highest = keysetExtractionObjectBuilder.getHighest();
                Serializable[][] keysets = keysetExtractionObjectBuilder.getKeysets();
                // extract count
                if (inlinedCountQuery) {
                    totalSize = keysetExtractionObjectBuilder.getCount();
                }
                newKeyset = new DefaultKeysetPage(firstRow, pageSize, lowest, highest, keysets);
            } else if (objectBuilder instanceof CountExtractionObjectBuilder<?>) {
                totalSize = ((CountExtractionObjectBuilder<X>) objectBuilder).getCount();
            }
        }
        totalSize = Math.max(totalSize, firstRow + result.size());
        PagedList<X> pagedResultList = new PagedArrayList<X>(result, newKeyset, totalSize, queryFirstResult, pageSize);
        return pagedResultList;
    }
}
Also used : Serializable(java.io.Serializable) KeysetExtractionObjectBuilder(com.blazebit.persistence.impl.builder.object.KeysetExtractionObjectBuilder) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) CountExtractionObjectBuilder(com.blazebit.persistence.impl.builder.object.CountExtractionObjectBuilder) PagedArrayList(com.blazebit.persistence.PagedArrayList) ArrayList(java.util.ArrayList) KeysetPage(com.blazebit.persistence.KeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) PagedArrayList(com.blazebit.persistence.PagedArrayList) PagedArrayList(com.blazebit.persistence.PagedArrayList) ArrayList(java.util.ArrayList) PagedList(com.blazebit.persistence.PagedList) List(java.util.List)

Example 2 with DefaultKeysetPage

use of com.blazebit.persistence.DefaultKeysetPage in project blaze-persistence by Blazebit.

the class KeysetPageableHandlerMethodArgumentResolver method resolveArgument.

@Override
public Mono<Object> resolveArgument(MethodParameter methodParameter, BindingContext bindingContext, ServerWebExchange serverWebExchange) {
    assertPageableUniqueness(methodParameter);
    Pageable defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter);
    String pageString = serverWebExchange.getRequest().getQueryParams().getFirst(getParameterNameToUse(getPageParameterName(), methodParameter));
    String offsetString = serverWebExchange.getRequest().getQueryParams().getFirst(getParameterNameToUse(getOffsetParameterName(), methodParameter));
    String pageSizeString = serverWebExchange.getRequest().getQueryParams().getFirst(getParameterNameToUse(getSizeParameterName(), methodParameter));
    boolean pageAndSizeGiven = (StringUtils.hasText(pageString) || StringUtils.hasText(offsetString)) && StringUtils.hasText(pageSizeString);
    if (!pageAndSizeGiven && defaultOrFallback == null) {
        return null;
    }
    int pageSize = StringUtils.hasText(pageSizeString) ? parseAndApplyBoundaries(pageSizeString, getMaxPageSize(), false) : defaultOrFallback.getPageSize();
    // Limit lower bound
    pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
    // Limit upper bound
    pageSize = pageSize > getMaxPageSize() ? getMaxPageSize() : pageSize;
    int offset;
    if (StringUtils.hasText(offsetString)) {
        offset = parseAndApplyBoundaries(offsetString, Integer.MAX_VALUE, false);
    } else if (StringUtils.hasText(pageString)) {
        offset = pageSize * parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);
    } else {
        offset = pageSize * defaultOrFallback.getPageNumber();
    }
    org.springframework.data.domain.Sort sort = (org.springframework.data.domain.Sort) sortResolver.resolveArgument(methodParameter, bindingContext, serverWebExchange).block();
    // Default if necessary and default configured
    sort = sort == UNSORTED && defaultOrFallback != null ? defaultOrFallback.getSort() : sort;
    KeysetPage keysetPage = null;
    Iterator<org.springframework.data.domain.Sort.Order> iterator;
    if (sort != null && (iterator = sort.iterator()).hasNext()) {
        KeysetConfig keysetConfig = methodParameter.getParameterAnnotation(KeysetConfig.class);
        Class<?> domainClass = keysetConfig.keysetClass();
        if (domainClass == void.class) {
            domainClass = keysetConfig.value();
        }
        if (domainClass == void.class) {
            Method annotatedMethod = methodParameter.getMethod();
            throw new IllegalStateException(String.format(INVALID_KEYSET_DOMAIN_CLASS, annotatedMethod));
        }
        String previousOffsetName = getParameterName(keysetConfig.previousOffsetName(), getParameterNameToUse(getPreviousOffsetParameterName(), methodParameter));
        String previousOffsetString = serverWebExchange.getRequest().getQueryParams().getFirst(previousOffsetName);
        String previousPageName = getParameterName(keysetConfig.previousPageName(), getParameterNameToUse(getPreviousPageParameterName(), methodParameter));
        String previousPageString = serverWebExchange.getRequest().getQueryParams().getFirst(previousPageName);
        if (StringUtils.hasText(previousOffsetString) || StringUtils.hasText(previousPageString)) {
            String previousPageSizeName = getParameterName(keysetConfig.previousPageSizeName(), getParameterNameToUse(getPreviousSizeParameterName(), methodParameter));
            String previousPageSizeString = serverWebExchange.getRequest().getQueryParams().getFirst(previousPageSizeName);
            int previousPageSize = StringUtils.hasText(previousPageSizeString) ? parseAndApplyBoundaries(previousPageSizeString, getMaxPageSize(), false) : pageSize;
            int previousOffset;
            if (StringUtils.hasText(previousOffsetString)) {
                previousOffset = parseAndApplyBoundaries(previousOffsetString, Integer.MAX_VALUE, false);
            } else {
                int previousPage = parseAndApplyBoundaries(previousPageString, Integer.MAX_VALUE, true);
                previousOffset = previousPage * previousPageSize;
            }
            String lowestName = getParameterName(keysetConfig.lowestName(), getParameterNameToUse(getLowestParameterName(), methodParameter));
            String lowestString = serverWebExchange.getRequest().getQueryParams().getFirst(lowestName);
            String highestName = getParameterName(keysetConfig.highestName(), getParameterNameToUse(getHighestParameterName(), methodParameter));
            String highestString = serverWebExchange.getRequest().getQueryParams().getFirst(highestName);
            if (StringUtils.hasText(lowestString) && StringUtils.hasText(highestString)) {
                List<Serializable> lowest = new ArrayList<>();
                List<Serializable> highest = new ArrayList<>();
                JsonNode lowestObject;
                JsonNode highestObject;
                try {
                    lowestObject = mapper.readTree(lowestString);
                } catch (IOException ex) {
                    throw new IllegalArgumentException("Invalid lowest object!", ex);
                }
                try {
                    highestObject = mapper.readTree(highestString);
                } catch (IOException ex) {
                    throw new IllegalArgumentException("Invalid highest object!", ex);
                }
                while (iterator.hasNext()) {
                    org.springframework.data.domain.Sort.Order o = iterator.next();
                    JsonNode low = lowestObject;
                    JsonNode high = highestObject;
                    String[] propertyParts = o.getProperty().split("\\.");
                    Class<? extends Serializable> propertyType = getPropertyType(domainClass, o.getProperty());
                    for (int i = 0; i < propertyParts.length; i++) {
                        low = low == null ? null : low.get(propertyParts[i]);
                        high = high == null ? null : high.get(propertyParts[i]);
                    }
                    lowest.add(low == null ? null : convert(low, propertyType));
                    highest.add(high == null ? null : convert(high, propertyType));
                }
                keysetPage = new DefaultKeysetPage(previousOffset, previousPageSize, new DefaultKeyset(lowest.toArray(new Serializable[lowest.size()])), new DefaultKeyset(highest.toArray(new Serializable[highest.size()])));
            }
        }
    }
    return Mono.just(new KeysetPageRequest(keysetPage, sort, offset, pageSize));
}
Also used : Serializable(java.io.Serializable) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) KeysetPageable(com.blazebit.persistence.spring.data.repository.KeysetPageable) Pageable(org.springframework.data.domain.Pageable) DefaultKeyset(com.blazebit.persistence.DefaultKeyset) Method(java.lang.reflect.Method) IOException(java.io.IOException) KeysetConfig(com.blazebit.persistence.spring.data.webflux.KeysetConfig) KeysetPage(com.blazebit.persistence.KeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) KeysetPageRequest(com.blazebit.persistence.spring.data.repository.KeysetPageRequest)

Example 3 with DefaultKeysetPage

use of com.blazebit.persistence.DefaultKeysetPage in project blaze-persistence by Blazebit.

the class GraphQLEntityViewSupport method extractKeysetPage.

/**
 * Extracts the {@link KeysetPage} from the page size and offset,
 * as well as deserializing before or after cursors.
 *
 * @param first The GraphQL relay first parameter
 * @param last The GraphQL relay last parameter
 * @param beforeCursor The GraphQL relay before cursor
 * @param afterCursor The GraphQL relay after cursor
 * @return the {@link KeysetPage} or <code>null</code>
 */
public KeysetPage extractKeysetPage(Integer first, Integer last, String beforeCursor, String afterCursor) {
    if (first == null && last == null && beforeCursor == null && afterCursor == null) {
        return null;
    } else {
        KeysetPage keysetPage;
        if (beforeCursor != null) {
            if (afterCursor != null) {
                throw new RuntimeException("Can't provide both beforeCursor and afterCursor!");
            }
            GraphQLCursor cursor = deserialize(beforeCursor);
            keysetPage = new DefaultKeysetPage(cursor.getOffset(), cursor.getPageSize(), new DefaultKeyset(cursor.getTuple()), null);
        } else if (afterCursor != null) {
            if (last != null) {
                // Using an after cursor with last does not make sense, so skip using the cursor
                // The only problem with that is, that the cursor could refer to the last element
                // If that is the case, we would still get a result, which is IMO an edge case and can be ignored
                keysetPage = new DefaultKeysetPage(0, last, new DefaultKeyset(null), null);
            } else {
                GraphQLCursor cursor = deserialize(afterCursor);
                keysetPage = new DefaultKeysetPage(cursor.getOffset(), cursor.getPageSize(), null, new DefaultKeyset(cursor.getTuple()));
            }
        } else if (first != null) {
            keysetPage = new DefaultKeysetPage(0, first, null, null);
        } else {
            // Keyset with empty tuple is a special case for traversing the result list in reverse order
            keysetPage = new DefaultKeysetPage(0, last, new DefaultKeyset(null), null);
        }
        return keysetPage;
    }
}
Also used : KeysetPage(com.blazebit.persistence.KeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) DefaultKeyset(com.blazebit.persistence.DefaultKeyset)

Example 4 with DefaultKeysetPage

use of com.blazebit.persistence.DefaultKeysetPage in project blaze-persistence by Blazebit.

the class KeysetPageableParamConverter method fromString.

@Override
public Pageable fromString(String value) {
    MultivaluedMap<String, String> queryParameters = requestUriInfo.getQueryParameters();
    Pageable defaultOrFallback = pageableConfiguration.getFallbackPageable();
    String offsetString = queryParameters.getFirst(pageableConfiguration.getPrefix() + pageableConfiguration.getOffsetParameterName());
    String pageString = queryParameters.getFirst(pageableConfiguration.getPrefix() + pageableConfiguration.getPageParameterName());
    String pageSizeString = queryParameters.getFirst(pageableConfiguration.getPrefix() + pageableConfiguration.getSizeParameterName());
    boolean pageAndSizeGiven = (!StringUtils.isEmpty(pageString) || !StringUtils.isEmpty(offsetString)) && !StringUtils.isEmpty(pageSizeString);
    if (!pageAndSizeGiven && defaultOrFallback == null) {
        return null;
    }
    int maxPageSize = pageableConfiguration.getMaxPageSize();
    int pageSize = !StringUtils.isEmpty(pageSizeString) ? parseAndApplyBoundaries(pageSizeString, maxPageSize, false) : defaultOrFallback.getPageSize();
    // Limit lower bound
    pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
    // Limit upper bound
    pageSize = pageSize > maxPageSize ? maxPageSize : pageSize;
    int offset;
    if (!StringUtils.isEmpty(offsetString)) {
        offset = parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, false);
    } else if (!StringUtils.isEmpty(pageString)) {
        offset = pageSize * parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);
    } else {
        offset = pageSize * defaultOrFallback.getPageNumber();
    }
    Sort sort = resolveSort(queryParameters.get(pageableConfiguration.getSortParameterName()));
    // Default if necessary and default configured
    sort = sort == null && defaultOrFallback != null ? defaultOrFallback.getSort() : sort;
    KeysetPage keysetPage = null;
    Iterator<Sort.Order> iterator;
    if (keysetClass != null) {
        if (sort != null && (iterator = sort.iterator()).hasNext()) {
            String previousOffsetString = queryParameters.getFirst(keysetPageableConfiguration.getPrefix() + keysetPageableConfiguration.getPreviousOffsetParameterName());
            String previousPageString = queryParameters.getFirst(keysetPageableConfiguration.getPrefix() + keysetPageableConfiguration.getPreviousPageParameterName());
            if (!StringUtils.isEmpty(previousOffsetString) || !StringUtils.isEmpty(previousPageString)) {
                String previousPageSizeString = queryParameters.getFirst(keysetPageableConfiguration.getPrefix() + keysetPageableConfiguration.getPreviousSizeParameterName());
                int previousPageSize = StringUtils.isEmpty(previousPageSizeString) ? pageSize : parseAndApplyBoundaries(previousPageSizeString, maxPageSize, false);
                int previousOffset;
                if (!StringUtils.isEmpty(previousOffsetString)) {
                    previousOffset = parseAndApplyBoundaries(previousOffsetString, Integer.MAX_VALUE, false);
                } else {
                    int previousPage = parseAndApplyBoundaries(previousPageString, Integer.MAX_VALUE, true);
                    previousOffset = previousPage * previousPageSize;
                }
                String lowestString = queryParameters.getFirst(keysetPageableConfiguration.getPrefix() + keysetPageableConfiguration.getLowestParameterName());
                String highestString = queryParameters.getFirst(keysetPageableConfiguration.getPrefix() + keysetPageableConfiguration.getHighestParameterName());
                if (!StringUtils.isEmpty(lowestString) && !StringUtils.isEmpty(highestString)) {
                    List<Serializable> lowest = new ArrayList<>();
                    List<Serializable> highest = new ArrayList<>();
                    JsonNode lowestObject;
                    JsonNode highestObject;
                    try {
                        lowestObject = mapper.readTree(lowestString);
                    } catch (IOException ex) {
                        throw new IllegalArgumentException("Invalid lowest object!", ex);
                    }
                    try {
                        highestObject = mapper.readTree(highestString);
                    } catch (IOException ex) {
                        throw new IllegalArgumentException("Invalid highest object!", ex);
                    }
                    while (iterator.hasNext()) {
                        Sort.Order o = iterator.next();
                        JsonNode low = lowestObject;
                        JsonNode high = highestObject;
                        String[] propertyParts = o.getPath().split("\\.");
                        Class<? extends Serializable> propertyType = getPropertyType(keysetClass, o.getPath());
                        for (int i = 0; i < propertyParts.length; i++) {
                            low = low == null ? null : low.get(propertyParts[i]);
                            high = high == null ? null : high.get(propertyParts[i]);
                        }
                        lowest.add(low == null ? null : convert(low, propertyType));
                        highest.add(high == null ? null : convert(high, propertyType));
                    }
                    keysetPage = new DefaultKeysetPage(previousOffset, previousPageSize, new DefaultKeyset(lowest.toArray(new Serializable[lowest.size()])), new DefaultKeyset(highest.toArray(new Serializable[highest.size()])));
                }
            }
        }
        return new KeysetPageRequest(keysetPage, sort, offset, pageSize);
    }
    return new PageRequest(sort, offset, pageSize);
}
Also used : Serializable(java.io.Serializable) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) IOException(java.io.IOException) KeysetPage(com.blazebit.persistence.KeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) KeysetPageRequest(com.blazebit.persistence.deltaspike.data.KeysetPageRequest) PageRequest(com.blazebit.persistence.deltaspike.data.PageRequest) Pageable(com.blazebit.persistence.deltaspike.data.Pageable) DefaultKeyset(com.blazebit.persistence.DefaultKeyset) KeysetPageRequest(com.blazebit.persistence.deltaspike.data.KeysetPageRequest) Sort(com.blazebit.persistence.deltaspike.data.Sort)

Example 5 with DefaultKeysetPage

use of com.blazebit.persistence.DefaultKeysetPage in project blaze-persistence by Blazebit.

the class KeysetPageableHandlerMethodArgumentResolver method resolveArgument.

@Override
public KeysetPageable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
    assertPageableUniqueness(methodParameter);
    Pageable defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter);
    String pageString = webRequest.getParameter(getParameterNameToUse(getPageParameterName(), methodParameter));
    String offsetString = webRequest.getParameter(getParameterNameToUse(getOffsetParameterName(), methodParameter));
    String pageSizeString = webRequest.getParameter(getParameterNameToUse(getSizeParameterName(), methodParameter));
    boolean pageAndSizeGiven = (StringUtils.hasText(pageString) || StringUtils.hasText(offsetString)) && StringUtils.hasText(pageSizeString);
    if (!pageAndSizeGiven && defaultOrFallback == null) {
        return null;
    }
    int pageSize = StringUtils.hasText(pageSizeString) ? parseAndApplyBoundaries(pageSizeString, getMaxPageSize(), false) : defaultOrFallback.getPageSize();
    // Limit lower bound
    pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
    // Limit upper bound
    pageSize = pageSize > getMaxPageSize() ? getMaxPageSize() : pageSize;
    int offset;
    if (StringUtils.hasText(offsetString)) {
        offset = parseAndApplyBoundaries(offsetString, Integer.MAX_VALUE, false);
    } else if (StringUtils.hasText(pageString)) {
        offset = pageSize * parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);
    } else {
        offset = pageSize * defaultOrFallback.getPageNumber();
    }
    org.springframework.data.domain.Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
    // Default if necessary and default configured
    sort = sort == UNSORTED && defaultOrFallback != null ? defaultOrFallback.getSort() : sort;
    KeysetPage keysetPage = null;
    Iterator<org.springframework.data.domain.Sort.Order> iterator;
    if (sort != null && (iterator = sort.iterator()).hasNext()) {
        KeysetConfig keysetConfig = methodParameter.getParameterAnnotation(KeysetConfig.class);
        Class<?> domainClass = keysetConfig.keysetClass();
        if (domainClass == void.class) {
            domainClass = keysetConfig.value();
        }
        if (domainClass == void.class) {
            Method annotatedMethod = methodParameter.getMethod();
            throw new IllegalStateException(String.format(INVALID_KEYSET_DOMAIN_CLASS, annotatedMethod));
        }
        String previousOffsetName = getParameterName(keysetConfig.previousOffsetName(), getParameterNameToUse(getPreviousOffsetParameterName(), methodParameter));
        String previousOffsetString = webRequest.getParameter(previousOffsetName);
        String previousPageName = getParameterName(keysetConfig.previousPageName(), getParameterNameToUse(getPreviousPageParameterName(), methodParameter));
        String previousPageString = webRequest.getParameter(previousPageName);
        if (StringUtils.hasText(previousOffsetString) || StringUtils.hasText(previousPageString)) {
            String previousPageSizeName = getParameterName(keysetConfig.previousPageSizeName(), getParameterNameToUse(getPreviousSizeParameterName(), methodParameter));
            String previousPageSizeString = webRequest.getParameter(previousPageSizeName);
            int previousPageSize = StringUtils.hasText(previousPageSizeString) ? parseAndApplyBoundaries(previousPageSizeString, getMaxPageSize(), false) : pageSize;
            int previousOffset;
            if (StringUtils.hasText(previousOffsetString)) {
                previousOffset = parseAndApplyBoundaries(previousOffsetString, Integer.MAX_VALUE, false);
            } else {
                int previousPage = parseAndApplyBoundaries(previousPageString, Integer.MAX_VALUE, true);
                previousOffset = previousPage * previousPageSize;
            }
            String lowestName = getParameterName(keysetConfig.lowestName(), getParameterNameToUse(getLowestParameterName(), methodParameter));
            String lowestString = webRequest.getParameter(lowestName);
            String highestName = getParameterName(keysetConfig.highestName(), getParameterNameToUse(getHighestParameterName(), methodParameter));
            String highestString = webRequest.getParameter(highestName);
            if (StringUtils.hasText(lowestString) && StringUtils.hasText(highestString)) {
                List<Serializable> lowest = new ArrayList<>();
                List<Serializable> highest = new ArrayList<>();
                JsonNode lowestObject;
                JsonNode highestObject;
                try {
                    lowestObject = mapper.readTree(lowestString);
                } catch (IOException ex) {
                    throw new IllegalArgumentException("Invalid lowest object!", ex);
                }
                try {
                    highestObject = mapper.readTree(highestString);
                } catch (IOException ex) {
                    throw new IllegalArgumentException("Invalid highest object!", ex);
                }
                while (iterator.hasNext()) {
                    org.springframework.data.domain.Sort.Order o = iterator.next();
                    JsonNode low = lowestObject;
                    JsonNode high = highestObject;
                    String[] propertyParts = o.getProperty().split("\\.");
                    Class<? extends Serializable> propertyType = getPropertyType(domainClass, o.getProperty());
                    for (int i = 0; i < propertyParts.length; i++) {
                        low = low == null ? null : low.get(propertyParts[i]);
                        high = high == null ? null : high.get(propertyParts[i]);
                    }
                    lowest.add(low == null ? null : convert(low, propertyType));
                    highest.add(high == null ? null : convert(high, propertyType));
                }
                keysetPage = new DefaultKeysetPage(previousOffset, previousPageSize, new DefaultKeyset(lowest.toArray(new Serializable[lowest.size()])), new DefaultKeyset(highest.toArray(new Serializable[highest.size()])));
            }
        }
    }
    return new KeysetPageRequest(keysetPage, sort, offset, pageSize);
}
Also used : Serializable(java.io.Serializable) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) KeysetPageable(com.blazebit.persistence.spring.data.repository.KeysetPageable) Pageable(org.springframework.data.domain.Pageable) DefaultKeyset(com.blazebit.persistence.DefaultKeyset) Method(java.lang.reflect.Method) IOException(java.io.IOException) KeysetConfig(com.blazebit.persistence.spring.data.webmvc.KeysetConfig) KeysetPage(com.blazebit.persistence.KeysetPage) DefaultKeysetPage(com.blazebit.persistence.DefaultKeysetPage) KeysetPageRequest(com.blazebit.persistence.spring.data.repository.KeysetPageRequest)

Aggregations

DefaultKeysetPage (com.blazebit.persistence.DefaultKeysetPage)6 DefaultKeyset (com.blazebit.persistence.DefaultKeyset)5 KeysetPage (com.blazebit.persistence.KeysetPage)5 Serializable (java.io.Serializable)4 ArrayList (java.util.ArrayList)4 JsonNode (com.fasterxml.jackson.databind.JsonNode)3 IOException (java.io.IOException)3 KeysetPageRequest (com.blazebit.persistence.spring.data.repository.KeysetPageRequest)2 KeysetPageable (com.blazebit.persistence.spring.data.repository.KeysetPageable)2 Method (java.lang.reflect.Method)2 Pageable (org.springframework.data.domain.Pageable)2 PagedArrayList (com.blazebit.persistence.PagedArrayList)1 PagedList (com.blazebit.persistence.PagedList)1 KeysetPageRequest (com.blazebit.persistence.deltaspike.data.KeysetPageRequest)1 PageRequest (com.blazebit.persistence.deltaspike.data.PageRequest)1 Pageable (com.blazebit.persistence.deltaspike.data.Pageable)1 Sort (com.blazebit.persistence.deltaspike.data.Sort)1 CountExtractionObjectBuilder (com.blazebit.persistence.impl.builder.object.CountExtractionObjectBuilder)1 KeysetExtractionObjectBuilder (com.blazebit.persistence.impl.builder.object.KeysetExtractionObjectBuilder)1 KeysetConfig (com.blazebit.persistence.spring.data.webflux.KeysetConfig)1