attached is an approach that uses just the tiniest amount of  
awareness of how a mapper works, to do the whole optimized loading  
scenario ahead of time, and you get an object with your two distinct  
"pro" and "con" relationships, no list decoration or anything  
needed.  the appropriateness of this approach comes from the fact  
that your optimization case is a load-time optimization, therefore  
put the complexity at load time (which is easier to deal with since  
it doesnt have to be concerned with collection mutability).


--~--~---------~--~----~------------~-------~--~----~
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 *

class SomeClass(object):pass

class Position(object):
    def __init__(self, data, type):
        self.data = data
        self.type = type

metadata = BoundMetaData('sqlite://', echo=True)

t1 = Table("t1", metadata, 
    Column('id', Integer, primary_key=True),
    Column('data', String(30)))
    
t2 = Table('t2', metadata, 
    Column('id', Integer, primary_key=True),
    Column('parent_id', Integer, ForeignKey('t1.id')),
    Column('data', String(30)),
    Column('type', String(20))
    )
metadata.create_all()

class MyExt(MapperExtension):
    def populate_instance(self, mapper, context, row, instance, identitykey, isnew):
        # tell the mapper to populate the instance like it always does
        mapper.populate_instance(context, instance, row, identitykey, isnew)
        
        # get the "row decorator" that will translate the eager loaded row to something
        # based off the columns in "t2"
        decorator = context.attributes[id(mapper.props['_positions'].strategy)]
        row = decorator(row)
        
        # determine pro or con - create instance and append to either collection
        if row[t2.c.type] == 'pro':
            instance.pro.append(class_mapper(Position)._instance(context, row, None))
        elif row[t2.c.type] == 'con':
            instance.con.append(class_mapper(Position)._instance(context, row, None))

        # alternatively!  get the instance that was just appended to _positions
        # if _positions[-1].type == 'pro':
        #  instance.pro.append(_positions[-1])
        #  ...etc
        
        # tell the calling mapper "populate_instance" is taken care of
        return None
        
mapper(SomeClass, t1, extension=MyExt(), properties={
    '_positions':relation(Position, lazy=False, viewonly=True),
    'pro':relation(Position, lazy=None, primaryjoin=and_(t1.c.id==t2.c.parent_id,t2.c.type=='pro')),
    'con':relation(Position, lazy=None, primaryjoin=and_(t1.c.id==t2.c.parent_id,t2.c.type=='con'))
})
mapper(Position, t2)

sess = create_session()
sc =SomeClass()
sc.pro.append(Position("tastes great", "pro"))
sc.pro.append(Position("less filling", "pro"))
sc.con.append(Position("beer sucks", "con"))
sess.save(sc)
sess.flush()
sess.clear()

sc = sess.query(SomeClass).get(sc.id)
assert [x.data for x in sc.pro] == ["tastes great", "less filling"]
assert [x.data for x in sc.con] == ["beer sucks"]

On Apr 16, 2007, at 8:00 PM, jason kirtland wrote:

>
> Michael wrote:
>> On Apr 12, 2007, at 2:03 PM, jason kirtland wrote:
>>> [...]
>>> This does work, but because relation updates are happening
>>> outside of the InstrumentedList (i.e. not on 'analysis'
>>> directly), I'm losing the events that would normally be
>>> triggered.  I don't think I can manually manage them either, as
>>> they're private __methods on InstrumentedList.
>>
>> some ideas which im not sure if theyd work, one is to not use
>> "collection_class" and to go with an approach that is more like
>> the   AssociationProxy - i.e. "pro" and "con" have special
>> collections on   them which proxy to the utlimate "associations"
>> colleciton, but on   top of the InstrumentedList instead of
>> underneath it the way   collection_class does.
>
> I've got a new implementation that uses this approach and it does
> work- but it is even more complex.  If the InstrumentedCollection
> refactor (#213) allows implementors to choose when to fire add/del
> events I think this sort of pattern can be made pretty simple.
>
> On that front, I think it would be super useful if future
> InstrumentedCollection classes have access to their relation()
> arguments- e.g. a DRY ordered collection that keys off the
> relation's order_by.  A chance to error out at definition time
> would be useful too.
>
> -jek
>
>
> --~--~---------~--~----~------------~-------~--~----~
> 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- 
> [EMAIL PROTECTED]
> For more options, visit this group at http://groups.google.com/ 
> group/sqlalchemy?hl=en
> -~----------~----~----~----~------~----~------~--~---
>

Reply via email to