-----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