You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cayenne.apache.org by Andrus Adamchik <an...@objectstyle.org> on 2013/05/24 17:45:55 UTC

SQLSelect: Getting fluent… WDYT?

https://issues.apache.org/jira/browse/CAY-1828
http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java

So SQLTemplate annoyed me enough to wrap it as a quick experiment with fluent APIs. I guess this is the direction where the rest of the queries should be going. Aside from chaining query configuration parameters, there are "select" and "selectOne" methods that allow to take the chain to the logical conclusion - the resulting objects.

I can think of other methods for building SQL chunks based on Cayenne mapping, such as "allColumns()", etc.

What do you think? Also method naming criticism is accepted. E.g. I am not sure that changing "setPageSize()" to "pageSize()" was such a great idea.

Andrus



Re: SQLSelect: Getting fluent… WDYT?

Posted by Andrus Adamchik <an...@objectstyle.org>.
Just committed basic scalar API:

int c = SQLSelect.scalarQuery(Integer.class, "")
          .append("SELECT COUNT(*) FROM ARTIST")
          .selectOne(context);

List<Long> ids = SQLSelect.scalarQuery(Long.class, "SELECT ARTIST_ID FROM ARTIST ORDER BY ARTIST_ID").select(context);

and documented the remaining enhancements per CAY-1830.

Andrus

On May 25, 2013, at 1:39 PM, Andrus Adamchik <an...@objectstyle.org> wrote:

> 
> On May 25, 2013, at 10:33 AM, Aristedes Maniatis <ar...@maniatis.org> wrote:
> 
> 
>> however I am confused by columnNameCaps(). This seems to be something you'd want to set in the data model rather than per query. Or could Cayenne just perform a case insensitive match to the db model and then adjust the case as needed, all without specifying anything.
> 
> Guessing it in Cayenne would be ideal. The feature itself dates back to SQLTemplate, but the new API is all about making things easier. The goal of this feat is to be able to convert DataRow to object, so we presumably know the entity involved and can make a good guess.
> 
>> Also, does it make sense to allow the bindings within the query method as an option:
>> 
>>   SQLSelect.query(Artist.class, "SELECT * FROM Artists WHERE name = $name", "name", "fred")
>> 
>> That's a bit like printf style calls (although it references replacements by position rather than name).
> 
> Yeah, I'd say we should start supporting positional parameters (and we do in EJBQL, but not in SQLTemplate or Expression). Then it will work with a vararg method.
> 
> 
>> Would it be possible to write aggregate queries:
>> 
>>   int count = SQLSelect.scalar(Artist.class, "SELECT COUNT(*) FROM Artists WHERE name = $name").bind("name", "fred").value()
> 
> Good idea. It should be easy to do.
> 
> Andrus
> 
> 


Re: SQLSelect: Getting fluent… WDYT?

Posted by Andrus Adamchik <an...@objectstyle.org>.
On May 25, 2013, at 10:33 AM, Aristedes Maniatis <ar...@maniatis.org> wrote:


> however I am confused by columnNameCaps(). This seems to be something you'd want to set in the data model rather than per query. Or could Cayenne just perform a case insensitive match to the db model and then adjust the case as needed, all without specifying anything.

Guessing it in Cayenne would be ideal. The feature itself dates back to SQLTemplate, but the new API is all about making things easier. The goal of this feat is to be able to convert DataRow to object, so we presumably know the entity involved and can make a good guess.

> Also, does it make sense to allow the bindings within the query method as an option:
> 
>    SQLSelect.query(Artist.class, "SELECT * FROM Artists WHERE name = $name", "name", "fred")
> 
> That's a bit like printf style calls (although it references replacements by position rather than name).

Yeah, I'd say we should start supporting positional parameters (and we do in EJBQL, but not in SQLTemplate or Expression). Then it will work with a vararg method.


> Would it be possible to write aggregate queries:
> 
>    int count = SQLSelect.scalar(Artist.class, "SELECT COUNT(*) FROM Artists WHERE name = $name").bind("name", "fred").value()

Good idea. It should be easy to do.

Andrus


Re: SQLSelect: Getting fluent… WDYT?

Posted by Michael Gentry <mg...@masslight.net>.
Hi Ari,

