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.