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)
              .column(Artist.ARTIST_NAME)
              .column(Artist.ARTIST_BIRTH_DATE)
              .select(context);

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(nameLength.gt(10))
>                                .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(paintingCountProperty.gt(10L))
>>                 .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(paintingCountProperty.gt(10L))
>                 .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)
                 .having(paintingCountProperty.gt(10L))
                 .select(context);

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?


Ari




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

Reply via email to