Perhaps a bit off topic (since I haven't really reviewed the class Andrus
posted yet), but I've already written some code for aggregates
(count/min/max/sum/avg) if anyone wants to use it.

Main project:
https://github.com/mrg/cbe/tree/master/FetchingObjects/Aggregates

Example using it:
https://github.com/mrg/cbe/blob/master/FetchingObjects/Aggregates/src/main/java/cbe/fetching/Aggregates.java

mrg



On Sat, May 25, 2013 at 3:33 AM, Aristedes Maniatis <ar...@maniatis.org>wrote:

> On 25/05/13 1:45am, Andrus Adamchik wrote:
>
>> I can think of other methods for building SQL chunks based on Cayenne
>> mapping, such as "allColumns()", etc.
>>
>> What do you think? Also method naming criticism is accepted. E.g. I am
>> not sure that changing "setPageSize()" to "pageSize()" was such a great
>> idea.
>>
>
> I think that in a fluent api, removing "set" before every method is
> clearer. Then you will have:
>
>     Artists<List> artists = SQLSelect.query(Artist.class, "SELECT * FROM
> Artists WHERE name = $name").bind("name", "fred").pageSize(10).**
> cacheGroups("main").select()
>
>
> However I am confused by columnNameCaps(). This seems to be something
> you'd want to set in the data model rather than per query. Or could Cayenne
> just perform a case insensitive match to the db model and then adjust the
> case as needed, all without specifying anything.
>
> Also, does it make sense to allow the bindings within the query method as
> an option:
>
>     SQLSelect.query(Artist.class, "SELECT * FROM Artists WHERE name =
> $name", "name", "fred")
>
> That's a bit like printf style calls (although it references replacements
> by position rather than name).
>
>
>
> Would it be possible to write aggregate queries:
>
>     int count = SQLSelect.scalar(Artist.class, "SELECT COUNT(*) FROM
> Artists WHERE name = $name").bind("name", "fred").value()
>
>
>
> Ari
>
>
>
> --
> -------------------------->
> Aristedes Maniatis
> GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
>

Re: SQLSelect: Getting fluent… WDYT?

Posted by Aristedes Maniatis <ar...@maniatis.org>.
On 25/05/13 1:45am, Andrus Adamchik wrote:
> I can think of other methods for building SQL chunks based on Cayenne mapping, such as "allColumns()", etc.
>
> What do you think? Also method naming criticism is accepted. E.g. I am not sure that changing "setPageSize()" to "pageSize()" was such a great idea.

I think that in a fluent api, removing "set" before every method is clearer. Then you will have:

     Artists<List> artists = SQLSelect.query(Artist.class, "SELECT * FROM Artists WHERE name = $name").bind("name", "fred").pageSize(10).cacheGroups("main").select()


However I am confused by columnNameCaps(). This seems to be something you'd want to set in the data model rather than per query. Or could Cayenne just perform a case insensitive match to the db model and then adjust the case as needed, all without specifying anything.

Also, does it make sense to allow the bindings within the query method as an option:

     SQLSelect.query(Artist.class, "SELECT * FROM Artists WHERE name = $name", "name", "fred")

That's a bit like printf style calls (although it references replacements by position rather than name).



Would it be possible to write aggregate queries:

     int count = SQLSelect.scalar(Artist.class, "SELECT COUNT(*) FROM Artists WHERE name = $name").bind("name", "fred").value()



Ari



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

Re: SQLSelect: Getting fluent… WDYT?

Posted by Michael Gentry <mg...@masslight.net>.
On Sun, May 26, 2013 at 3:41 PM, Andrus Adamchik <an...@objectstyle.org>wrote:

> If others are mostly using SQLTemplate to get a count or another aggregate
> function, we should just build utilities around SelectQuery to make
> aggregates possible / easy (kind of like you did already).
>

I have no issue with including the aggregates into Cayenne if you'd like.
 The entire project is open sourced under ASF 2.0.


>  So I'd like to hear from everyone what are the most typical use cases for
> SQLTemplate now?
>

I personally rarely use SQLTemplate.  The large project I'm working on has
a few EJBQLQuery uses that do behind-the-scenes updates, but I'll probably
eventually nuke those, too (they are causing issues).  I'd only use an
SQLTemplate if I needed to do something for which Cayenne was really
ill-suited (like a mass-update or mass-delete).

mrg

Re: SQLSelect: Getting fluent… WDYT?

Posted by Robert Zeigler <ro...@puregumption.com>.
My most common use-cases for SQLTemplate are either
a) To express an idiom that doesn't exist via other API's
b) For performance purposes.

