All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.search.KiwiSearching Maven / Gradle / Ivy

Go to download

Kiwi is a utility library. We really like Google's Guava, and also use Apache Commons. But if they don't have something we need, and we think it is useful, this is where we put it.

There is a newer version: 4.4.0
Show newest version
package org.kiwiproject.search;

import static com.google.common.base.Preconditions.checkArgument;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull;

import lombok.Getter;
import lombok.experimental.UtilityClass;

/**
 * Utilities related to searching and pagination. Supports both zero- and one-based page numbering but the
 * default is one-based. Use the methods that accept
 */
@UtilityClass
public class KiwiSearching {

    /**
     * Enum that represents either zero or one-based page numbering scheme.
     */
    public enum PageNumberingScheme {

        /**
         * Page numbers start at zero.
         */
        ZERO_BASED("pageNumber starts at 0", 0),

        /**
         * Page numbers start at one.
         */
        ONE_BASED("pageNumber starts at 1", 1);

        /**
         * @implNote Allow access through a traditional getter method or via a public field (which is perfectly
         * fine since this is an immutable String.)
         */
        @Getter
        public final String pageNumberError;

        private final int minimumPageNumber;

        PageNumberingScheme(String pageNumberError, int minimumPageNumber) {
            this.pageNumberError = pageNumberError;
            this.minimumPageNumber = minimumPageNumber;
        }

        /**
         * Check the given page number for this scheme's minimum page number.
         *
         * @param pageNumber the page number to check
         * @throws IllegalArgumentException if the given page number is not valid
         */
        public void checkPageNumber(int pageNumber) {
            checkArgument(pageNumber >= minimumPageNumber, pageNumberError);
        }
    }

    /**
     * A rather opinionated value for the default page size.
     */
    public static final int DEFAULT_PAGE_SIZE = 25;

    /**
     * The rather opinionated value for default page size as a String, in order to support web framework annotations
     * like JAX-RS's {@code javax.ws.rs.DefaultValue} that require a String.
     *
     * @implNote This must be a constant not an expression, otherwise trying to use it in an annotation like
     * the JAX-RS {@code DefaultValue} will result in a compilation error due to the vagaries of Java annotations.
     * For example, trying to do this:
     * {@code DEFAULT_PAGE_SIZE_AS_STRING = String.valueOf(DEFAULT_PAGE_SIZE)}
     * and then using in an annotation like this:
     * {@code @DefaultValue(DEFAULT_PAGE_SIZE_AS_STRING)}
     * will result in the following compiler error: "java: element value must be a constant expression"
     */
    public static final String DEFAULT_PAGE_SIZE_AS_STRING = "25";

    public static final String PAGE_SIZE_ERROR = "pageSize must be at least 1";

    /**
     * Validate that the given page size is greater than zero.
     *
     * @param pageSize the page size to check
     */
    public static void checkPageSize(int pageSize) {
        checkArgument(pageSize > 0, PAGE_SIZE_ERROR);
    }

    /**
     * Validate the given page number is greater than zero. This uses one-based page numbering.
     *
     * @param pageNumber the page number to check
     * @throws IllegalArgumentException if the page number is not greater than zero
     * @see #checkPageNumber(int, PageNumberingScheme)
     * @see PageNumberingScheme#ONE_BASED
     */
    public static void checkPageNumber(int pageNumber) {
        PageNumberingScheme.ONE_BASED.checkPageNumber(pageNumber);
    }

    /**
     * Validate the given page number is equal to or greater than the minimum for the given {@link PageNumberingScheme}.
     *
     * @param pageNumber      the page number to check
     * @param numberingScheme the page numbering scheme to use
     * @throws IllegalArgumentException if the page number is invalid according to the numbering scheme
     * @see PageNumberingScheme
     */
    public static void checkPageNumber(int pageNumber, PageNumberingScheme numberingScheme) {
        checkArgumentNotNull(numberingScheme);
        numberingScheme.checkPageNumber(pageNumber);
    }

    /**
     * Calculate the zero-based offset for the given page number and size using page numbers starting
     * at one, after first validating the page number and size. Useful for any data access library that requires a
     * zero-based offset.
     * 

* This uses one-based page numbering. * * @param pageNumber the page number (one-based) * @param pageSize the page size * @return the zero-based offset, e.g. for use in SQL queries using OFFSET and LIMIT * @throws IllegalArgumentException if the page number or size is invalid * @see PageNumberingScheme#ONE_BASED * @see #zeroBasedOffset(int, PageNumberingScheme, int) */ public static int zeroBasedOffset(int pageNumber, int pageSize) { return zeroBasedOffset(pageNumber, PageNumberingScheme.ONE_BASED, pageSize); } /** * Calculate the zero-based offset for the given page number and size using the given page numbering * scheme, after first validating the page number and size. Useful for any data access library that requires * a zero-based offset. * * @param pageNumber the page number * @param numberingScheme the page numbering scheme to use * @param pageSize the page size * @return the zero-based offset, e.g. for use in SQL queries using OFFSET and LIMIT * @throws IllegalArgumentException if the page number or size is invalid * @see PageNumberingScheme */ public static int zeroBasedOffset(int pageNumber, PageNumberingScheme numberingScheme, int pageSize) { checkPageNumber(pageNumber, numberingScheme); checkPageSize(pageSize); return (pageNumber - numberingScheme.minimumPageNumber) * pageSize; } /** * Calculate the number of pages necessary to paginate the given number of results using the given page size. * * @param resultCount the total number of results to paginate * @param pageSize the size of each page * @return the number of pages * @throws IllegalArgumentException if the page size is invalid */ public static int numberOfPages(long resultCount, int pageSize) { checkPageSize(pageSize); return (int) (resultCount / pageSize) + (resultCount % pageSize > 0 ? 1 : 0); } /** * Calculate the number of results on the given page number for the given number of results and page size. * This uses one-based page numbering. * * @param resultCount the total number of results to paginate * @param pageSize the size of each page * @param pageNumber the page number * @return the number of results on the given page * @throws IllegalArgumentException if page number or size is invalid * @see PageNumberingScheme#ONE_BASED * @see #numberOnPage(long, int, int, PageNumberingScheme) */ public static int numberOnPage(long resultCount, int pageSize, int pageNumber) { return numberOnPage(resultCount, pageSize, pageNumber, PageNumberingScheme.ONE_BASED); } /** * Calculate the number of results on the given page number for the given number of results and page size, and * using the given {@link PageNumberingScheme}. * * @param resultCount the total number of results to paginate * @param pageSize the size of each page * @param pageNumber the page number * @param numberingScheme the page numbering scheme to use * @return the number of results on the given page * @throws IllegalArgumentException if page number or size is invalid * @see PageNumberingScheme */ public static int numberOnPage(long resultCount, int pageSize, int pageNumber, PageNumberingScheme numberingScheme) { checkPageNumber(pageNumber, numberingScheme); checkPageSize(pageSize); if (resultCount == 0) { return 0; } var numPages = numberOfPages(resultCount, pageSize); var schemePageNumber = (numberingScheme == PageNumberingScheme.ONE_BASED) ? pageNumber : pageNumber + 1; if (schemePageNumber > numPages) { return 0; } if (schemePageNumber == numPages) { long remainder = resultCount % pageSize; return remainder == 0 ? pageSize : (int) remainder; } return pageSize; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy