diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java index 39e9fafbf..bbcc9a948 100644 --- a/api/src/main/java/jakarta/data/Limit.java +++ b/api/src/main/java/jakarta/data/Limit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022,2024 Contributors to the Eclipse Foundation + * Copyright (c) 2022,2026 Contributors to the Eclipse Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,22 @@ */ package jakarta.data; +import jakarta.data.messages.Messages; import jakarta.data.page.PageRequest; +import jakarta.data.repository.Find; +import jakarta.data.repository.Query; /** *
Specifies a limit on the number of results retrieved by a repository * method. The results of a single invocation of a repository method may be - * limited to a given {@linkplain #of(int) maximum number of results} or to a - * given {@linkplain #range(long, long) positioned range} defined in terms of an - * offset and maximum number of results.
+ * limited to + *A query method of a repository may have a parameter of type * {@code Limit} if its return type indicates that it may return multiple @@ -104,10 +112,15 @@ public int maxResults() { // Override to provide method documentation: /** - *
Offset at which to start when returning query results. - * The first query result is position {@code 1}.
+ *The position at which to start when returning query results.
+ *The first query result is at position {@code 1}. If the start position + * is greater than one, some results at the beginning of the result set + * are skipped.
+ * + * @return position of the first result. * - * @return offset of the first result. + * @apiNote Positions are indexed from one; + * offsets are indexed from zero. */ public long startAt() { return startAt; @@ -126,6 +139,37 @@ public static Limit of(int maxResults) { return new Limit(maxResults, DEFAULT_START_AT); } + /** + * Create a limit that caps the number of results at the given maximum, + * starting at the given {@code offset} from the first result. + *+ * An {@code offset} of zero includes the first result. A positive + * {@code offset} skips the respective number of results. + * + * @param maxResults maximum number of results + * @param offset offset at which to start + * @return limit that can be supplied to a {@link Find} method or + * {@link Query} method that performs a find operation; + * will never be {@code null} + * @throws IllegalArgumentException if {@code maxResults} or + * {@code offset} is negative or the {@code offset} is + * {@link Long#MAX_VALUE} + * @since 1.1 + */ + public static Limit of(int maxResults, long offset) { + if (offset < 0) { + throw new IllegalArgumentException( + Messages.get("004.arg.negative", "offset")); + } + + if (offset == Long.MAX_VALUE) { + throw new IllegalArgumentException( + Messages.get("013.arg.invalid", "offset", offset)); + } + + return new Limit(maxResults, offset + 1); + } + /** *
Create a limit that restricts the results to a range, * beginning with the {@code startAt} position and ending after the diff --git a/api/src/main/java/jakarta/data/page/PageRequest.java b/api/src/main/java/jakarta/data/page/PageRequest.java index 10fe0313a..054f0ce41 100644 --- a/api/src/main/java/jakarta/data/page/PageRequest.java +++ b/api/src/main/java/jakarta/data/page/PageRequest.java @@ -20,6 +20,7 @@ import jakarta.data.Limit; import jakarta.data.Order; import jakarta.data.Sort; +import jakarta.data.messages.Messages; import jakarta.data.repository.First; import jakarta.data.repository.OrderBy; @@ -223,9 +224,11 @@ static PageRequest beforeCursor(Cursor cursor, long pageNumber, int maxPageSize, Mode mode(); /** - * Returns the page to be returned. + * Returns the requested page number. Page numbers begin with {@code 1}. * - * @return the page to be returned. + * @return the requested page number + * @apiNote Page numbers are indexed from one; + * page {@linkplain #pageOffset offsets} are indexed from zero. */ long page(); @@ -259,16 +262,55 @@ static PageRequest beforeCursor(Cursor cursor, long pageNumber, int maxPageSize, boolean requestTotal(); /** - *
Creates a new page request with the same pagination information, - * but with the specified page number.
+ * Creates a new page request with the same pagination information, + * but with the specified page number. The first page number is {@code 1}. * * @param pageNumber the page number. * @return a new instance of {@code PageRequest}. This method never returns * {@code null}. * @since 1.1 + * @apiNote Page numbers are indexed from one; + * page {@linkplain #pageOffset offsets} are indexed from zero. */ PageRequest page(long pageNumber); + /** + * Creates a new page request with the same pagination information, + * but with the given {@code offset}. + *+ * The offset is relative to the first page. An offset of {@code 0} + * requests the first page, and an offset of {@code 1} requests the + * second page. + * + * @return the offset of the requested page + * @throws IllegalStateException if the {@link #mode()} is not + * {@link Mode#OFFSET} + * @throws IllegalArgumentException if the {@code offset} is negative + * or {@link Long#MAX_VALUE} + * @since 1.1 + * + * @apiNote Page offsets are indexed from zero; + * page {@linkplain #page numbers} are indexed from one. + */ + default PageRequest pageOffset(long offset) { + if (mode() != Mode.OFFSET) { + throw new IllegalStateException( + Messages.get("014.mode.disallows.offset", mode())); + } + + if (offset < 0) { + throw new IllegalArgumentException( + Messages.get("004.arg.negative", "offset")); + } + + if (offset == Long.MAX_VALUE) { + throw new IllegalArgumentException( + Messages.get("013.arg.invalid", "offset", offset)); + } + + return page(offset + 1); + } + /** *
Creates a new page request with the same pagination information, * but with the specified maximum page size. When a page is retrieved from diff --git a/api/src/main/resources/jakarta/data/messages/DataMessages.properties b/api/src/main/resources/jakarta/data/messages/DataMessages.properties index bc276eb83..b7a2157e9 100644 --- a/api/src/main/resources/jakarta/data/messages/DataMessages.properties +++ b/api/src/main/resources/jakarta/data/messages/DataMessages.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2025 Contributors to the Eclipse Foundation +# Copyright (c) 2025,2026 Contributors to the Eclipse Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -35,3 +35,6 @@ identify the entity class that declares the attribute. For static metamodel \ classes, use an .of method that is defined on an Attribute subtype to supply \ the entity class and entity attribute type. +013.arg.invalid=The {0} argument cannot be {1} +014.mode.disallows.offset=A page cannot be requested to have an offset \ + and a mode of {0}