One example of b: Several years ago (long before EJBQL support), I essentially had to build a pivot table, and to do it through the object api wound up being incredibly expensive. So I wrote some highly tuned and optimized queries and used SQLTemplate to fetch the data as data rows.

Outside of a and b, I typically stick with the object-based APIs.

Robert

On May 26, 2013, at 5/262:41 PM , Andrus Adamchik <an...@objectstyle.org> wrote:

> I think the example in the unit tests is just not too representative of how this will be used in real life. If all I need is "SELECT * FROM ARTIST", I'd use SelectQuery, not raw SQL. Usually SQLTemplate (and now SQLSelect) is a query of a last resort. 
> 
> An example from my customer apps... Occasionally I'd have a  situation when in addition to the main table ARTIST, I have a set of views that fetch data structures compatible with ARTIST, but do it in some really twisted way (with unions, subqueries, etc.). So 90% of the time I'd do "new SelectQuery(Artist.class)", and in the remaining 10% it will be "new SQLTemplate(Artist.class, "SELECT * FROM ARTIST_VIEW1")".
> 
> If others are mostly using SQLTemplate to get a count or another aggregate function, we should just build utilities around SelectQuery to make aggregates possible / easy (kind of like you did already). 
> 
> So I'd like to hear from everyone what are the most typical use cases for SQLTemplate now?
> 
> Andrus
> 
> 
> On May 26, 2013, at 9:13 PM, Michael Gentry <mg...@masslight.net> wrote:
>> That's cool, but it still seems like there is too much duplication for SQL
>> queries.
>> 
>> The main reason to pass in Artist.class, I think, is to know which objects
>> to create coming back, which means you shouldn't do:
>> 
>> "SELECT NAME FROM ARTIST"
>> 
>> if you are returning Artist.class (you want to fetch all the columns).
>> That type of query is only valid for data rows, right?
>> 
>> Also, I still don't like having to specify the artist twice.  So if doing a
>> data row query, maybe:
>> 
>> SQLSelect.dataRowsOn(Artist.class).columns(List<String> or
>> String...).where("...").fetch(context);
>> 
>> In this example, Cayenne can look up the correct table name for
>> Artist.class and automatically build it into the "SELECT ... FROM ARTIST"
>> for you.  And no need to write "select" three times, either -- I've
>> replaced your select(context) above with fetch(context).  Also, have two
>> methods for columns(), one which takes a List<String> and one that takes a
>> varargs parameter.  If you omit the columns, it can default to "*"
>> automatically.  I think this would provide more type safety, such as:
>> 
>> SQLSelect.dataRowsOn(Artist.class).columns(ARTIST.NAME_PROPERTY).where("...").select(context);
>> 
>> Of course, there should also be a where() method accepts an Expression, I
>> think.
>> 
>> Thoughts?
>> 
>> Thanks,
>> 
>> mrg
>> 
>> 
>> 
>> 
>> 
>> On Sun, May 26, 2013 at 12:58 PM, Andrus Adamchik <an...@objectstyle.org>wrote:
>> 
>>> Absolutely. I was planning a model-based SQL building as the next step for
>>> SQLSelect. The current version (that only took me maybe an hour to write)
>>> streamlines casting the result to something that you need, binding
>>> parameters, etc. I haven't looked at the SQL "payload" part of it yet. My
>>> note below about "other methods for building SQL chunks based on Cayenne
>>> mapping, such as "allColumns()" is essentially about doing something like
>>> you suggest.
>>> 
>>> In general designing this fluent API requires a bit different mindset
>>> compared to designing "canonical" API that we have. Will need to better
>>> wrap my head around it.
>>> 
>>> A.
>>> 
>>> 
>>> On May 26, 2013, at 3:19 PM, Michael Gentry <mg...@masslight.net> wrote:
>>>> Hi Andrus,
>>>> 
>>>> I may be missing something, but it looks like you'd have to do something
>>>> such as:
>>>> 
>>>> SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");
>>>> 
>>>> In most cases, you are always going to select "*" I think and artist is
>>>> duplicated.  Why not something more along the lines of:
>>>> 
>>>> SQLSelect.on(Artist.class).where("...");
>>>> 
>>>> Thanks,
>>>> 
>>>> mrg
>>>> 
>>>> 
>>>> 
>>>> On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <
>>> andrus@objectstyle.org>wrote:
>>>> 
>>>>> https://issues.apache.org/jira/browse/CAY-1828
>>>>> 
>>>>> 
>>> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
>>>>> 
>>>>> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
>>>>> fluent APIs. I guess this is the direction where the rest of the queries
>>>>> should be going. Aside from chaining query configuration parameters,
>>> there
>>>>> are "select" and "selectOne" methods that allow to take the chain to the
>>>>> logical conclusion - the resulting objects.
>>>>> 
>>>>> I can think of other methods for building SQL chunks based on Cayenne
>>>>> mapping, such as "allColumns()", etc.
>>>>> 
>>>>> What do you think? Also method naming criticism is accepted. E.g. I am
>>> not
>>>>> sure that changing "setPageSize()" to "pageSize()" was such a great
>>> idea.
>>>>> 
>>>>> Andrus
>>>>> 
>>>>> 
>>>>> 
>>> 
>>> 
> 


