Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 51 additions & 7 deletions api/src/main/java/jakarta/data/Limit.java
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;

/**
* <p>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.</p>
* limited to
* <ul>
* <li>a {@linkplain #of(int) maximum number of results},</li>
* <li>a {@linkplain #of(int, long) maximum number of results relative to an
* offset}, or</li>
* <li>a {@linkplain #range(long, long) positioned range} defined in terms of
* a starting position and an ending position.</li>
* </ul></p>
*
* <p>A query method of a repository may have a parameter of type
* {@code Limit} if its return type indicates that it may return multiple
Expand Down Expand Up @@ -104,10 +112,15 @@ public int maxResults() {
// Override to provide method documentation:

/**
* <p>Offset at which to start when returning query results.
* The first query result is position {@code 1}.</p>
* <p>The position at which to start when returning query results.</p>
* <p>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.</p>
*
* @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;
Expand All @@ -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.
* <p>
* 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);
}

/**
* <p>Create a limit that restricts the results to a range,
* beginning with the {@code startAt} position and ending after the
Expand Down
50 changes: 46 additions & 4 deletions api/src/main/java/jakarta/data/page/PageRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 <em>numbers</em> are indexed from one;
* page {@linkplain #pageOffset offsets} are indexed from zero.
*/
long page();

Expand Down Expand Up @@ -259,16 +262,55 @@ static PageRequest beforeCursor(Cursor cursor, long pageNumber, int maxPageSize,
boolean requestTotal();

/**
* <p>Creates a new page request with the same pagination information,
* but with the specified page number.</p>
* 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 <em>numbers</em> 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}.
* <p>
* 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 <em>offsets</em> 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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this one here.

  1. the Long.MAX_VALUE still a valid number right?

Why is this not supported?

Copy link
Copy Markdown
Member Author

@njr-11 njr-11 Jun 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. the Long.MAX_VALUE still a valid number right?

Why is this not supported?

Of course it's a valid number. But an offset of Long.MAX_VALUE from the first result has a page number (Long.MAX_VALUE + 1) that is not representable as a positive long value. If we allowed it, what would you propose to return when a user/Data provider asks the API for the page number?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10^19 is an implausible number of rows.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, that's precisely how many rows I have. Make it work.

throw new IllegalArgumentException(
Messages.get("013.arg.invalid", "offset", offset));
}

return page(offset + 1);
}

/**
* <p>Creates a new page request with the same pagination information,
* but with the specified maximum page size. When a page is retrieved from
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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}