-----Original Message-----
From: Aristedes Maniatis [mailto:[email protected]] 
Sent: Monday, January 30, 2012 12:21 PM
To: [email protected]
Subject: Re: SelectQuery + Orderings

On 30/01/12 9:12 PM, Durchholz, Joachim wrote:

>> giving
>>    new QualifierList ()
>>    .like("name", "b%")
>>    .or (
>>      new Greater("age", 23)
>>      .less("age", 27)
>>    )
>>
>
> I am not sure you have achieved any more readability over the plain string 
> version.
> Compare:
>
>    new SelectQuery().query("age < 27")
>
>    new SelectQuery().less("age", 27)


Oh, that was more a presentational afterthought, not the actual issue.
The background is that if you allow literals in query strings, it's getting 
seductive to write conditions like
  new SelectQuery().query("age < " + userInput)
and get an SQL injection problem.

> Which parameter is supposed to be less than which?

Left side is less than right side.
Hibernate is using this idiom in its Criteria queries, and while I have many 
gripes with Hibernate, this particular decision never causes any problem for me.

> A more radical approach was also discussed before.

Aww, the last weeks were a bit busy, so I probably missed that one.

> Something like (from memory):
> 
> new SelectQuery().and(Artist.AGE.under(23))

I'd introduce a standard abbreviation that SelectQuery() is automatically 
accepting conditions just like and() does.

> It reads nicely and can be made type-safe, but is a bit messy
> in that it moves many Expression methods into the ObjAttribute class.

I can't say much about messiness - I have done my part in writing ORM code, but 
I haven't had the time to take an actual look at Cayenne's sources, so in the 
end, my perspective is more that of an application programmer (Cayenne user) 
than that of a Cayenne developer.

However, I like that idiom very much, though I'd like to make it more concise.
My last example would look like this:

  SelectQuery(Artist.class)
  .and(
    .Artist.NAME.isLike("b%")
    .or(
      Artist.AGE.above(23),
      Artist.AGE.below(27)
    )
  )
  .join(Gallery.class)
  .Gallery.COUNTRY.eq("UK")
  .limit(10)
  .order(Artist.name)
  .perform()

Hm. What's nice about this is that it can be made type-safe and everything.
What's not so nice is that we have to repeat Artist. all over the place.

How about this one:

  Artist.query()
    .and(
      .NAME.isLike("b%")
      .or(
        Artist.conditions() // FAIL
        .AGE.above(23),
        .AGE.below(27)
      )
  .join(Gallery.class)
    .COUNTRY.eq("UK")
  .limit(10)
  .order(Artist.name)
  .perform()

I don't like the line marked FAIL, it's two tokens (Artist and conditions) just 
to make Java happy.
I'll have to come up with something better. Maybe make the nesting structure 
explicit with an .end() call:

  Artist.query()
  .and()
    .NAME.isLike("b%")
    .or()
      .AGE.above(23)
      .AGE.below(27)
    .end()
  .end() // redundant
  .order()
    .NAME
  .end() // redundant
  .join(Gallery.class)
  .COUNTRY.eq("UK")
  .perform()

Some of the .end() calls are redundant and could be eliminated.
It's still relatively compact, at the price of the occasional end() - those 
marked with "redundant" probably could be eliminated, so it's not so bad.

This all smells like a generalized type-safe expression builder trying to get 
out.

Unfortunately, I won't be able make this into a proof of concept, much less 
program it, so I'm limited to providing food for thought. Hope it helps - if 
not, please ignore :-)

Regards,
Jo

Reply via email to