Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some PageRequest params for query beans #3462

Closed
artemik opened this issue Aug 26, 2024 · 1 comment · Fixed by #3478
Closed

Add some PageRequest params for query beans #3462

artemik opened this issue Aug 26, 2024 · 1 comment · Fixed by #3478
Assignees
Milestone

Comments

@artemik
Copy link

artemik commented Aug 26, 2024

Feature Request

Would be nice to have some function on query beans allowing to pass some sort of paging params (like PageRequest in Spring Boot Data for Ebean to apply paging params in a consistent way:

var paging = ...
paging.pageNumber = 1;
paging.pageSize = 20;

new QOrder()
    ...
    .findPagedList(paging);

It should also support some "unpaged" flag, so that all entities are pulled. And could also probably support ordering params (again like in Spring Boot Data).

Current Workaround

Currently users have to manually and separately call these functions:

  • setMaxRows()
  • setFirstRow()

Why

Without it, it's not convenient and error prone.

Many UIs in a project would share functionality of showing paged lists of various entities. Would be great if there would be a consistent way to maintain paging params for all of them.

Currently, if users want consistency, they have to come up with their own paging params implementation of some sort:

if (pageRequest.unpaged) {
    queryBean.setMaxRows(Integer.MAX_VALUE);
    queryBean.setFirstRow(0);
} else {
    queryBean.setMaxRows(pageRequest.size);
    queryBean.setFirstRow(pageRequest.pageIndex * pageRequest.size);
}

I saw an Ebean issue where it mentioned that pageIndex and pageSize pair is not enough to cover some cases, then there could be some additional methods or some other thinking around that, but at least simple paging mechanism itself very much makes sense to exist (from that issue it also seems Ebean earlier supported paging, where has it gone?).

@rbygrave
Copy link
Member

Proposed API:

package io.ebean;

import io.avaje.lang.Nullable;

public interface Paging {

  /**
   * Create a Paging with the given page index size and orderBy.
   *
   * @param pageIndex the page index starting from zero
   * @param pageSize  the page size (effectively max rows)
   * @param orderBy   order by for the query result
   */
  static Paging of(int pageIndex, int pageSize, @Nullable OrderBy<?> orderBy) {
    return DPaging.build(pageIndex, pageSize, orderBy);
  }

  /**
   * Create a Paging with a raw order by clause.
   *
   * @param pageIndex     the page index starting from zero
   * @param pageSize      the page size (effectively max rows)
   * @param orderByClause raw order by clause for ordering the query result
   */
  static Paging of(int pageIndex, int pageSize, @Nullable String orderByClause) {
    return of(pageIndex, pageSize, OrderBy.of(orderByClause));
  }

  /**
   * Create a Paging that will use the id property for ordering.
   *
   * @param pageIndex the page index starting from zero
   * @param pageSize  the page size (effectively max rows)
   */
  static Paging of(int pageIndex, int pageSize) {
    return DPaging.build(pageIndex, pageSize);
  }

  /**
   * Return a Paging that will not apply any pagination to a query.
   */
  static Paging ofNone() {
    return DPaging.NONE;
  }

  /**
   * Return the page index.
   */
  int pageIndex();

  /**
   * Return the page size.
   */
  int pageSize();

  /**
   * Return the order by.
   */
  OrderBy<?> orderBy();

  /**
   * Return a Paging using the given page index.
   */
  Paging withPage(int pageIndex);

  /**
   * Return a Paging using the given order by clause.
   */
  Paging withOrderBy(String orderByClause);

}

Example use:

  @Test
  void example() {
    var orderBy = OrderBy.of("lastName desc nulls first, firstName asc");
    var paging = Paging.of(0, 100, orderBy);

    DB.find(Contact.class)
      .setPaging(paging)
      .findList();
    // or instead of findList() use another find method like ...
    // findPagedList(), findEach(), findStream(), findMap(), findSet(), findSingleAttributeList(),
    
    var nextPage = paging.withPage(1);

    DB.find(Contact.class)
      .setPaging(nextPage)
      .findList();
  }

The logic in DefaultOrmQuery:

  @Override
  @SuppressWarnings("unchecked")
  public Query<T> setPaging(@Nullable Paging paging) {
    if (paging != null && paging.pageSize() > 0) {
      firstRow = paging.pageIndex() * paging.pageSize();
      maxRows = paging.pageSize();
      orderBy = (OrderBy<T>) paging.orderBy();
      if (orderBy == null || orderBy.isEmpty()) {
        // should not be paging without any order by clause so set
        // orderById such that the Id property is used
        orderById = true;
      }
    }
    return this;
  }

rbygrave added a commit that referenced this issue Sep 12, 2024
Paging is an alternative to specifying the maxRows + firstRow + orderBy on a query.

Example:
```java

    var orderBy = OrderBy.of("lastName desc nulls first, firstName asc");
    var paging = Paging.of(0, 100, orderBy);

    DB.find(Contact.class)
      .setPaging(paging)
      .where().startsWith("lastName", "foo")
      .findList();
```
rbygrave added a commit that referenced this issue Sep 17, 2024
#3462 Add Paging as alternative to maxRows + firstRow + orderBy
@rbygrave rbygrave added this to the 15.6.0 milestone Sep 17, 2024
@rbygrave rbygrave self-assigned this Sep 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants
@rbygrave @artemik and others