cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Aristedes Maniatis <>
Subject Re: API for aggregate and non aggregate SQL functions
Date Sun, 08 Jan 2017 12:26:09 GMT
On 8/1/17 1:03am, Nikita Timofeev wrote:

> The later is closer to the design.
> Both column() and columns() methods return same ObjectSelect object,
> they only change result type (as fetchDataRows() method do):
> column() changes result to ObjectSelect<T>, where T is type of
> Property, so no cast of the result required
> and columns() changes to ObjectSelect<Object[]>. The idea is that you
> can still use all methods in ObjectSelect.

Yes, fair enough and that makes sense. So could we do this:

List<Object[]> namesAndBirthDates = ObjectSelect.query(Artist.class)

how can we handle the result type?

Will this work with selectOne() returning Object or Object[] in difference cases?

> Property<Integer> nameLength =
> Property.create(FunctionExpressionFactory.lengthExp(Artist.ARTIST_NAME.path()),
> Integer.class);
> List<Artist> artists = ObjectSelect.query(Artist.class)
>                                .where(
>                                .select(context);

Could that syntax above could be cleaner like:

   Property<Integer> nameLength = Artist.ARTIST_NAME.function(Expression.SQL_LENGTH)

or is that just going to result in a whole lot of clutter in the class?

>> I know factories are the Java way, but given how common count() and max() are, surely
we'd want a shortcut. I'd like to be able to go directly to:
>> int count = ObjectSelect.query(Artist.class)
>>                 .where(Artist.ARTIST_NAME.eq("Ari"))
>>                 .selectCount(context);
> I want this shortcut too :) I'd like to avoid a feature bloat, so that
> could be done later.

I think its worth planning the API for this now, given that this is probably the most common
function used.

I was trying to think of some syntax using Java 8 lambas, but couldn't quite see how it might
work cleanly.

>> would a map be more useful to return than this tuple style approach? Java's collections
are a bit clunky, but:
>> Map<PersistentObject, Object[]> result2 = ObjectSelect.query(Artist.class)
>>                 .columns(Artist.ARTIST_NAME, paintingCountProperty)
>>                 .having(
>>                 .select(context);
> I'm not sure that Map<> will be a good approach to the problem.
> We actually discussed with Andrus how PersistentObject can be returned
> with columns() method.
> And we decided that it will be better to define explicitly that you
> want PersistentObject in result:
> Property<Artist> artistSelf = Property.create("hollowArtist", ?some
> expression?, Artist.class);
> List<Object[]> result2 = ObjectSelect.query(Artist.class)
>                 .columns(Artist.ARTIST_NAME, artistSelf, paintingCountProperty)
>                 .having(
>                 .select(context);
> What do you think about it?

Seems reasonable. Given this could be a very useful approach, it makes sense to make the syntax
above a it more explicit or simple.

List<Object[]> result2 = ObjectSelect.query(Artist.class)
                 .columns(Artist.ARTIST_NAME, Property.HOLLOW_OBJECT, paintingCountProperty)

This sort of query would be great for displaying a list of records (where you might want only
a couple of columns to be loaded and displayed rather than whole objects). But then double
clicking opens an edit view and you want to easily fault all its attributes without worrying
about tracking its PK directly.

Finally, 'having()' matches the SQL (HAVING is needed for queries on the result of functions).
Have you thought about how that could be abstracted away so that the user can use where()
and the correct SQL is still generated by Cayenne?


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

View raw message