Re: split expressions

From: Aristedes Maniatis (ar..aniatis.org)
Date: Thu Jan 14 2010 - 04:40:56 EST

  • Next message: Andrus Adamchik: "Re: split expressions"

    On 14/01/10 8:10 PM, Andrus Adamchik wrote:
    >
    > On Jan 13, 2010, at 2:38 PM, Aristedes Maniatis wrote:
    >
    >> I've tried to explain the current usage better in the docs, given what
    >> I now understand. Please let me know if I misunderstood something. I
    >> had originally thought they were there as shortcuts to a path string.
    >
    > Actually we may start using them that purpose as well in 3.1 when and if
    > we merge SelectQuery and EJBQLQuery into a new SuperSelectQuery. Now I
    > think I remember that a possibility of unifying expressions with EJBQL
    > was considered when designing the API for splits. Hence aliases were
    > suggested.
    >
    >
    >> A way think of aliases is that they are markers within part of an
    >> expression which give Cayenne hints about merging. Like a query cache
    >> key, they are important only if you use the same key twice. But
    >> because aliases are created when you create the Expression path
    >> string, and then expanded when you construct the query, they can be
    >> awkward to use. It would be nicer if the Expression carried not only
    >> the idea of the key, but also how it expands and passed that onto the
    >> query.
    >>
    >> Expression e1 = ExpressionFactory.like("path1|paintings.gallery.name",
    >> "foo");
    >> Expression e2 = ExpressionFactory.like("path2|paintings.gallery.name",
    >> "bar");
    >>
    >> This puts the definition of the alias and the expansion in the same
    >> logical place. It would also allow
    >>
    >> Expression e2 = ExpressionFactory.like("path2|", "bar");
    >>
    >> to use the alias previously defined. Or to have Cayenne construct an
    >> arbitrary random, non-reusable alias:
    >>
    >> Expression e1 = ExpressionFactory.like("|paintings.gallery.name", "foo");
    >>
    >> Then you could even define an expression
    >>
    >> Expression e1 = Expression.fromString("|paintings.gallery.name = foo
    >> and |paintings.gallery.name = bar")
    >
    >
    > So the name before the pipe is an alias, right? Then how do we create
    > splits in the middle of the path?

       paintings.|gallery.name

    You could even this which uses an existing alias:

       paintings.path2|.name

    or this which makes a named alias:

       paintings.path2|gallery.name

    But the syntax is prone to confusion because it is hard to read. On the plus side though, I can't imagine why anyone would want to use named aliases in this way, so they are likely to be rare.

    > I guess we can have a more complex
    > notation:
    >
    > Artist.PAINTINGS.dot(Painting.EXHIBITS).alias("X").dot(Exhibit.GALLERIES).eq("Y");

    This is a long way from obvious for the most common use of the syntax: combining AND queries across a to-many join. Sure named aliases might be useful in themselves, maybe, for someone. I can't personally think of a reason. But the following seems clearer to me:

       Artist.PAINTINGS.join(Painting.EXHIBITS, Expression.SPLIT_PATH).join(Exhibit.GALLERIES).like("Y")

    My overall preference is to make the expression functions slightly more SQL-like, with words like join and like. Avoiding abstract ideas like 'alias' where they aren't relevant to the user is part of that same goal. In fact 'alias' has a specific SQL common meaning (table aliases) which is only going to confuse new users.

    If you really want to name an alias:

       Artist.PAINTINGS.join(Painting.EXHIBITS, "aliasX").join(Exhibit.GALLERIES).like("Y")

    > or setting the path, specifying the number of segments:
    >
    > Artist.PAINTINGS.dot(Painting.EXHIBITS).dot(Exhibit.GALLERIES).alias("X", 2);

    Maybe as an option, but I'd never use it. Consider the method:

    performAQuery(Expression e) {
       e1 = e.and(somequalifier);
       performMyQuery(e1.alias("X", 2); // what did that just do? How long was the path expression passed to the method?
    }

    >
    >
    > (s/dot/join/ or whatever)
    >
    > or the old way:
    >
    > // this will probably require defining a special Expression subclass -
    > KeyValueCondition or something
    > // that ensures there's only a single path inside
    > ExpressionFactory.like("paintings.gallery.name", "foo").split("X", 2);

    Just throw a runtime exception...

    Or if you really wanted to, promote 'path expression' from being just a String to having its own class. Then alias is just a special case of Path. Come to think of it, what is the difference between your new Key typesafe class and Path, other than a few dots...

    > So yeah, we are definitely making progress. One remaining case that is
    > still not accommodated is when subexpressions are created "in the
    > vacuum" with no knowledge of the overall query context. So we need to
    > take an existing (possibly nested) conditional expression and setup
    > correct splits for one or more of its paths. I guess some expression
    > transformer is needed here.

    My guess is that 99% of use cases would be met with a parameter to pass into the query which splits ALL paths. It would actually solve every instance of why we started this conversation in the first splace.

    Ari

    -- 
    -------------------------->
    Aristedes Maniatis
    GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
    



    This archive was generated by hypermail 2.0.0 : Thu Jan 14 2010 - 04:41:37 EST