Re: SQLSelect: Getting fluent… WDYT?

Posted by Andrus Adamchik <an...@objectstyle.org>.
I think the example in the unit tests is just not too representative of how this will be used in real life. If all I need is "SELECT * FROM ARTIST", I'd use SelectQuery, not raw SQL. Usually SQLTemplate (and now SQLSelect) is a query of a last resort. 

An example from my customer apps... Occasionally I'd have a  situation when in addition to the main table ARTIST, I have a set of views that fetch data structures compatible with ARTIST, but do it in some really twisted way (with unions, subqueries, etc.). So 90% of the time I'd do "new SelectQuery(Artist.class)", and in the remaining 10% it will be "new SQLTemplate(Artist.class, "SELECT * FROM ARTIST_VIEW1")".

If others are mostly using SQLTemplate to get a count or another aggregate function, we should just build utilities around SelectQuery to make aggregates possible / easy (kind of like you did already). 

So I'd like to hear from everyone what are the most typical use cases for SQLTemplate now?

Andrus


On May 26, 2013, at 9:13 PM, Michael Gentry <mg...@masslight.net> wrote:
> That's cool, but it still seems like there is too much duplication for SQL
> queries.
> 
> The main reason to pass in Artist.class, I think, is to know which objects
> to create coming back, which means you shouldn't do:
> 
> "SELECT NAME FROM ARTIST"
> 
> if you are returning Artist.class (you want to fetch all the columns).
> That type of query is only valid for data rows, right?
> 
> Also, I still don't like having to specify the artist twice.  So if doing a
> data row query, maybe:
> 
> SQLSelect.dataRowsOn(Artist.class).columns(List<String> or
> String...).where("...").fetch(context);
> 
> In this example, Cayenne can look up the correct table name for
> Artist.class and automatically build it into the "SELECT ... FROM ARTIST"
> for you.  And no need to write "select" three times, either -- I've
> replaced your select(context) above with fetch(context).  Also, have two
> methods for columns(), one which takes a List<String> and one that takes a
> varargs parameter.  If you omit the columns, it can default to "*"
> automatically.  I think this would provide more type safety, such as:
> 
> SQLSelect.dataRowsOn(Artist.class).columns(ARTIST.NAME_PROPERTY).where("...").select(context);
> 
> Of course, there should also be a where() method accepts an Expression, I
> think.
> 
> Thoughts?
> 
> Thanks,
> 
> mrg
> 
> 
> 
> 
> 
> On Sun, May 26, 2013 at 12:58 PM, Andrus Adamchik <an...@objectstyle.org>wrote:
> 
>> Absolutely. I was planning a model-based SQL building as the next step for
>> SQLSelect. The current version (that only took me maybe an hour to write)
>> streamlines casting the result to something that you need, binding
>> parameters, etc. I haven't looked at the SQL "payload" part of it yet. My
>> note below about "other methods for building SQL chunks based on Cayenne
>> mapping, such as "allColumns()" is essentially about doing something like
>> you suggest.
>> 
>> In general designing this fluent API requires a bit different mindset
>> compared to designing "canonical" API that we have. Will need to better
>> wrap my head around it.
>> 
>> A.
>> 
>> 
>> On May 26, 2013, at 3:19 PM, Michael Gentry <mg...@masslight.net> wrote:
>>> Hi Andrus,
>>> 
>>> I may be missing something, but it looks like you'd have to do something
>>> such as:
>>> 
>>> SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");
>>> 
>>> In most cases, you are always going to select "*" I think and artist is
>>> duplicated.  Why not something more along the lines of:
>>> 
>>> SQLSelect.on(Artist.class).where("...");
>>> 
>>> Thanks,
>>> 
>>> mrg
>>> 
>>> 
>>> 
>>> On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <
>> andrus@objectstyle.org>wrote:
>>> 
>>>> https://issues.apache.org/jira/browse/CAY-1828
>>>> 
>>>> 
>> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
>>>> 
>>>> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
>>>> fluent APIs. I guess this is the direction where the rest of the queries
>>>> should be going. Aside from chaining query configuration parameters,
>> there
>>>> are "select" and "selectOne" methods that allow to take the chain to the
>>>> logical conclusion - the resulting objects.
>>>> 
>>>> I can think of other methods for building SQL chunks based on Cayenne
>>>> mapping, such as "allColumns()", etc.
>>>> 
>>>> What do you think? Also method naming criticism is accepted. E.g. I am
>> not
>>>> sure that changing "setPageSize()" to "pageSize()" was such a great
>> idea.
>>>> 
>>>> Andrus
>>>> 
>>>> 
>>>> 
>> 
>> 


Re: SQLSelect: Getting fluent… WDYT?

Posted by Andrus Adamchik <an...@objectstyle.org>.
On May 26, 2013, at 9:31 PM, Michael Gentry <mg...@masslight.net> wrote:

> Also, the three selects I mentioned are: SQLSelect[1].query(Artist.class,
> "SELECT[2] * FROM Artists").select[3](context).  That just seems like too
> many selects to me, which is why I was suggesting alternatives.

Good point about 3 selects. I am all for providing select clause builder, appending columns, etc. to eliminate #2.

I guess the only reason for select #3 is to be symmetrical with the new ObjectContext.select method (as this is what is being called ultimately). Other than that I don't have objections for renaming it to "fetch". Also we have "selectOne"… I guess that would be "fetchOne" or something.

A.


Re: SQLSelect: Getting fluent… WDYT?

Posted by Michael Gentry <mg...@masslight.net>.
Just to clarify (hopefully) a few points I made...

I'm fine with passing in the Java class (Artist.class) if I don't further
have to specify it as "SELECT * FROM ARTIST".  In fact, I'd prefer the
type-safety of letting Java use the class, but I'm not opposed to allowing
the complete string, either, would just prefer more type-safe options.

Also, the three selects I mentioned are: SQLSelect[1].query(Artist.class,
"SELECT[2] * FROM Artists").select[3](context).  That just seems like too
many selects to me, which is why I was suggesting alternatives.

mrg


On Sun, May 26, 2013 at 2:13 PM, Michael Gentry <mg...@masslight.net>wrote:

