Type-safe qualifiers

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Wed Dec 30 2009 - 14:59:13 EST

  • Next message: Andrus Adamchik: "Re: Type-safe qualifiers (and queries)"

    While there's lots of things we need to figure out to create
    generified queries, here is one low-hanging fruit - type-safe
    qualifiers. The idea is borrowed from the WebObjects EOF extensions
    framework called Wonder:

    http://webobjects.mdimension.com/hudson/job/Wonder53/javadoc/er/extensions/eof/ERXKey.html

    The way it works, is that for each String property in a Persistent
    object, we generate an extra parameterized "key". E.g.:

    public class _Artist extends CayenneDataObject {

            public static final String DATE_OF_BIRTH_PROPERTY = "dateOfBirth";
            public static final Key<Date> DATE_OF_BIRTH = new Key<Date>(
                            DATE_OF_BIRTH_PROPERTY);

            public static final String NAME_PROPERTY = "name";
            public static final Key<String> NAME = new Key<String>(NAME_PROPERTY);

            public static final String PAINTINGS_PROPERTY = "paintings";
            public static final Key<Painting> PAINTINGS = new Key<Painting>(
                            PAINTINGS_PROPERTY);
    ...

    Key class is a builder of type-safe key-value expressions (see the
    link above for the type of methods that it has). I wrote a quick API-
    only prototype that is a replacement of ExpressionFactory. Here is an
    example of building the following Expression the old way and the new
    way:

       Expression: name='X' and (painting.name='Y' or painting.name='Z' or
    painting.name='A')

    1. Current API:

    Expression clause1 = ExpressionFactory.matchExp(Artist.NAME_PROPERTY,
    "X");
    Expression clause2 =
    ExpressionFactory.matchExp(Artist.PAINTINGS_PROPERTY + "." +
    Painting.NAME_PROPERTY, "Y");
    Expression clause3 =
    ExpressionFactory.matchExp(Artist.PAINTINGS_PROPERTY + "." +
    Painting.NAME_PROPERTY, "Z");
    Expression clause4 =
    ExpressionFactory.matchExp(Artist.PAINTINGS_PROPERTY + "." +
    Painting.NAME_PROPERTY, "A");

    Expression clause23 = clause2.orExp(clause3);
    Expression clause234 = clause23.orExp(clause4);
    Expression qualifier = clause1.andExp(clause234);

    2. New API:

    Expression clause1 = Artist.NAME.eq("X");
    Expression clause2 = Artist.PAINTINGS.dot(Painting.NAME).eq("Y");
    Expression clause3 = Artist.PAINTINGS.dot(Painting.NAME).eq("Z");
    Expression clause4 = Artist.PAINTINGS.dot(Painting.NAME).eq("A");

    Expression qualifier = Each.get(clause1, Any.get(clause2, clause3,
    clause4));

    As you see the new API is much tighter, and the first part of it is
    completely type-safe (generated "keys" ensure that we are matching
    against the right type of value, even in a multi-step path). The last
    line uses 2 new Expression factories, "Each" and "Any", to quickly
    organize key-value expressions into a nested expression tree. I think
    this is as good as it can get within the constraints of the Java syntax.

    I'd like to see if a similar approach can be extended to query
    building. Although that'll be a entirely different level of effort.
    For one thing it may force us to reconcile EJQBL and SelectQuery into
    a single query (SelectQuery is functionally a subset of EJBQLQuery.
    But SelectQuery "compilation" into SQL is fairly optimized, while
    EJBQLQuery-to-SQL conversion involves a much longer and slower
    pipeline). Plus of course there are other obstacles that we discussed
    before (such as a variety of possible result types).

    Andrus



    This archive was generated by hypermail 2.0.0 : Wed Dec 30 2009 - 14:59:53 EST