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.

Reply via email to