-
Notifications
You must be signed in to change notification settings - Fork 35
Sort with type parameter #432
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
Sort with type parameter #432
Conversation
|
Instead of breaking the whole API, I would create a wrapper of this sort. Also, I would create it as an extension in a vendor first. |
b6f741a to
0c5f575
Compare
The whole reason I am trying this out is because Gavin pointed out that Hibernate already has the ability to parameterize their equivalent of Sort with the entity type. So I want to explore what it would look like in Jakarta Data.
You make that sound so easy, but in practice I do not see how what you suggest is even possible. What the exploration under this pull has already shown is that Sort is tightly coupled to Pageable, and in turn to Slice, and Page, and so forth. I think it was important to illustrate that as we evaluate whether or not it's a good idea. |
Nice, I mean, implementation is based on a Jakarta Data implementation itself. I hope that I can start to help with the static model at the end of February.
It is not trivial, but we can do it with a wrapper, I would start with: interface ParametrizedSorted<T> extends Supplier<Sort>{
}Mainly because we want to use if static model. |
That isn't something I can prototype for you because I don't have an understanding of how that would fit into Pageable and the existing API. If you want to write a pull of your own that illustrates your idea and shows how it fits in, go for it. |
8e3e854 to
d969bab
Compare
|
I'm not sure the type safety in this case is worth it. employees.findByYearHired(2024, Limit.of(5), _Employee.lastName.asc(), _Employee.firstName.asc());Also I didn't even know that this was possible or what the meaning of it is in java: Sorts.<Employee> of(Sort.asc("id"))It seems unreasonable for us to require users to write code this way, and worse if they aren't using an IDE they might not even see the type safety warning until they compile anyway. If we do go down this route, however, I think we need a new name for |
d969bab to
81faaa2
Compare
|
Excellent comments Kyle - thanks!
Good point - I had been wondering if that would be too unfamiliar. I switched the approach to follow the style of providing the class instead: Pageable<Employee> pageRequest = Pageable.of(Employee.class).page(1).size(20).sortBy(
Sort.asc("lastName"),
Sort.asc("firstName"),
Sort.asc("id"));In the above case,
That's another good point: List<Employee> found = findByYearHired(2024, Sorting.by(Sort.asc("lastName"),
Sort.asc("firstName"),
Sort.asc("id")));In the above case, Here are some other examples where the static metamodel is used instead: Pageable<Employee> pageRequest = Sorting.by(_Employee.lastName.asc(),
_Employee.firstName.asc(),
_Employee.id.asc()),
.page(1)
.size(20);
In the above case, this ends up being just as concise as currently, but does involve starting from the `Sorting.by` rather than `Pageable.of...`.
List<Employee> found = findByYearHired(2024, Sorting.by(_Employee.lastName.asc(),
_Employee.firstName.asc(),
_Employee.id.asc()));The above very closely matches the corresponding scenario with string values/constants. |
|
Sorry for not responding sooner. So here's what the API looks like in Hibernate. First, the usage: // finder method
repo.getBooksByTitle("%Hibernate%", desc(Book_.isbn))
// query method returning an entity type
repo.findBooksByTitle("%Hibernate%", first(10), asc(Book_.isbn))
repo.findBooksByTitle("%Hibernate%", first(10), asc(Book_.isbn), desc(Book_.publicationDate))
// query method returning a projection
repo.findBookAttributesByTitle("%Hibernate%", first(10), asc(1), asc(2))where the query methods are declared as follows: @Find
List<Book> getBooksByTitle(String title, Order<Book> ord);
@HQL("where title like :title")
List<Book> findBooksByTitle(String title, Page page, Order<? super Book>... ordering);
@HQL("select title, isbn from Book where title like :title")
List<Object[]> findBookAttributesByTitle(String title, Page page, Order<Object[]>... ordering);A couple of observations:
|
|
[Of course, you're also allowed to write |
|
Oh and if you're concerned about the stupid and useless "heap pollution" warning, this is also allowed: @HQL("where title like ?1")
repo.findBooksByTitle("%Hibernate%", first(10), asList(asc(Book_.isbn), desc(Book_.title)))
List<Book> findBooksByTitle(String title, Page page, List<Order<? super Book>> ordering); |
Thanks for responding. Yes, most of the experimentation I've been doing under this pull is aimed at trying to figure out how to spare customers from that annoying warning and the other warning you get when trying to use the repository method. Your strategy of using @otaviojava @gavinking @KyleAure will it be possible for all of you to make it to the February 7th Jakarta Data meeting so that we can all discuss/decide whether or not to add the type parameter? |
Yep, I agree, they're the same. Another possibility would be to always declare the methods as: @Find
List<Book> getBooksByTitle(String title, Sort<Book> ordering);But let you call it as: getBooksByTitle("Jakarta Data", _Book.isbn.asc())or: getBooksByTitle("Jakarta Data", order(_Book.title.asc(), _Book.isbn.asc()))Where the static method @SafeVarargs
public static <T> Sort<T> order(Sort<T>... orders) {
return .... ;
}That is, it aggregates multiple This is quite clean, it seems to me. |
81faaa2 to
acf86d7
Compare
Signed-off-by: Nathan Rauh <[email protected]>
acf86d7 to
9011d8c
Compare
I have the same concern as well. Anyway, could we at least don't break the whole core code doing it? I mean, why not create an adapter or wrapper to Sort instead of breaking the whole API? Let's create a ParametizedSort interface and go with it. I agree that is not trivial, but it is not that hard. |
My experience of first attempting to make a more isolated change is that I was unable to accomplish it because these interfaces are all tied together. If you have a way to achieve it in a more isolated way, please submit a pull of your own to demonstrate your idea. What is currently under this pull is the best I have to offer. At the next meeting, I would like us all to decide between the approach I have demonstrated under the pull, versus the approach you are suggesting (assuming you can demonstrate it as a complete and working solution), versus not doing anything at all and leaving the specification as is. Or maybe someone else will have other ideas that have not been explored yet. |
IMHO: I like the Parametized approach at static metadata, but it should not break what we have. So if it does not break what we have is a good candidate, otherwise, we should think more. Jakarta Data is not a race to include as much features as possible, thus, it is fine if we don't include at the version 1.0.0 and bring as a best approach. |
|
This pull is ready now. The first commit is the same as what was shown on the Jakarta Data call. The second and third commits include the corresponding updates to the JavaDoc and spec doc. The fourth commit includes the suggestion which Gavin made on the call to add the more concise approach for appending generic sorts to a page request: |
KyleAure
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏🏼 Thanks @njr-11 for putting this all together. Just a few typos and one clarification needed.
|
|
||
| /** | ||
| * <p>Creates a new page request with the same pagination information, | ||
| * appending the specified {@link Sort#ascIgnoreCase(String) case-insensitive ascending sort} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might need to expand on this a bit.
Does ignoring case here mean we ignore the case of the property or the returned results?
- if we call ascIgnoreCase("id") will we find and sort by
id,Id,ID, and/oriD? - if we call ascIgnoreCase("firstName") will we ignore case when sorting strings like (Kacy, Kyle, kim) -> (Kacy, kim, Kyle)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the latter. I was hoping to rely on the link to explain it better. I'll see what else I can add to these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the clarification here:
09dece6
Co-authored-by: Kyle Aure <[email protected]>
Co-authored-by: Kyle Aure <[email protected]>
Co-authored-by: Kyle Aure <[email protected]>
Co-authored-by: Kyle Aure <[email protected]>
Co-authored-by: Kyle Aure <[email protected]>
Co-authored-by: Kyle Aure <[email protected]>
KyleAure
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼 Looks good to me
|
Excellent, this looks great! |
To help evaluate the proposal to have Sort with a type parameter #430, I created this pull to demonstrate what that would look like. As expected, it spills over into Pageable, which is constructed from Sorts, and then to Page and Slice which require a Pageable, although it gets more complicated at this point because Page and Slice might not return the same type (a repository method that is annotated
@Queryand uses query language can return a different type than the entity with the attributes that are the sort criteria), meaning that now Page and Slice methods that return Pageable need a way of returning that Pageable as one for the entity class rather than the result type.To get rid of warnings and avoid the need to suppress them, we need to eliminate usage of variable arguments (...) in a number of places. I first tried replacing that with
Iterable<Sort<MyEntityClass>>, but it wasn't a very distinguishable as a special parameter type, so I added a Sorts class for that purpose. Initially constructing Sort instances with static methods also becomes a bit awkward because the entity class isn't naturally supplied yet, requiring usage likeSort.<MyEntityClass>asc("myAttributeName")or it could have been done asSort.asc(MyEntityClass.class, "myAttributeName")(This pull first went with the former, then switched to a different approach). Using the static metamodel avoids that problem. Preserving the type on Pageable was another problem. I moved where sorts are supplied to a Pageable to the initial static method, from which the entity type is inferred from the Sort instances, and that helps in some cases, but in other cases there is still a need to clarify the type with<MyEntityClass>, which could be annoying to the user. This was later changed to using a separateOrder<MyEntityClass>to collect parameterized sorts and created a parameterized page request from that.