> That's cool, but it still seems like there is too much duplication for SQL
> queries.
>
> The main reason to pass in Artist.class, I think, is to know which objects
> to create coming back, which means you shouldn't do:
>
> "SELECT NAME FROM ARTIST"
>
> if you are returning Artist.class (you want to fetch all the columns).
>  That type of query is only valid for data rows, right?
>
> Also, I still don't like having to specify the artist twice.  So if doing
> a data row query, maybe:
>
> SQLSelect.dataRowsOn(Artist.class).columns(List<String> or
> String...).where("...").fetch(context);
>
> In this example, Cayenne can look up the correct table name for
> Artist.class and automatically build it into the "SELECT ... FROM ARTIST"
> for you.  And no need to write "select" three times, either -- I've
> replaced your select(context) above with fetch(context).  Also, have two
> methods for columns(), one which takes a List<String> and one that takes a
> varargs parameter.  If you omit the columns, it can default to "*"
> automatically.  I think this would provide more type safety, such as:
>
>
> SQLSelect.dataRowsOn(Artist.class).columns(ARTIST.NAME_PROPERTY).where("...").select(context);
>
> Of course, there should also be a where() method accepts an Expression, I
> think.
>
> Thoughts?
>
> Thanks,
>
> mrg
>
>
>
>
>
> On Sun, May 26, 2013 at 12:58 PM, Andrus Adamchik <an...@objectstyle.org>wrote:
>
>> Absolutely. I was planning a model-based SQL building as the next step
>> for SQLSelect. The current version (that only took me maybe an hour to
>> write) streamlines casting the result to something that you need, binding
>> parameters, etc. I haven't looked at the SQL "payload" part of it yet. My
>> note below about "other methods for building SQL chunks based on Cayenne
>> mapping, such as "allColumns()" is essentially about doing something like
>> you suggest.
>>
>> In general designing this fluent API requires a bit different mindset
>> compared to designing "canonical" API that we have. Will need to better
>> wrap my head around it.
>>
>> A.
>>
>>
>> On May 26, 2013, at 3:19 PM, Michael Gentry <mg...@masslight.net>
>> wrote:
>> > Hi Andrus,
>> >
>> > I may be missing something, but it looks like you'd have to do something
>> > such as:
>> >
>> > SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");
>> >
>> > In most cases, you are always going to select "*" I think and artist is
>> > duplicated.  Why not something more along the lines of:
>> >
>> > SQLSelect.on(Artist.class).where("...");
>> >
>> > Thanks,
>> >
>> > mrg
>> >
>> >
>> >
>> > On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <
>> andrus@objectstyle.org>wrote:
>> >
>> >> https://issues.apache.org/jira/browse/CAY-1828
>> >>
>> >>
>> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
>> >>
>> >> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
>> >> fluent APIs. I guess this is the direction where the rest of the
>> queries
>> >> should be going. Aside from chaining query configuration parameters,
>> there
>> >> are "select" and "selectOne" methods that allow to take the chain to
>> the
>> >> logical conclusion - the resulting objects.
>> >>
>> >> I can think of other methods for building SQL chunks based on Cayenne
>> >> mapping, such as "allColumns()", etc.
>> >>
>> >> What do you think? Also method naming criticism is accepted. E.g. I am
>> not
>> >> sure that changing "setPageSize()" to "pageSize()" was such a great
>> idea.
>> >>
>> >> Andrus
>> >>
>> >>
>> >>
>>
>>
>

Re: SQLSelect: Getting fluent… WDYT?

Posted by Michael Gentry <mg...@masslight.net>.
That's cool, but it still seems like there is too much duplication for SQL
queries.

The main reason to pass in Artist.class, I think, is to know which objects
to create coming back, which means you shouldn't do:

"SELECT NAME FROM ARTIST"

if you are returning Artist.class (you want to fetch all the columns).
 That type of query is only valid for data rows, right?

Also, I still don't like having to specify the artist twice.  So if doing a
data row query, maybe:

SQLSelect.dataRowsOn(Artist.class).columns(List<String> or
String...).where("...").fetch(context);

In this example, Cayenne can look up the correct table name for
Artist.class and automatically build it into the "SELECT ... FROM ARTIST"
for you.  And no need to write "select" three times, either -- I've
replaced your select(context) above with fetch(context).  Also, have two
methods for columns(), one which takes a List<String> and one that takes a
varargs parameter.  If you omit the columns, it can default to "*"
automatically.  I think this would provide more type safety, such as:

SQLSelect.dataRowsOn(Artist.class).columns(ARTIST.NAME_PROPERTY).where("...").select(context);

Of course, there should also be a where() method accepts an Expression, I
think.

Thoughts?

Thanks,

mrg





On Sun, May 26, 2013 at 12:58 PM, Andrus Adamchik <an...@objectstyle.org>wrote:

