-
Notifications
You must be signed in to change notification settings - Fork 30
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
[Use Case]: JDQL fragments #546
Comments
JDQL query fragments are something we can consider in the future. They address a very different use case than,
The use case for query fragments is similar to The use case for making parameter-based automatic query methods on par with Query by Method Name trades off the ability to have more complex queries for the ability to perform basic operations relying purely on API and API JavaDoc without needing to learn any query language or needing to specify string values that are vulnerable to spelling and other errors. Another way of having JDQL query fragments might be to include then in the @Query(where = "title like :pattern and type = :type",
orderBy = "lower(title) desc, isbn")
List<Book> booksByTitle(Type type, String pattern); Similarly, having what you refer to as an annotation zoo isn't the only option for the annotative pattern. Another option is for a single annotation, such as @By(_Product.name) @Is(Like) String pattern,
@By(_Product.category) @Is(In) List<Category> categories, |
I mean, that really depends. In my implementation the tradeoff between Now, OK, that requires some fairly serious machinery, which I spent some time developing a few years ago, and so I just happened to have it lying around when Jakarta Data came along. And so not all implementations are going to have that. Fine. But for simpler cases like That is to say, Now, I'm not suggesting we can't have
Well that wouldn't let me mix JDQL fragments into a What I'm looking for is the ability to mix bits of JDQL into a
This isn't awful; I quite like it, actually. Nice idea! But on the other hand it sorta undermines the main value of @By("name like :pattern") String pattern,
@By("category in :categories") List<Category> categories, So, y'know, I'm just not sure I'm sold on the idea of implementing an expression language in annotations. |
So I've spent some more time reflecting on this last night and this morning, going back to first principles of what I originally liked about the When I first implemented I was pretty sure I didn't want to try implementing a whole expression language in annotations. I didn't and still don't want to open the door to the whole open-ended hog of On the other hand, it was also pretty clear early on that there was going to be lots of pressure to handle pattern matching (i.e. But now after a lot of reflection on this, I've realized that there's a perfectly reasonable "ideology" which lets me address those two cases without opening any doors I don't want to open. It's this: @Find
Book[] booksByIsbn(String[] isbn);
@Find
List<Book> booksByTitle(@Pattern String title); Notice that there are no "operators" here. In the first case, the type alone requires that this be interpreted as an And that's consistent with the original philosophy that So what happens if I do need @Find @Where("deleted = false")
Book[] booksByIsbn(String[] isbn);
@Find @Where("deleted = false")
@OrderBy("lower(title), isbn desc")
List<Book> longBooks(@By("pages > ?1") int minPages,
@By("left(locale, 2) = lower(?2)") String language
@Pattern String topic) That is to say, we can express things which will just never be elegant or even possible using "operator annotations". Now, are these examples obviously better than just writing: @Query("where deleted = false and isbn in ?1")
Book[] booksByIsbn(String[] isbn);
@Query("where pages > ?1 and left(locale, 2) = lower(?2) and topic like ?3"
+ " and deleted = false"
+ " order by title, isbn desc")
List<Book> longBooks(int minPages,
String language
String topic) I dunno, I think you could argue that they are slight better, though it's clearly a matter of taste. But what I like above all else is that it unifies I understand that this looks superficially less typesafe than the "operator annotations". But what I've seen is that it really doesn't need to be. It really is quite straightforward to typecheck these kinds of fragments in an annotation processor. I have been taken a bit by surprise by how well this approach works in practice. On the other hand, if you're lucky enough to have IntelliJ Ultimate, IntelliJ now does a fantastic job of highlighting/validating/autocompleting JPQL embedded in annotations. Of course, IntelliJ doesn't understand the Jakarta Data annotations yet, it only understands the similar annotations in Hibernate. But the guys working on this stuff have been extremely responsive to my requests in this area, so I expect they'll jump on Jakarta Data. They already have the machinery they need. I also understand that the reasoning here is maybe a bit hard to digest at first. I'm not suggesting that there's something deeply broken about |
As a ...
I need to be able to ...
specify JDQL expressions or fragments of JDQL in annotations.
Which enables me to ...
reduce the cognitive dissonance in moving between
@Find
and@Query
.Additional information
So in thinking through:
@By
annotation,@Like
,@IgnoreCase
,@In
, etc), and@OrderBy("name")
works, and unhappiness with how ugly@OrderBy(vale="name",descending=true,ignoreCase=true)
looks.I came to the realization that there's a general approach that makes
@Find
much more flexible, reduces the conceptual gap between@Find
and@Query
, solves the problem with@OrderBy
, and makes the trip to the zoo unnecessary.[Don't get scared. I'm not proposing to do any of this today, I'm just trying to understand what the future might look like.]
The idea is to have a smaller set of annotations which accept fragments of JDQL. So, for example:
which would be assembled to:
You might even be able subsume
@Where
into@By
, since it's pretty easy to distinguish a scalar expression with no parameters from a conditional expression with a parameter. And you might allow@OrderBy
to accept a list. So:Now, one might look at this particular example, and think "but the
@Query
version is shorter and perhaps even more readable", and that's true because this is a sort-of "extreme" case in the sense that I have three annotations and only two parameters. But if I had four parameters and just one or two annotations, it would look more attractive.But that's anyway not the point. The point is to reduce the pressure to add lots of special-purpose annotations, and save the developer from getting into the sort of edit war where they find themselves switching back and forth between
@Find
and@Query
.To reiterate:
@Where("title like :pattern")
is more verbose than@Like
. But it covers many more cases and is somehow, at least to my way of thinking, a much more elegant approach.Note that the content of these annotations can still be checked at compile time. JDQL has a very a simple expression language that's easy to parse in an annotation processor.
So we would have:
@By
acceptingscalar_expression
,@OrderBy
acceptingorderby_item
or perhaps a whole list of them,@Where
acceptingconditional_expression
except for logical operators, and@Select
acceptingselect_list
or perhaps just a single select item.By side effect,
@By("id(this)")
becomes the much more elegant way to write@By(ID)
.Everything here looks backward-compatible with what we have today! That said, we could consider adopting this approach for
@OrderBy
in this release, if we have time. But it's definitely not critical.The text was updated successfully, but these errors were encountered: