JDO Typesafe Queries : Part 2 – Expressions

Continuing on from the previous post, in order to be able to express components of a query in a Java style we need to represent all fields/properties/parameters/variables as expressions. The type of the field/property/parameter/variable determines its expression type. Let’s take an example


public class Person
{
String firstName;
String lastName;
int age;
Person bestFriend;
}

We need to represent these field types with expressions, so let’s start with

  • StringExpression – for Strings
  • NumericExpression – for int, long, short, double, float, Integer, Long, Short, Double, Float, BigDecimal, BigInteger etc
  • BooleanExpression – for boolean, Boolean
  • ByteExpression – for byte, Byte
  • CharacterExpression – for char, Character
  • DateExpression – for Date-based types
  • ObjectExpression – for other Object-based types where we have no specific handling

Ok, so this is all well and good and we can express firstName as a StringExpression, and similarly age is a NumericExpression. So for that we can do


QPerson person = QPerson.person;
Query q = pm.newTypesafeQuery(person);
Person bob =
q.filter(person.firstName.eq("Bob")).executeUnique();

To represent a persistable field (i.e a 1-1 relation, bestFriend in the above example) we have another expression type PersistableExpression.

“Q” classes

Above you see use of metamodel query classes. We refer to them as “Q” classes currently, but the naming is arbitrary for now. So what does a “Q” class look like ?


public class QPerson implements PersistableExpression
{
public static final QPerson person = new QPerson("person");

public final QPerson bestFriend;
public final NumericExpression age;
public final StringExpression name;

... (implementation of other PersistableExpression methods).
}

So in simple terms, we have a public field for each of the normal fields in Person, but that are of XXXExpression types. So when a user accessed QPerson.person they get the candidate for use in a query. Then they can do “person.name” and this is a StringExpression. The NumericExpressionImpl/StringExpressionImpl are the implementations for the particular provider of this typesafe query (e.g DataNucleus). You also notice above that the bestFriend field is also a QPerson, and hence a PersistableExpression, so we can chain field access as “person.bestFriend.firstName

Methods of field types

Obviously in JDOQL (and Java), we allow some method calls. This is represented here by adding the supported methods to StringExpression, NumericExpression etc. For example StringExpression has a method toUpperCase() to match what Java allows, so we can upgrade the query example to be


QPerson person = QPerson.person;
Query q = pm.newTypesafeQuery(person);
Person bob =
q.filter(person.firstName.toUpperCase().eq("BOB")).executeUnique();

There are still some more challenging areas of the API to work out, but the above is just to give a further taster and provoke comment.

Please refer to the current javadocs here (Work-in-progress).

Advertisements
This entry was posted in JDO, JDOQL, Persistence. Bookmark the permalink.

11 Responses to JDO Typesafe Queries : Part 2 – Expressions

  1. Some comments

    * ComparableExpression for literal types which are comparable (as supertype for String,Number,Boolean etc.?)

    * new NumericExpressionImpl(this,”age”); ?!?, otherwise you lose the parent reference

    * You have lots of comparison methods in Expression. Entity expressions will not support them, so maybe push the down to a ComparableExpression?

    * Same thing with numeric methods in Expression. They belong to NumericExpression

    * with DateExpression you bind the expression type to java.util.Date. DataNucleus doesn't support the JodaTime API?

    Like

  2. andy says:

    Having < , >, < =, >= on an intermediate interface is fine, but don't think I'd call it “ComparableExpression” since ==, != are also comparison operations and they aren't included. But that's just naming …

    NumericExpressionImpl is an implementation detail, so not part of any interface and not a concern here.

    As DateExpression javadoc says, 'consider splitting it into something more generic'. JodaTime is one consideration, but it is non-standard (though supported by DN). Also we have javax.time as a consideration (also supported by DN, and in the future likely also by JDO). Could have a base TemporalExpression and then add subexpression for java.util.Date based types, others for javax.time based types, and optionally (maybe impl dependent) jodatime expression type(s).

    Like

  3. andy says:

    Though maybe “ComparableExpression” makes more sense as a name to just map across to java.lang.Comparable. That's in SVN now

    Like

  4. Ok, ComparableExpression for the relation to java.util.Comparable, but that's just naming.

    NumericExpressionImpl usage was just quite confusing here. Code examples should make sense, that's why I mentioned it.

    Like

  5. andy says:

    Post updated to remove implementation details of the Q class so the user sees the API. Javadocs also updated to reflect above comments. Retained the add() method on StringExpression since it is concatenation in that case. Thx

    Like

  6. In the javadocs I found this :

    public interface ObjectExpression
    extends Expression

    This seems to be a bug.

    Also maybe ObjectExpression is not necessary. Object is the supertype for everything in Java, so maybe just implemenent Expression when nothing else fits.

    Like

  7. Sorry, I meant

    public interface ObjectExpression
    extends Expression
    More comments

    * asc, desc, min, max belong to ComparableExpression

    * avg and sum to NumericExpression

    * eq(Expression) -> eq(Expression) etc.

    * NumericExpresssion.add, div, mul, mod, mul sub also with Number arguments

    Like

  8. Suggestions for StringExpression :

    * BooleanExpression equalsIgnoreCase(String str);

    * BooleanExpression equalsIgnoreCase(Expression e);

    Like

  9. andy says:

    All suggestions ought to be in DN SVN now.
    Those StringExpression ideas (whilst now in DN SVN for typesafe queries) aren't part of JDOQL itself currently but you can obviously get the same via things like “str.toUpperCase() == str2.toUpperCase()” though makes sense to have that method added.

    Like

  10. How do you extract from Expression instances the data needed for serialization? e.g. the used operators and operands.

    If we could standardize this layer, then Querydsl and DataNucleus/JDO expressions could easily be mixed.

    This is something I am sketching for Querydsl 2.0 : http://source.mysema.com/forum/mvnforum/viewthread_thread,106

    The last class diagram shows the core types. For Querydsl 2.0 I am trying to separate the DSL part from the Expression archetypes.

    Like

  11. andy says:

    Timo, I've got a working prototype of this API for JDOQL now in DN SVN trunk. See
    http://www.datanucleus.org/products/accessplatform_2_2/jdo/jdoql_typesafe.html
    I've not implemented all TypesafeQuery methods yet (i.e parameters, variables, and some of the execute methods), and also I've not yet considered subqueries.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s