11.9. Single-String JDOQL

It is often convenient to represent an entire JDOQL query as a single string. JDO defines a single-string query form that encompasses all parts of a query: the unique flag, result string, result class, filter, parameters, variables, imports, grouping, ordering, and range.

[Note]Note

Single-string JDOQL is new in JDO 2. Its format is subject to change prior to the final JDO 2 specification. In addition to standard single-string JDOQL support, Kodo uses the single-string format to implement JDOQL subquery support, covered in Section 13.3, “JDOQL Subqueries”.

We present the grammar for single-string JDOQL queries below. Clauses in square brackets are optional. Clauses in angle brackets are required, and represent portions of the Query API.

select [unique] [<result>] [into <result class>]
    [from <candidate class> [exclude subclasses]]
    [where <filter>]
    [with [parameters <parameter declarations>]
          [variables <variable declarations>]
          [imports <import declarations>]]
    [group by <grouping>]
    [order by <ordering>]
    [range <start> [to <end>]]

The PersistenceManager has a factory method designed specifically for constructing a query from a single argument (in this case, a JDOQL string):

public Query newQuery (Object query);

In each code block below, we create and execute a standard JDOQL query, then demonstrate the same process using the single-string format. As you'll see, translating any query into single-string form is just a matter of plugging the corresponding strings into the grammar above.

Query query = pm.newQuery ();
query.setResult ("distinct title");
query.setClass (Magazine.class);
query.setFilter ("price < :p");
query.setRange (10, 20);
Collection results = (Collection) query.execute (new Double (10.0));

Query query = pm.newQuery ("select distinct title from org.mag.Magazine "
    + "where price < :p range 10 to 20");
Collection results = (Collection) query.execute (new Double (10.0));
Query query = pm.newQuery ();
query.setUnique (true);
query.setCandidates (pm.getExtent (Magazine.class, false));
query.setFilter ("title == 'JDJ'");
Magazine mag = (Magazine) query.execute ();

Query query = pm.newQuery ("select unique from org.mag.Magazine "
    + "exclude subclasses where title == 'JDJ'");
Magazine mag = (Magazine) query.execute ();
Query query = pm.newQuery ();
query.setResult ("publisher.name as pub, avg(price) as price");
query.setResultClass (org.mag.pub.PubPrice.class);
query.setClass (Magazine.class);
query.setGrouping ("publisher having avg(price) < :p");
query.setOrdering ("publisher.name ascending");
Collection results = (Collection) query.execute (new Double (10.0));

Query query = pm.newQuery ("select publisher.name as pub, avg(price) as price "
    + "into org.mag.pub.PubPrice from org.mag.Magazine "
    + "group by publisher having avg(price) < :p "
    + "order by publisher.name ascending");
Collection results = (Collection) query.execute (new Double (10.0));

On a final note, single-string queries are mutable. You can construct a single-string query as in the examples above, then change the result string, filter, or any other part of the query through the standard Query APIs. This is especially useful for temporary properties like the result range.