On Tue, Dec 6, 2011 at 12:38 PM, Daniel Nouri <daniel.no...@gmail.com> wrote: > On Mon, Dec 5, 2011 at 11:30 PM, Michael Bayer <mike...@zzzcomputing.com> > wrote: >> On Dec 5, 2011, at 1:39 PM, Daniel Nouri wrote: >>> Thanks for your explanation. I haven't used hybrid a lot yet and this >>> helped me understand what it does and what not. >>> >>> Your last example that uses a 'with_transformation', i.e. a protocol >>> that I guess would amount to allowing to run the query through an >>> arbitrary function, is quite nice to read, and I'd definitely be a >>> user. Then again, there's nice enough alternatives for what I'm >>> trying to do, so I'll be fine without. :-) >> >> OK, well with_transformation is literally: >> >> def with_transformation(self, fn): >> return fn(self) >> >> so there's not much controversy there. I've added it and wrote up an >> example of how to combine this with a hybrid comparator, to produce two >> approaches for your problem (which just makes a nice example). It looks >> *interesting*, but I don't know how much this pattern would catch on - if >> it's one of those patterns that can keep expanding out or not. Check it >> out at: >> >> http://www.sqlalchemy.org/docs/orm/extensions/hybrid.html#building-transformers > > Awesome! Thanks for not only giving me a way to do this, but > basically solve my homework too. :-) > > I have to admit I only understood Comparators now. And why the need > for a 'with_transformation' on top of the Comparators. The way > GrandparentTransformer's functionality is put together using > 'with_transform' seems very elegant. > > The GrandparentTransformer in the second example that separates 'join' > from 'filter' seems interesting and the implementation slightly > easier, but the query part is definitely harder in a way that exposes > maybe a lot of what's going on behind the scenes. > > I imagine that novice users would also be tempted to think that they > can do "query.filter(Node.grandparent == Node(id=5))". Since the > "join" in your example doesn't affect the way that subsequent filters > work, I guess it's not useful for the user (doing the query) to know > if it's a transform or a filter, right? (I don't pretend I understand > the full scope of this, so wouldn't be surprised if this were a choice > of explicit over implicit or some such.)
Here's a little generalization of that GrandparentTransformer that I came up with. class ParentalTransformer(Comparator): def __init__(self, expression, level): super(ParentalTransformer, self).__init__(expression) self.level = level def operate(self, op, other): def transform(query): cls = Node for i in range(self.level-1): cls, prev_cls = aliased(cls), cls query = query.filter(cls.id==prev_cls.parent_id) return query.filter(op(cls.parent, other)) return transform This one tries to do arbitrary depths -- because in my real life example I needed three levels really (query on grand-grandparent). It also turned out that when using polymorphic subclasses of Node (my tree is really different types of Nodes), I had to use "Node" instead of "self.__clause_element__()", or else the generated query would assume that all nodes along the way were of the same type as "self.__clause_element__()". (I *think* this would apply to the example in the docs too if one were to use polymorphic.) Does this look right? :-) -- http://danielnouri.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 sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.