Skip to content

[Use Case]: JDQL fragments #546

@gavinking

Description

@gavinking

As a ...

  • Application user/user of the configuration itself
  • API user (application developer)
  • SPI user (container or runtime developer)
  • Specification implementer

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:

  • the nature of the@By annotation,
  • the potential for us to grow a whole zoo of similar animals in future (@Like, @IgnoreCase, @In, etc), and
  • also about my unexpected happiness with how well @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:

@Find 
@OrderBy("lower(title) desc")
@OrderBy("isbn")
List<Book> booksByTitle(Type type, @Where("title like :pattern") String pattern);

which would be assembled to:

@Query("where title like :pattern and type = :type order by lower(title) desc, isbn")
List<Book> booksByTitle(Type type, String pattern);

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:

@Find 
@OrderBy("lower(title) desc, isbn")
List<Book> booksByTitle(Type type, @By("title like :pattern") String pattern);

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 accepting scalar_expression,
  • @OrderBy accepting orderby_item or perhaps a whole list of them,
  • @Where accepting conditional_expression except for logical operators, and
  • possibly @Select accepting select_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions