Package ch.tocco.nice2.persist.core.api.query
The Query Language
In order to be able to query entities based on arbitrary search criteria independently from the storage backend, the persistence layer defines its own query language.
To build queries in code please refer to the interface
QueryBuilder
There are three basic forms of queries:
* Query for all: find MyEntity Note that named queries are currently not implemented and probably never will be. We found that [functions](#functions) are just fine. * Find by criteria: find MyEntity where someField == 23 or someRelation.anotherField == 42The two first forms should be self-explanatory, so the following describes the last form only.
Query Syntax
Keywords
The following words are keywords:find
, where
, and
,
or
, not
, null
, true
, false
, exists
, secure
,
insecure
.
There are some more keywords which are reserved for possible future extensions:
keys
, in
, exists
.
Identifiers
Any word that follows the usual Java identifier constraints and isn't a keyword is an identifier. If an identifier matches a keyword (e.g. a field called "exists") or doesn't match the identifier constraints may be enclosed in single quotes. For example,
find MyEntity where where == "Some Location" or my field > 42
would result in syntax errors: The second <<<where>>>
is not allowed here, neither
is field
after my
. To get around this problem, you may write:
find MyEntity where 'where' == "Some Location" or 'my field' > 24
Quoted identifiers may contain any characters you like. Also, all Java escape
sequences are supported.
A special form of identifiers are paths, which are used to follow relations:
find Person where city.country.isoCode == "CH"Find all persons living in a city located in Switzerland. The quoted form of this would be:
find 'Person' where 'city'.'country'.'isoCode' == "CH"
Literals
You've already seen two kinds of literals: Integer literals and string literals. Like in quoted identifiers, all Java escape sequences are supported within string literals. Integer literals also follow the Java conventions, i.e.<<<0xa>>>
is the
hex number A, 03 is the octal number 3.
Floating point literals are also supported and follow the same rules as in Java.
Other supported literals are the boolean literals true
and false
, and the
literal for null: null
.
Finally, there are special literals for non-builtin types. These take the form
type:'value' Some examples:Time values may also contain seconds (13:30:15) or milliseconds (12:30:15.250).decimal:"12345"
: A big decimal.date:"2009-01-23"
: A date.time:"12:30"
: A time.datetime:"2009-01-23 12:30"
: Date and time.
Parameters
Parameters have the form:myParameter
. The values can be injected into a query
using the (compiled) query's
Query.setParameter(String, Object)
setParameter()} method.
The where
Clause
The where
clause specifies the actual search criteria and conjunctions. The
conjunctions are the usual ones, or
, and
and not
, their precedence
as listed, i.e.
A and B or not C and D can also be written as (A and B) or ((not C) and D)The actual criteria are boolean expressions. The following operators are available:
==
, !=
, >
, >=
, <
, <=
and ~=
. ~=
is similar to the LIKE
operator
in SQL and supported for string fields only.
The supported wildcard characters are the asterisk * (for SQL %
, zero to any
characters) and the questionmark ?
(exactly one character, most probably depends
on the character set in use (db table or connection) for what the boundaries of
"one character" are).
Do not use the %
and _
wildcards in the QL; they work at the moment because they
are transparently passed on to sql, but may be subject to escaping in the future.
As of now it is not possible to escape the wildcard characters. If really required then it can be implemented.
The non-existent limit
Clause
In SQL there is various non-standard offset and limit syntax. In nice2 the limit
parameters must be specified when executing the query:
Query.execute(int limit)
The order by
Clause
In SQL the order by clause is part of the command.
In nice2 it can either be done as in sql, or the ordering can be added to an ordering object.
Example:
Query query = userEntity.getContext().compileQuery("find Interface_language");
Ordering ordering = query.getOrdering();
ordering.append("sorting", Ordering.Direction.ASCENDING);
Assume that if the query contains an order clause, and then later on ordering
is appended using query.getOrdering().append(), that the code just appends, and clear()
also clears the one from the query string.
exists()
and count()
subqueries
Using exists()
you can check for the existence of a specific related entity. The
syntax is as follows:
find MyEntity where exists(myRelation.anotherRelation [where ...])Any paths in the optional where clause will be relative to the target entity.
Functions
A function may be part of a boolean expression but it must contributed to the backend of choice first. If contributed, the function is recognized by the parser and generation of the target language is delegated to the function implementation.A function is used as follows:
functionname ( [param1 [, paramN]] )The function arguments may be a mix of literals, identifiers or parameters.
A simple example that assumes a contributed function of name DISTANCE
:
find Cities where DISTANCE(lat, lng, :lat2, :lng2) < :dist
-
ClassDescriptionThrown when a query written in the nice QL fails to compile.See equivalent JPA lock modes for details.This class specifies the ordering policy of a query.One of ASCENDING, DESCENDINGRepresents an ordering rule.Object which represents the offset and limit of a db query.Configure and execute queries.The execution mode of the query.Compile a query string to an executable query.A class that holds all data required to build a query.A specialised query variant used by the
Entity.resolve(String)
method.Helper class for manually writing SQL queries.