[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-30 Thread Michael Bayer



On Apr 30, 1:11 pm, "Gaetan de Menten" <[EMAIL PROTECTED]> wrote:

> There is (at least) one problem remaining though: subqueries do not
> get correlated correctly. This is because the table in the main query
> is aliased and the one in the subquery is not and that the
> "correlator" in the Select class does not recognize an aliased table
> as being the same as the original table.
>
> I see two ways to fix this:
>
> * The first and most easy one is to change the correlator to correlate
> aliased tables with the original ones. Attached is patch which does
> just that. But I highly suspect it's not correct to do that.
>
> * The other option is obviously to aliasize the table in the
> subquery... The problem with that is that the ClauseAdapter in
> sql_util simply doesn't do it... And I didn't see a way to make it do
> it since the "from" objects in a select are pretty much private. Any
> idea?

ticket #52 needs to be implemented first.  the work there is 5% adding
the method, 95% in creating the unit tests so that any changes to
sql.Select in the future dont break the method.

secondly, the "from" list of Select can be affected in two ways, by
adding a FromClause that implements _hide_froms() to "conceal" from
clauses which it replaces, and also by explicitly calling
correlate(from_obj) which is not quite what you need here.  but theres
no reason append_from() cant have a "hides=None" argument added to it
so an external actor can also indicate "FROM object X masks FROM
object Y".  also theres not any huge reason there cant be a
remove_from() either.   looking at the code im seeing some possible
simplifications to the _process_froms() method which might make some
of this easier to see.

the usage of these "from altering" methods in sql_util would all be
just an enhancement to AbstractClauseProcessor who's usage would
become more generalized to be able to process selects and not just
binary/compound clause fragments.  the Aliasizer also i think will
soon be removed in all cases and replaced with ClauseAdapter which is
easier to use.


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-30 Thread Gaetan de Menten
On 4/30/07, Michael Bayer <[EMAIL PROTECTED]> wrote:

> turns out scalar columns already worksince they are
> just...columns !  which ColumnProperty already handles.

That's what I tried to get at... that it was supposed to "just work"...

> any old SA
> version will allow the test script to work, if you use ColumnProperty
> explicitly along with two small fixes in sql.py.  in the trunk ive
> added those fixes, as well as reinstated the function "column_property
> ()" as a synonym for ColumnProperty and adapted your "eager" handling
> logic (also aliases the labels) so the columns work out in an eager
> relation, so mappings:

Thanks a lot for taking the trouble to fix those bugs.

There is (at least) one problem remaining though: subqueries do not
get correlated correctly. This is because the table in the main query
is aliased and the one in the subquery is not and that the
"correlator" in the Select class does not recognize an aliased table
as being the same as the original table.

I see two ways to fix this:

* The first and most easy one is to change the correlator to correlate
aliased tables with the original ones. Attached is patch which does
just that. But I highly suspect it's not correct to do that.

* The other option is obviously to aliasize the table in the
subquery... The problem with that is that the ClauseAdapter in
sql_util simply doesn't do it... And I didn't see a way to make it do
it since the "from" objects in a select are pretty much private. Any
idea?

-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---

Index: sql.py
===
--- sql.py  (revision 2589)
+++ sql.py  (working copy)
@@ -2875,9 +2875,12 @@
 This basically means the given from object will not come out
 in this select statement's ``FROM`` clause when printed.
 """
+if isinstance(from_obj, Alias):
+original = from_obj.original
+else:
+original = from_obj
+self.__correlated[original] = from_obj
 
-self.__correlated[from_obj] = from_obj
-
 def append_from(self, fromclause):
 if type(fromclause) == str:
 fromclause = FromClause(fromclause)


[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-29 Thread Michael Bayer

turns out scalar columns already worksince they are  
just...columns !  which ColumnProperty already handles.   any old SA  
version will allow the test script to work, if you use ColumnProperty  
explicitly along with two small fixes in sql.py.  in the trunk ive  
added those fixes, as well as reinstated the function "column_property 
()" as a synonym for ColumnProperty and adapted your "eager" handling  
logic (also aliases the labels) so the columns work out in an eager  
relation, so mappings:

mapper(Tag, tags_table, properties={
 'query_score': column_property((tags_table.c.score1 *  
tags_table.c.score2).label('tag_score'))
})

user_score = select([func.sum(tags_table.c.score1 *
   tags_table.c.score2)],
 tags_table.c.user_id == users_table.c.id,
 scalar=True).label('user_score')

mapper(User, users_table, properties={
 'tags': relation(Tag, backref='user'),
 'query_score': column_property(user_score),
})

though it still wont work with every kind of eager load, such as an  
eager load from Tag to Userpostgres will see the Tag table  
referenced in the subquery and demand the GROUP BY expression as ive  
mentioned.  i dont really see any way around that scenario.

im usually up for adding features to SA if they dont require actually  
adding any featuresthis one just needed two bug fixes and a  
little bit of extra grease in the eager load setup.


On Apr 25, 2007, at 3:52 PM, Gaetan de Menten wrote:

> It's better with the attachments (the actual patch and a small
> demonstration/test file)...
>
> On 4/25/07, Gaetan de Menten <[EMAIL PROTECTED]> wrote:
>> Ok, I'm quite a bit stubborn at times, so I implemented this the  
>> way I
>> thought because I think it makes much more sense this way.
>>
>> Attached is an experimental (as usual) patch to add a
>> StatementProperty, so that you can define stuff like:
>>
>> mapper(Tag, tags_table, properties={
>> 'query_score': StatementProperty((tags_table.c.score1 *
>> tags_table.c.score2).label('tag_score'), Float()),
>> })
>>
>> or even:
>>
>> user_score = select([func.sum(tags_table.c.score1 *
>>   tags_table.c.score2)],
>> tags_table.c.user_id == users_table.c.id,
>> scalar=True).label('user_score')
>>
>> mapper(User, users_table, properties={
>> 'tags': relation(Tag, backref='user', lazy=False),
>> 'query_score': StatementProperty(user_score, Float()),
>> })
>>
>> I don't see what's wrong with this approach so far. As always, I  
>> might
>> not see the big picture... I just hope this will be useful in some
>> way, even if it's not what you envisioned.
>>
>> Some random remarks:
>> - the statement you give must have a label (that seem pretty logical
>> this way though)
>> - you need to manually provide the type of the property you create
>> (seem logical too). In a final patch, we'd probably want to also
>> accept types in their class form (Float and Float()).
>> - it works both for lazy and eagerloads (I struggled quite a bit to
>> get those to work)
>> - subselects pulled from a lazyload don't work though. But I think it
>> should be quite easily fixable.
>> - As always, I'm not attached to the names I've given.
>>
>> On 4/24/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
>>>
>>>
>>> On Apr 24, 2007, at 4:44 AM, Gaetan de Menten wrote:
>>>

> the next way is to do it almost the same as Jonathan's blog  
> says to
> do it, except youd map the relation to some intermediary class  
> like
> "Score", and then use AssociationProxy to apply the "scalar"  
> property
> to the class.

 I thought about something like this but it felt sooo hacky I
 disregarded it quickly.

>>>
>>> this is probably the least hacky as like i said im probably going to
>>> implement a feature that works just like this.
>>>
>>
>>
>>
>> --
>> Gaëtan de Menten
>> http://openhex.org
>>
>
>
> -- 
> Gaëtan de Menten
> http://openhex.org
>
> >
> from sqlalchemy import *
> from sqlalchemy.orm.properties import StatementProperty
>
> metadata = MetaData()
>
> users_table = Table('users', metadata,
> Column('id', Integer, primary_key=True),
> Column('name', String(16)),
> )
>
> tags_table = Table('tags', metadata,
> Column('id', Integer, primary_key=True),
> Column('user_id', Integer, ForeignKey("users.id")),
> Column('score1', Float),
> Column('score2', Float),
> )
>
> metadata.connect('sqlite:///')
> metadata.create_all()
>
> class User(object):
> def __init__(self, name):
> self.name = name
>
> @property
> def prop_score(self):
> return sum(tag.prop_score for tag in self.tags)
>
> class Tag(object):
> def __init__(self, score1, score2):
> self.score1 = score1
> self.score2 = score2
>
> @property
> def prop_score(self):
> return self.score1 * self.score2
>
> # this doesn't work
> tag_score 

[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-27 Thread Gaetan de Menten

On 4/26/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
> On Apr 26, 2007, at 4:40 AM, Gaetan de Menten wrote:
> >
> >> - the biggest picture not here - its read only !
> >
> > It's obviously meant to be that way... So I don't see a problem here.
> > We might want to add an exception when people try to change it, but
> > that shouldn't be too hard. Besides, I don't see how the
> > association_proxy approach would make it any different.
> >
>
> the function allows the adding of any arbitrary SQL expression.  if
> that expression were just a column somewhere, and not an aggregate,
> it would be expected that this would be writeable.  reasons like this
> are why the feature as proposed is too narrow.   IMO if you are
> querying things that are read-only, they generally belong more on the
> Query side of things and not the object-relationship side of
> things

Well, for me, everything which is called often enough should be
factored in the class as a property. The problem being that if you use
a python property, you'd have an extremely inefficient code (to
compute one aggregate method, you'd have to load all related
instances, and so on...).

> within the SA philosophy at least.

Ok, I'll shut-up after this mail... I can't argue with that. ;-)

> >> - we already have a way to do the above - map to a select
> >> statement,
> >> thereby forcing the user to figure out GROUP BY, polymorphic loading,
> >> etc., also produces an encapsulated statement which eager loaders,
> >> LIMIT/OFFSET etc. criterion can be more readily tacked onto.
> >
> > No, this doesn't suit my needs. I need that particular property to be
> > deferrable. As I said, I got several of them and, for each query, I
> > can need any combination of them. Even though my patch doesn't include
> > the code to do it, with "my" approach, I think it's possible to do it,
> > unlike with the "map to a select statement" approach.
>
> yeah i would just use non_primary mappers and/or Query.select(full
> select statement)/ Query.add_column(.etc), the "deferred" version
> would be just a property on the class itself that issues a Query.

I'll try this (add_column) route. The problem with this approach is
that I fear it won't be easy to have those additional columns still
available as lazy load. Though I haven't thought much about this
option yet, so that might prove easier than I think.

> essentially everything you want is possible here except that the
> "deferred" option doesnt hook into it the way you want.  which almost
> implies that maybe you just want a new kind of option() that can
> select a non-primary mapper for a particular class query...  query
> (MyClass).use_mapper(aggregate_mapper).select()...

Almost... I would have wanted to not even have to declare alternate
mappers, only all the possible "additional" (aggregate) columns. And
at query time say: fetch this and that "column" (in addition to the
main query) and not those others (which would still be available as
lazy properties).

> at most, for this feature, it would have to be called "aggregate()"
> since its pretty limited to that, and take a limited set of criterion
> in the same way as relation(), and the GROUP BY stuff would have to
> work since postgres/oracle/etc. require that.

FYI, postgres eats my example just fine.

> the  GROUP BY columns
> would be automatically added during the query process since its
> basically, "every column we're selecting".  the whole query wrapping
> thing would have to take place too to cleanly tack on other eager
> loads, limiting criterion and such.  i think some things might
> continue to break when the query is formed this way (particularly
> inheritance) and we might have to add a disclaimer "oh by the way,
> you cant do X, Y and Z when you have a non-deferred aggregate()
> column" if thats the case.
>
> the main thing is, all the tools are there to do this already, we're
> just talking about adding "yet another way to do it" to suit the code
> looking a certain way, in a way that also has a lot of non-working
> use cases.  plus, just because its not in core, so what ?  its a
> great recipe, maybe extension, we can even add a unit test to ensure
> the API continues to support it.  elixir can have a built-in feature
> tying to the recipe as well (since elixir is the "convenience" layer
> with a little more opinion).

Ok, I'll try to implement that in my own private layer on top of
Elixir, then *if* that's not too invasive I'll either include it in
Elixir (if nobody disagrees there) or post it as a recipe for
SQLAlchemy.

-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~

[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-26 Thread Michael Bayer


On Apr 26, 2007, at 9:46 AM, Gaetan de Menten wrote:

>
> But nevermind the patch I did. I realize now it's pretty much useless.
> But what about the approach I discussed in my previous mail? (using
> what is in the relation loaders but without creating the instances)
>

well as ive said, id like it to support scalars or collections, and  
to be writeable...it would generally be used for values loaded from  
another table that are returned as non-entities, like integers,  
strings, etc.  the corresponding feature in hibernate is http:// 
www.hibernate.org/hib_docs/v3/reference/en/html/ 
collections.html#collections-ofvalues , except as usual we have the  
"uselist=False" option which allows it to be just one element.

I kind of feel like i have to experiment with hibernate to see  
exactly what the second option there, "formula='any sql expression'",  
actually does.  im not sure if the feature covers the specific thing  
you want to do.  at the very least, if you mapped to an aggregate  
thered be a "viewonly=True" thing happening there.

implementation-wise, our entity-mapping capabilities are the best way  
to handle keeping track of these elements and writing them back to  
the DB, so it would at some level use mapped entities that are  
handled behind the scenes.   you think its a bad idea because youre  
looking at it as something bolted on to the outside, but it doesnt  
have to be that way.  its likely that it  may be best handled as a  
collection of entities that is only generated at flush time against  
the mapped collection, within the dependency processor itself.   the  
attribute instrumentation system would need some tweaks to support  
collections of non-entities as well (which i think is probably not a  
big deal, if even it cant do it already).



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-26 Thread Michael Bayer


On Apr 26, 2007, at 4:40 AM, Gaetan de Menten wrote:

>
>> - the biggest picture not here - its read only !
>
> It's obviously meant to be that way... So I don't see a problem here.
> We might want to add an exception when people try to change it, but
> that shouldn't be too hard. Besides, I don't see how the
> association_proxy approach would make it any different.
>

the function allows the adding of any arbitrary SQL expression.  if  
that expression were just a column somewhere, and not an aggregate,  
it would be expected that this would be writeable.  reasons like this  
are why the feature as proposed is too narrow.   IMO if you are  
querying things that are read-only, they generally belong more on the  
Query side of things and not the object-relationship side of  
thingswithin the SA philosophy at least.

>> - we already have a way to do the above - map to a select  
>> statement,
>> thereby forcing the user to figure out GROUP BY, polymorphic loading,
>> etc., also produces an encapsulated statement which eager loaders,
>> LIMIT/OFFSET etc. criterion can be more readily tacked onto.
>
> No, this doesn't suit my needs. I need that particular property to be
> deferrable. As I said, I got several of them and, for each query, I
> can need any combination of them. Even though my patch doesn't include
> the code to do it, with "my" approach, I think it's possible to do it,
> unlike with the "map to a select statement" approach.

yeah i would just use non_primary mappers and/or Query.select(full  
select statement)/ Query.add_column(.etc), the "deferred" version  
would be just a property on the class itself that issues a Query.   
essentially everything you want is possible here except that the  
"deferred" option doesnt hook into it the way you want.  which almost  
implies that maybe you just want a new kind of option() that can  
select a non-primary mapper for a particular class query...  query 
(MyClass).use_mapper(aggregate_mapper).select()...

at most, for this feature, it would have to be called "aggregate()"  
since its pretty limited to that, and take a limited set of criterion  
in the same way as relation(), and the GROUP BY stuff would have to  
work since postgres/oracle/etc. require that.  the  GROUP BY columns  
would be automatically added during the query process since its  
basically, "every column we're selecting".  the whole query wrapping  
thing would have to take place too to cleanly tack on other eager  
loads, limiting criterion and such.  i think some things might  
continue to break when the query is formed this way (particularly  
inheritance) and we might have to add a disclaimer "oh by the way,  
you cant do X, Y and Z when you have a non-deferred aggregate()  
column" if thats the case.

the main thing is, all the tools are there to do this already, we're  
just talking about adding "yet another way to do it" to suit the code  
looking a certain way, in a way that also has a lot of non-working  
use cases.  plus, just because its not in core, so what ?  its a  
great recipe, maybe extension, we can even add a unit test to ensure  
the API continues to support it.  elixir can have a built-in feature  
tying to the recipe as well (since elixir is the "convenience" layer  
with a little more opinion).



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-26 Thread Gaetan de Menten

On 4/26/07, Michael Bayer <[EMAIL PROTECTED]> wrote:

> On Apr 26, 2007, at 4:40 AM, Gaetan de Menten wrote:
>
> >> - you have an aggregate function there.  wheres the GROUP
> >> BY ? not
> >> just of the main table's columns but any other columns named for
> >> eager loads.
> >
> > It's unneeded in my example, and for cases where this would be needed,
> > I think we could easily enhance the StatementProperty so that you can
> > add anything to the parent query: join conditions, etc...
> >
>
> how do you select multiple columns, where only one column is used in
> an aggregate function, and no GROUP BY?

The answer is: you don't. This is a subselect. Here is, for example,
the query generated for the lazy version:

SELECT (SELECT sum(tags.score1 * tags.score2) FROM tags WHERE
tags.user_id = users.id) AS user_score, users.id AS users_id,
users.name AS users_name
FROM users ORDER BY users.id

> are you using mysql only ?

Nope.

By the way, the patch I did is buggier than I thought for eager
relationships. I thought it broke only for subselects, but the simple
"statement" I provided in my example doesn't work nicely either
(because it needlessly joins to the "tags" table). So the result are
correct but it's awfull behind the scene. :)

But nevermind the patch I did. I realize now it's pretty much useless.
But what about the approach I discussed in my previous mail? (using
what is in the relation loaders but without creating the instances)

-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-26 Thread Michael Bayer


On Apr 26, 2007, at 4:40 AM, Gaetan de Menten wrote:

>> - you have an aggregate function there.  wheres the GROUP  
>> BY ? not
>> just of the main table's columns but any other columns named for
>> eager loads.
>
> It's unneeded in my example, and for cases where this would be needed,
> I think we could easily enhance the StatementProperty so that you can
> add anything to the parent query: join conditions, etc...
>

how do you select multiple columns, where only one column is used in  
an aggregate function, and no GROUP BY?  are you using mysql only ?





--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-26 Thread Gaetan de Menten

On 4/26/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
>
>
> On Apr 25, 2007, at 3:52 PM, Gaetan de Menten wrote:
>
> > It's better with the attachments (the actual patch and a small
> > demonstration/test file)...
> >
> > On 4/25/07, Gaetan de Menten <[EMAIL PROTECTED]> wrote:
> >> Ok, I'm quite a bit stubborn at times, so I implemented this the
> >> way I
> >> thought because I think it makes much more sense this way.
> >>
> >> Attached is an experimental (as usual) patch to add a
> >> StatementProperty, so that you can define stuff like:
> >>
> >> mapper(Tag, tags_table, properties={
> >> 'query_score': StatementProperty((tags_table.c.score1 *
> >> tags_table.c.score2).label('tag_score'), Float()),
> >> })
> >>
> >> or even:
> >>
> >> user_score = select([func.sum(tags_table.c.score1 *
> >>   tags_table.c.score2)],
> >> tags_table.c.user_id == users_table.c.id,
> >> scalar=True).label('user_score')
> >>
> >> mapper(User, users_table, properties={
> >> 'tags': relation(Tag, backref='user', lazy=False),
> >> 'query_score': StatementProperty(user_score, Float()),
> >> })
> >>
> >> I don't see what's wrong with this approach so far. As always, I
> >> might
> >> not see the big picture... I just hope this will be useful in some
> >> way, even if it's not what you envisioned.
>
> OK well thats not bad. also im glad you are getting familiarized with
> ORM internals, since there are very few who have ventured in there so
> far.  But here some bigger picture things:
>
> - you have an aggregate function there.  wheres the GROUP BY ? not
> just of the main table's columns but any other columns named for
> eager loads.

It's unneeded in my example, and for cases where this would be needed,
I think we could easily enhance the StatementProperty so that you can
add anything to the parent query: join conditions, etc...

> - it only works for scalars.  what about statements that return lists 
> ?

Yeah that's a limitation of the approach, but I think it's ok. Maybe
rename the thing to ScalarProperty to make it more obvious?

> - it doesnt figure out any kind of join conditions to the parent
> table.  what happens when a polymorphically loading mapper tries to
> use it  (or any of the other myriad bizarro things that happen with
> inheritance)?

Ok, that might be a problem. Honestly, I have a pretty narrow
knowledge (and fuzzy understanding) of the internals of that whole
polymorphic inheritance. But wouldn't it be possible to factor out
what is done in the relation loaders. The problems ought to be the
same, right? And it'd also solve your list statement complaint above.
From my understanding, it's "just" the last part (ie to create an
instance out of the scalar(s)) which needs to be skipped). In fact,
this was how I originally intended to implement the thing but that
code seemed too complex to tap into to make my demonstration patch, so
I rather took the ColumnProperty code as a base ;-).

My point was and still is (I just realized I haven't said it clearly
yet): I don't get why it would be preferable to go through the trouble
of creating instances and proxies just to go through them and only
ever use them as scalars, when one could (or at least, I'm convinced
one could) simply skip the instance creation step.

> - the biggest picture not here - its read only !

It's obviously meant to be that way... So I don't see a problem here.
We might want to add an exception when people try to change it, but
that shouldn't be too hard. Besides, I don't see how the
association_proxy approach would make it any different.

> - we already have a way to do the above - map to a select statement,
> thereby forcing the user to figure out GROUP BY, polymorphic loading,
> etc., also produces an encapsulated statement which eager loaders,
> LIMIT/OFFSET etc. criterion can be more readily tacked onto.

No, this doesn't suit my needs. I need that particular property to be
deferrable. As I said, I got several of them and, for each query, I
can need any combination of them. Even though my patch doesn't include
the code to do it, with "my" approach, I think it's possible to do it,
unlike with the "map to a select statement" approach.

>
> Since you have built upon interfaces that I consider to be public so
> this is definitely at least a decent recipe.  im not sold on it as a
> core feature though since its scope is too narrow compared to what
> people will expect from it.
>


-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---

[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-25 Thread Michael Bayer


On Apr 25, 2007, at 3:52 PM, Gaetan de Menten wrote:

> It's better with the attachments (the actual patch and a small
> demonstration/test file)...
>
> On 4/25/07, Gaetan de Menten <[EMAIL PROTECTED]> wrote:
>> Ok, I'm quite a bit stubborn at times, so I implemented this the  
>> way I
>> thought because I think it makes much more sense this way.
>>
>> Attached is an experimental (as usual) patch to add a
>> StatementProperty, so that you can define stuff like:
>>
>> mapper(Tag, tags_table, properties={
>> 'query_score': StatementProperty((tags_table.c.score1 *
>> tags_table.c.score2).label('tag_score'), Float()),
>> })
>>
>> or even:
>>
>> user_score = select([func.sum(tags_table.c.score1 *
>>   tags_table.c.score2)],
>> tags_table.c.user_id == users_table.c.id,
>> scalar=True).label('user_score')
>>
>> mapper(User, users_table, properties={
>> 'tags': relation(Tag, backref='user', lazy=False),
>> 'query_score': StatementProperty(user_score, Float()),
>> })
>>
>> I don't see what's wrong with this approach so far. As always, I  
>> might
>> not see the big picture... I just hope this will be useful in some
>> way, even if it's not what you envisioned.

OK well thats not bad. also im glad you are getting familiarized with  
ORM internals, since there are very few who have ventured in there so  
far.  But here some bigger picture things:

- you have an aggregate function there.  wheres the GROUP BY ? not  
just of the main table's columns but any other columns named for  
eager loads.
- it only works for scalars.  what about statements that return lists ?
- it doesnt figure out any kind of join conditions to the parent  
table.  what happens when a polymorphically loading mapper tries to  
use it  (or any of the other myriad bizarro things that happen with  
inheritance)?
- the biggest picture not here - its read only !
- we already have a way to do the above - map to a select statement,  
thereby forcing the user to figure out GROUP BY, polymorphic loading,  
etc., also produces an encapsulated statement which eager loaders,  
LIMIT/OFFSET etc. criterion can be more readily tacked onto.

Since you have built upon interfaces that I consider to be public so  
this is definitely at least a decent recipe.  im not sold on it as a  
core feature though since its scope is too narrow compared to what  
people will expect from it.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-25 Thread Gaetan de Menten
It's better with the attachments (the actual patch and a small
demonstration/test file)...

On 4/25/07, Gaetan de Menten <[EMAIL PROTECTED]> wrote:
> Ok, I'm quite a bit stubborn at times, so I implemented this the way I
> thought because I think it makes much more sense this way.
>
> Attached is an experimental (as usual) patch to add a
> StatementProperty, so that you can define stuff like:
>
> mapper(Tag, tags_table, properties={
> 'query_score': StatementProperty((tags_table.c.score1 *
> tags_table.c.score2).label('tag_score'), Float()),
> })
>
> or even:
>
> user_score = select([func.sum(tags_table.c.score1 *
>   tags_table.c.score2)],
> tags_table.c.user_id == users_table.c.id,
> scalar=True).label('user_score')
>
> mapper(User, users_table, properties={
> 'tags': relation(Tag, backref='user', lazy=False),
> 'query_score': StatementProperty(user_score, Float()),
> })
>
> I don't see what's wrong with this approach so far. As always, I might
> not see the big picture... I just hope this will be useful in some
> way, even if it's not what you envisioned.
>
> Some random remarks:
> - the statement you give must have a label (that seem pretty logical
> this way though)
> - you need to manually provide the type of the property you create
> (seem logical too). In a final patch, we'd probably want to also
> accept types in their class form (Float and Float()).
> - it works both for lazy and eagerloads (I struggled quite a bit to
> get those to work)
> - subselects pulled from a lazyload don't work though. But I think it
> should be quite easily fixable.
> - As always, I'm not attached to the names I've given.
>
> On 4/24/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
> >
> >
> > On Apr 24, 2007, at 4:44 AM, Gaetan de Menten wrote:
> >
> > >
> > >> the next way is to do it almost the same as Jonathan's blog says to
> > >> do it, except youd map the relation to some intermediary class like
> > >> "Score", and then use AssociationProxy to apply the "scalar" property
> > >> to the class.
> > >
> > > I thought about something like this but it felt sooo hacky I
> > > disregarded it quickly.
> > >
> >
> > this is probably the least hacky as like i said im probably going to
> > implement a feature that works just like this.
> >
>
>
>
> --
> Gaëtan de Menten
> http://openhex.org
>


-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---

from sqlalchemy import *
from sqlalchemy.orm.properties import StatementProperty

metadata = MetaData()

users_table = Table('users', metadata, 
Column('id', Integer, primary_key=True),
Column('name', String(16)),
)

tags_table = Table('tags', metadata,
Column('id', Integer, primary_key=True),
Column('user_id', Integer, ForeignKey("users.id")),
Column('score1', Float),
Column('score2', Float),
)

metadata.connect('sqlite:///')
metadata.create_all()

class User(object):
def __init__(self, name):
self.name = name

@property
def prop_score(self):
return sum(tag.prop_score for tag in self.tags)

class Tag(object):
def __init__(self, score1, score2):
self.score1 = score1
self.score2 = score2

@property
def prop_score(self):
return self.score1 * self.score2

# this doesn't work
tag_score = select([tags_table.c.score1 * tags_table.c.score2],
   scalar=True).label('tag_score')

mapper(Tag, tags_table, properties={
# this doesn't work. It seems like the inside of a select is not aliasized.
#'query_score': StatementProperty(tag_score, Float()),
'query_score': StatementProperty((tags_table.c.score1 *
tags_table.c.score2).label('tag_score'),
Float()),
})

user_score = select([func.sum(tags_table.c.score1 *
  tags_table.c.score2)],
tags_table.c.user_id == users_table.c.id,
scalar=True).label('user_score')

mapper(User, users_table, properties={
'tags': relation(Tag, backref='user'),
#'tags': relation(Tag, backref='user', lazy=False), 
'query_score': StatementProperty(user_score, Float()),
})


u1 = User('joe')
t1 = Tag(5.0, 3.0)
t2 = Tag(55.0, 1.0)
u1.tags = [t1, t2]

u2 = User('bar')
t3 = Tag(5.0, 4.0)
t4 = Tag(50.0, 1.0)
t5 = Tag(15.0, 2.0)
u2.tags = [t3, t4, t5]


session = create_session()
session.save(u1)
session.save(u2)

session.flush()
session.clear()

metadata.engine.echo = True

users = session.query(User).select()
print 

for user in users:
print "===%s===" % user.name
print "totals: que

[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-25 Thread Gaetan de Menten

Ok, I'm quite a bit stubborn at times, so I implemented this the way I
thought because I think it makes much more sense this way.

Attached is an experimental (as usual) patch to add a
StatementProperty, so that you can define stuff like:

mapper(Tag, tags_table, properties={
'query_score': StatementProperty((tags_table.c.score1 *
tags_table.c.score2).label('tag_score'), Float()),
})

or even:

user_score = select([func.sum(tags_table.c.score1 *
  tags_table.c.score2)],
tags_table.c.user_id == users_table.c.id,
scalar=True).label('user_score')

mapper(User, users_table, properties={
'tags': relation(Tag, backref='user', lazy=False),
'query_score': StatementProperty(user_score, Float()),
})

I don't see what's wrong with this approach so far. As always, I might
not see the big picture... I just hope this will be useful in some
way, even if it's not what you envisioned.

Some random remarks:
- the statement you give must have a label (that seem pretty logical
this way though)
- you need to manually provide the type of the property you create
(seem logical too). In a final patch, we'd probably want to also
accept types in their class form (Float and Float()).
- it works both for lazy and eagerloads (I struggled quite a bit to
get those to work)
- subselects pulled from a lazyload don't work though. But I think it
should be quite easily fixable.
- As always, I'm not attached to the names I've given.

On 4/24/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
>
>
> On Apr 24, 2007, at 4:44 AM, Gaetan de Menten wrote:
>
> >
> >> the next way is to do it almost the same as Jonathan's blog says to
> >> do it, except youd map the relation to some intermediary class like
> >> "Score", and then use AssociationProxy to apply the "scalar" property
> >> to the class.
> >
> > I thought about something like this but it felt sooo hacky I
> > disregarded it quickly.
> >
>
> this is probably the least hacky as like i said im probably going to
> implement a feature that works just like this.
>



-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-24 Thread Michael Bayer


On Apr 24, 2007, at 4:44 AM, Gaetan de Menten wrote:

>
>> the next way is to do it almost the same as Jonathan's blog says to
>> do it, except youd map the relation to some intermediary class like
>> "Score", and then use AssociationProxy to apply the "scalar" property
>> to the class.
>
> I thought about something like this but it felt sooo hacky I
> disregarded it quickly.
>

this is probably the least hacky as like i said im probably going to  
implement a feature that works just like this.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-24 Thread Gaetan de Menten

On 4/24/07, Gaetan de Menten <[EMAIL PROTECTED]> wrote:
> On 4/23/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
> >
> >
> > On Apr 23, 2007, at 3:49 PM, Gaetan de Menten wrote:
> >
> > > Hello there,
> > >
> > > In a mapped object, is there any way to map a scalar attribute to an
> > > arbitrary selectable/subquery?
> > >
> > > Jonathan Ellis demonstrated how to do that for relations on this page:
> > > http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html
> > >
> > > I'd like to do that for scalars.
> > >
> > > I've thought about using a property returning a query, but this still
> > > generates one query per user (my mapped object) and I need to do
> > > everything in one pass.
> > >
> > > See attached file for an example of what I'd like to do.
> > >
> > > I've the feeling it might already be possible but I don't see how. If
> > > it's not possible yet, do you have any pointer how I could implement
> > > that?
> > >
> >
> > there are probably three general ways to do what youre doing there.
>
> Thanks for the quick answer!
>
> > the oldest way is something i did in the zblog demo before SA 0.1 was
> > released, which is that you map to the full query you want:
> >
> > s = select([users_table, func.sum(tags_table.c.score1 *
> > tags_table.c.score2).label('score')],
> > users_table.c.user_id==tags_table.c.user_id, group_by=[c for c in
> > users_table.c])
> >
> > mapper(User, s)
> >
> > the effect above is that your func() becomes another ColumnProperty.
>
> That's what I was looking for. So simple... and I didn't think of it. Damn...

Hmmm, on second thought, it's not enough for my needs. I need to be
able to defer that "column" and undefer it per query. I know I could
use several mappers with entity_names but since I'll have several such
"columns", it'll be too much trouble to create an alternate mapper for
each and every possible combination of those "columns" being deferred
or not. So I guess I'll need to use the ugly intermediary class
solution for now.

-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-24 Thread Gaetan de Menten

On 4/23/07, Michael Bayer <[EMAIL PROTECTED]> wrote:
>
>
> On Apr 23, 2007, at 3:49 PM, Gaetan de Menten wrote:
>
> > Hello there,
> >
> > In a mapped object, is there any way to map a scalar attribute to an
> > arbitrary selectable/subquery?
> >
> > Jonathan Ellis demonstrated how to do that for relations on this page:
> > http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html
> >
> > I'd like to do that for scalars.
> >
> > I've thought about using a property returning a query, but this still
> > generates one query per user (my mapped object) and I need to do
> > everything in one pass.
> >
> > See attached file for an example of what I'd like to do.
> >
> > I've the feeling it might already be possible but I don't see how. If
> > it's not possible yet, do you have any pointer how I could implement
> > that?
> >
>
> there are probably three general ways to do what youre doing there.

Thanks for the quick answer!

> the oldest way is something i did in the zblog demo before SA 0.1 was
> released, which is that you map to the full query you want:
>
> s = select([users_table, func.sum(tags_table.c.score1 *
> tags_table.c.score2).label('score')],
> users_table.c.user_id==tags_table.c.user_id, group_by=[c for c in
> users_table.c])
>
> mapper(User, s)
>
> the effect above is that your func() becomes another ColumnProperty.

That's what I was looking for. So simple... and I didn't think of it. Damn...

> the next way is to do it almost the same as Jonathan's blog says to
> do it, except youd map the relation to some intermediary class like
> "Score", and then use AssociationProxy to apply the "scalar" property
> to the class.

I thought about something like this but it felt sooo hacky I
disregarded it quickly.

> I might put a built-in feature in sa for "scalar"
> properties that does this, automatically creating an anonymous class
> for the intermediaryso that would be the closest to a "scalar
> relation".

A built-in thing would be great, but I don't see the point in using an
intermediary class at all. Wouldn't it be possible to "just" skip the
"make an instance out of the value" part and be done with it (more
like in your first solution)? It's probably no as easy as I make it
sound but it really feels like a better solution.

-- 
Gaëtan de Menten
http://openhex.org

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Selectable/subquery for a (scalar) column?

2007-04-23 Thread Michael Bayer


On Apr 23, 2007, at 3:49 PM, Gaetan de Menten wrote:

> Hello there,
>
> In a mapped object, is there any way to map a scalar attribute to an
> arbitrary selectable/subquery?
>
> Jonathan Ellis demonstrated how to do that for relations on this page:
> http://spyced.blogspot.com/2007/01/why-sqlalchemy-impresses-me.html
>
> I'd like to do that for scalars.
>
> I've thought about using a property returning a query, but this still
> generates one query per user (my mapped object) and I need to do
> everything in one pass.
>
> See attached file for an example of what I'd like to do.
>
> I've the feeling it might already be possible but I don't see how. If
> it's not possible yet, do you have any pointer how I could implement
> that?
>

there are probably three general ways to do what youre doing there.   
the oldest way is something i did in the zblog demo before SA 0.1 was  
released, which is that you map to the full query you want:

s = select([users_table, func.sum(tags_table.c.score1 *  
tags_table.c.score2).label('score')],  
users_table.c.user_id==tags_table.c.user_id, group_by=[c for c in  
users_table.c])

mapper(User, s)

the effect above is that your func() becomes another ColumnProperty.

the next way is to do it almost the same as Jonathan's blog says to  
do it, except youd map the relation to some intermediary class like  
"Score", and then use AssociationProxy to apply the "scalar" property  
to the class.   I might put a built-in feature in sa for "scalar"  
properties that does this, automatically creating an anonymous class  
for the intermediaryso that would be the closest to a "scalar  
relation".

the third way is not as slick but is to use add_column() on query:

session.query(User).join('tags').add_column(func.sum 
(tags_table.c.score1 * tags_table.c.score2).label('score'))).group_by 
([c for c in users_table.c])

which will give you back tuples of (User, int).




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---