> Absolutely. I was planning a model-based SQL building as the next step for
> SQLSelect. The current version (that only took me maybe an hour to write)
> streamlines casting the result to something that you need, binding
> parameters, etc. I haven't looked at the SQL "payload" part of it yet. My
> note below about "other methods for building SQL chunks based on Cayenne
> mapping, such as "allColumns()" is essentially about doing something like
> you suggest.
>
> In general designing this fluent API requires a bit different mindset
> compared to designing "canonical" API that we have. Will need to better
> wrap my head around it.
>
> A.
>
>
> On May 26, 2013, at 3:19 PM, Michael Gentry <mg...@masslight.net> wrote:
> > Hi Andrus,
> >
> > I may be missing something, but it looks like you'd have to do something
> > such as:
> >
> > SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");
> >
> > In most cases, you are always going to select "*" I think and artist is
> > duplicated.  Why not something more along the lines of:
> >
> > SQLSelect.on(Artist.class).where("...");
> >
> > Thanks,
> >
> > mrg
> >
> >
> >
> > On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <
> andrus@objectstyle.org>wrote:
> >
> >> https://issues.apache.org/jira/browse/CAY-1828
> >>
> >>
> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
> >>
> >> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
> >> fluent APIs. I guess this is the direction where the rest of the queries
> >> should be going. Aside from chaining query configuration parameters,
> there
> >> are "select" and "selectOne" methods that allow to take the chain to the
> >> logical conclusion - the resulting objects.
> >>
> >> I can think of other methods for building SQL chunks based on Cayenne
> >> mapping, such as "allColumns()", etc.
> >>
> >> What do you think? Also method naming criticism is accepted. E.g. I am
> not
> >> sure that changing "setPageSize()" to "pageSize()" was such a great
> idea.
> >>
> >> Andrus
> >>
> >>
> >>
>
>

Re: SQLSelect: Getting fluent… WDYT?

Posted by Andrus Adamchik <an...@objectstyle.org>.
Absolutely. I was planning a model-based SQL building as the next step for SQLSelect. The current version (that only took me maybe an hour to write) streamlines casting the result to something that you need, binding parameters, etc. I haven't looked at the SQL "payload" part of it yet. My note below about "other methods for building SQL chunks based on Cayenne mapping, such as "allColumns()" is essentially about doing something like you suggest. 

In general designing this fluent API requires a bit different mindset compared to designing "canonical" API that we have. Will need to better wrap my head around it.

A.


On May 26, 2013, at 3:19 PM, Michael Gentry <mg...@masslight.net> wrote:
> Hi Andrus,
> 
> I may be missing something, but it looks like you'd have to do something
> such as:
> 
> SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");
> 
> In most cases, you are always going to select "*" I think and artist is
> duplicated.  Why not something more along the lines of:
> 
> SQLSelect.on(Artist.class).where("...");
> 
> Thanks,
> 
> mrg
> 
> 
> 
> On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <an...@objectstyle.org>wrote:
> 
>> https://issues.apache.org/jira/browse/CAY-1828
>> 
>> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
>> 
>> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
>> fluent APIs. I guess this is the direction where the rest of the queries
>> should be going. Aside from chaining query configuration parameters, there
>> are "select" and "selectOne" methods that allow to take the chain to the
>> logical conclusion - the resulting objects.
>> 
>> I can think of other methods for building SQL chunks based on Cayenne
>> mapping, such as "allColumns()", etc.
>> 
>> What do you think? Also method naming criticism is accepted. E.g. I am not
>> sure that changing "setPageSize()" to "pageSize()" was such a great idea.
>> 
>> Andrus
>> 
>> 
>> 


Re: SQLSelect: Getting fluent… WDYT?

Posted by Michael Gentry <mg...@masslight.net>.
Hi Andrus,

I may be missing something, but it looks like you'd have to do something
such as:

SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE ...");

In most cases, you are always going to select "*" I think and artist is
duplicated.  Why not something more along the lines of:

SQLSelect.on(Artist.class).where("...");

Thanks,

mrg



On Fri, May 24, 2013 at 11:45 AM, Andrus Adamchik <an...@objectstyle.org>wrote:

> https://issues.apache.org/jira/browse/CAY-1828
>
> http://svn.apache.org/repos/asf/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SQLSelect.java
>
> So SQLTemplate annoyed me enough to wrap it as a quick experiment with
> fluent APIs. I guess this is the direction where the rest of the queries
> should be going. Aside from chaining query configuration parameters, there
> are "select" and "selectOne" methods that allow to take the chain to the
> logical conclusion - the resulting objects.
>
> I can think of other methods for building SQL chunks based on Cayenne
> mapping, such as "allColumns()", etc.
>
> What do you think? Also method naming criticism is accepted. E.g. I am not
> sure that changing "setPageSize()" to "pageSize()" was such a great idea.
>
> Andrus
>
>
>