This class will parse a query method's name and extract a
query description from that name.
In parsing the name, words are considered as being tokens in a camel case name.
Here is how a query method's name is parsed:
- We will look at the first word in the name until we reach one of the keywords that says we
are specifying a limit, or we are going over the criteria defined by the method. This
prefix will be called the "function name" for the operation defined by the query method. If
the function name is one of "read", "find", "query", "get", "load", or "select", we will
set the function name to null to indicate that no special function should be
applied to the result set. We are only looking at the first word to let you be more verbose
about the purpose of your query (e.g. findAllGreatPeopleByGreatnessGreaterThan(Integer greatness) will still resolve to the
function find, which will ultimately be returned as null
- We will then look for any of these patterns:
- The word By, signifying that we are ready to start parsing the query
criteria
- One of the words First or Top, signifying that we should look
for a limit on the number of results returned.
- The word Distinct, signifying that the results should include no
duplicates.
- If the word First had appeared, we will see if it is followed by an integer. If
it is, that will be the limit. If not, a limit of 1 is assumed.
- If the word Top had appeared, we will look for the limit number, which should be
an integer value.
- At this point, we will continue until we see 'By'. In the above, steps, we will look for
the keywords in any order, and there can be any words in between. So, getTop5StudentsWhoAreAwesomeDistinct is the same as getTop5Distinct
- Once we reach the word "By", we will read the query in terms of "decision branches".
Branches are separated using the keyword "Or", and each branch is a series of conjunctions.
So, while you are separating your conditions with "And", you are in the same branch.
- A single branch consists of the pattern:
"(Property)(Operator)?((And)(Property)(Operator)?)*". If the operator is missing, "Is" is
assumed. Properties must match a proper property in the domain object. So, if you have
"AddressZipPrefix" in your query method name, there must be a property reachable by one of
the following paths in your domain class (in the given order):
- addressZipPrefix
- addressZip.prefix
- address.zipPrefix
- address.zip.prefix
Note that if you have both the "addressZip" and "address.zip" in your entity, the first
will be taken up. To force the parser to choose the former, use the underscore character
(_) in place of the dot, like so: "Address_Zip"
Depending on the operator that was matched to the suffix provided (e.g. GreaterThan, Is,
etc.), a given number of method parameters will be matched as the operands to that
operator. For instance, "Is" requires two values to determine equality, one if the property
found on the domain object, and the other must be provided by the query method.
The operators themselves are scanned eagerly and based on the set of operators defined in
the OperatorContext.
- We continue the pattern indicated above, until we reach the end of the method name, or we
reach the "OrderBy" pattern. Once we see "OrderBy" we expect the following pattern:
"((Property)(Direction))+", wherein "Property" must follow the same rule as above, and
"Direction" is one of "Asc" and "Desc" to indicate "ascending" and "descending" ordering,
respectively.
- Finally, we look to see if the keyword "AllIgnoreCase" or
one of its variations is present at the end of the query name, which will indicate all
applicable comparisons should be case-insensitive.
- At the end, we allow one additional parameter for the query method, which can be of either
of these types:
Sort: to indicate a dynamic sort defined at runtime. If a static sort is
already indicated via the pattern above, this will result in an error.
Pageable: to indicate a paging (and, possibly, sorting) at runtime.
If a static sort is already indicated via the pattern above, the sort portion of this
parameter will be always ignored.