Re: [Still LONG] Re: [LONG] reasons why "advanced" expressions are needed

From: Giulio Cesare Solaroli (slrgcs..bn-italy.com)
Date: Mon Oct 06 2003 - 04:50:57 EDT

  • Next message: Mike Kienenberger: "Modeler doesn't generate/validate reverse relationships from EOModel [WAS Re: NullPointerException in QueryUtils$ExpressionTranslator.reverseDbPath(ObjEntity, String)]"

    On Friday, Oct 3, 2003, at 22:15 Europe/Rome, Andrus Adamchik wrote:

    >> Given all my comments (please, comment on them), if we managed to
    >> agree on my position that separating data from logic (like in the
    >> Expression, ExpressionEval, QueryTranslator case) is a bad think, I
    >> would propose the following path:
    >>
    >> - create a new cayenne.qualifiers (can you see how much I am biased?!
    >> :-] );
    >> - add all relevant methods to DataContext to be able to use
    >> qualifiers, still keeping Expressions working;
    >> - if everything works fine, we could start deprecating Expressions,
    >> with all the related classes and methods, and move up for a 2.0
    >> release!! ;-]
    >>
    >> This path seems long, but I don't think it will take too much. All
    >> other Cayenne features should be easily update where needed to use
    >> the new package.
    >>
    >> Needless to say, I will be pleased to start writing this new package,
    >> even if I will need much help in understanding how to integrate will
    >> all other Cayenne classes.
    >>
    >> Does this make any sense?
    >
    >
    > I am not taking any offense at constructive criticism. I can produce
    > badly designed stuff just like the guy next to me :-) In fact the
    > original Expressions design was done by another Cayenne committer,
    > Andriy (who is also the author of arguably most complicated piece in
    > Cayenne - graph sorting of database operations on commit - we are way
    > ahead of EOF here). Anyway, this original design had a nested class
    > hierarchy for expressions (operations vs. conditions vs...). It was an
    > explosion of inner classes, and after some time I replaced it with the
    > current package, for simplicity sake. He might have been on the right
    > track, not me .... so lets continue this discussion.
    >
    > I take the point that having expressions defined as data structures
    > with no behavior is bad for further extending. I most definitely agree
    > that ExpressionEval must be merged into expressions, making this part
    > of expression's behavior. But you still have to convince me that
    > translation to SQL must be done. My argument is that there must be a
    > horizontal layer separation, so there is a need of some sort of
    > external translation mechanism...

    I don't think we need a completely external translation mechanism, but
    let's try to list the feature we want to achieve and try to sort out
    the best arrangement to implement that.

    > E.g. take a look at DB2QualifierTranslator. SQL generated for the LIKE
    > expression is quiet different from any other database. At the same
    > time, like EOF, Cayenne would support parallel work with multiple
    > databases... So the user creating an expression in his code should be
    > able to run the same query against DB2 and Oracle without rebuilding
    > the expression....

    Point taken.

    > So whatever design we come up with should address the issue of
    > customizing SQL generation per RDBMS flavor, given a generic
    > db-independent expression.
    >
    >> As you can see yourself, with this arrangement you are forced of
    >> thinking about all possible cases upfront. To me this is a relevant
    >> sign of bad design.
    >
    > If we are to start rewriting expressions package from scratch, I'd
    > still vote for having an upfront design of such package presented on
    > this list, before we start an XP-style coding of it ;-).

    Absolutely! We must take all current feature request, and also how they
    have grown up, in order to find the best arrangement that could have
    allowed the easiest introduction of later requests.

    > Also, there are quiet a few existing expression packages (e.g. OGNL:
    > http://www.ognl.org/ )... I wonder if we can integrate one of those.
    > This is just something that came to my mind recently... I don't know
    > if this is a viable idea.

    I never give a deep look at OGNL but, for what I read, it was really
    useful. The main area where I head of its usage, was to extend the WOD
    syntax (in WebObjects components), in order to allow a greater number
    of feature available without having to code some extra methods in the
    class of the component.

    I don't know exactly how this could be used for Cayenne (trying to
    define expressions with a much richer semantic?), but I would take into
    consideration any concreate suggestion.

    Now, let's try to list the points that have been raised during this
    discussion, to find out which could be the best arrangement to
    implement this.

    - separating data from login is (usually) a bad choice;
    - it should be easy to add expressions with new semantic and patch
    existing expressions for errors or for compatibility with new RDBMS;
    - the SQL generated for each expression should be easily customized for
    each RDBMS in order to take advantage of every custom SQL syntax,
    keeping the code written using Cayenne DB independent. The coice of the
    RDBMS syntax to use should be a run-time decision taken from the
    deployment configuration in place.

    I have though about this during the weekend, and here the outcome of my
    delirium:

    - ExpressionEvaluation: an interface that expressions that can be
    evaluate in memory should implement; basically I think the only method
    defined here should be
            public boolean evalWithDataObject(org.objectstyle.cayenne.DataObject
    anObject);

    - SQLExpression: an interface to be implemented by expressions that can
    be evaluated as SQL statements; the method defined in this interface
    should be something like:
            public org.objectstyle.cayenne.query.SelectQuery
    queryWithAdapter(org.objectstyle.cayenne.dba.DbAdapter aDbAdapter);

    - Expression: an abstract class that could be used as superclass of the
    real expressions, and that could implement many common methods useful
    for the creation of the SQL;

    With this arrangement, every expression could be derived by Expression
    and should implement both the ExpressionEvaluation and the
    SQLExpression interfaces. This will allow for expression that could be
    only evaluated in memory and also for expressions that could be only
    evaluated on DB (for example expressions that translates to query using
    special syntax like the INTERMEDIA one, available with Oracle, that are
    not easily emulated in memory).

    The method "queryWithAdapter" should use the given adapter to customize
    the SQL generation for any given RDBMS supported; I have not figured
    out exactly how, however. I am not sure even if this method should
    return a SelectQuery or something else entirely, as the processes of
    creating the whole SQL string is not yet cristal clear to me, yet.

    Anyway, this is still the most troubled point also for other reasons:
    it is easy to factor into DbAdapter (and implement them into the
    subclasses) the differences of SQL syntax for the known situations, but
    it's quite hard to add something afterwards.

    What I am missing here is the Objective-C category concept, that will
    allow some methods to be added to a given class, also by an external
    package. :-[

    I have not found a solution I am proud of (yet?!?), but I am posting
    this message anyway, to let you comment on my current feeling
    immediately. I will follow up as soon as I have new thoughts on this
    topic.

    Does this make any sense?

    Giulio Cesare



    This archive was generated by hypermail 2.0.0 : Mon Oct 06 2003 - 04:53:02 EDT