[sqlalchemy] Re: Has anyone implemented a dict of lists collection_class?

2008-02-16 Thread Michael Bayer

oh, heres a second version that fixes list.__setitem__.

the operations here are not terribly efficient but you could build  
better caching scenarios if needed.

from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData()

objects = Table('objects', metadata,
 Column('id', Integer, primary_key=True),
 Column('name', String(50), nullable=False)
)

object_dict_of_lists = Table('object_dict_of_lists', metadata,
 Column('id', Integer, primary_key=True),
 Column('object_id', Integer, ForeignKey('objects.id')),
 Column('key', String(50), nullable=False),
 Column('data', String(50), nullable=False)
 )

engine = create_engine(sqlite:///:memory:, echo=True)
metadata.bind = engine

metadata.create_all()

class Object(object):
 def __init__(self, name, data=None):
 self.name = name
 if data:
 self.data = data

class DictOfListElement(object):
 def __init__(self, key, data):
 self.key = key
 self.data = data

mapper(Object, objects, properties={
 '_data':relation(DictOfListElement)
})

mapper(DictOfListElement, object_dict_of_lists)

class ListAdapter(object):
 def __init__(self, parent, key):
 self.__parent = parent
 self.__key = key

 def __cached(self):
 try:
 return self.__cached_data
 except AttributeError:
 self.__cached_data = [item.data for item in  
self.__parent._data if item.key == self.__key]
 return self.__cached_data
 __cached = property(__cached)

 def __iter__(self):
 return iter(self.__cached)

 def __eq__(self, other):
 return list(self) == list(other)

 def __repr__(self):
 return repr(list(self))

 def append(self, item):
 self.__parent._data.append(DictOfListElement(self.__key, item))
 self.__cached.append(item)

 def __getitem__(self, index):
 return self.__cached[index]

 def __setitem__(self, index, value):
 [item for item in self.__parent._data if item.key ==  
self.__key][index].data = value
 self.__cached[index] = value

 # other list like methods

class DictAdapterAttribute(object):
 def __get__(self, instance, owner):
 if instance is None:
 return self
 class DictAdapter(object):
 def __getitem__(self, key):
 return ListAdapter(instance, key)
 def keys(self):
 return iter(set([item.key for item in instance._data]))
 def __eq__(self, other):
 return dict(self) == dict(other)
 def __repr__(self):
 return repr(dict(self))

 # other dict like methods

 return DictAdapter()

 def __set__(self, instance, somedict):
 l =[]
 for key, somelist in somedict.items():
 for item in somelist:
 l.append(DictOfListElement(key, item))
 instance._data = l

Object.data = DictAdapterAttribute()


sess = create_session()

obj1 = Object('object1', {
 'key1':['key1_one', 'key1_two', 'key1_three'],
 'key2':['key2_one', 'key2_two', 'key2_three'],
 'key3':['key3_one', 'key3_two', 'key3_three'],
})

sess.save(obj1)
sess.flush()
sess.clear()

obj1 = sess.query(Object).get(obj1.id)

assert obj1.data['key2'] == ['key2_one', 'key2_two', 'key2_three'],  
obj1.data['key2']

obj1.data['key3'].append('key3_four')
obj1.data['key2'][1] = 'key2_two_modified'
sess.flush()

sess.clear()

obj1 = sess.query(Object).get(obj1.id)

assert obj1.data == {
 'key1':['key1_one', 'key1_two', 'key1_three'],
 'key2':['key2_one', 'key2_two_modified', 'key2_three'],
 'key3':['key3_one', 'key3_two', 'key3_three', 'key3_four'],
}

print obj1.data




--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-16 Thread Michael Bayer

yet another adjustment to ListAdapter...

class ListAdapter(object):
 def __init__(self, parent, key):
 self.__parent = parent
 self.__key = key

 def __cached(self):
 try:
 return self.__cached_data
 except AttributeError:
 self.__cached_data = [item.data for item in  
self.__parent._data if item.key == self.__key]
 return self.__cached_data
 __cached = property(__cached)

 def __delcached(self):
 try:
 del self.__cached_data
 except AttributeError:
 pass

 def __iter__(self):
 return iter(self.__cached)

 def __eq__(self, other):
 return list(self) == list(other)

 def __repr__(self):
 return repr(list(self))

 def append(self, item):
 self.__delcached()
 self.__parent._data.append(DictOfListElement(self.__key, item))

 def __getitem__(self, index):
 return self.__cached[index]

 def __setitem__(self, index, value):
self.__delcached()
 [item for item in self.__parent._data if item.key ==  
self.__key][index].data = value

 # other list like methods



--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-16 Thread Michael Bayer

also, it would take a lot more experimentation but maybe the @appender  
and @remover methods could be useful here, just so that the cached  
view of the data can be maintained as the data is retrieved from the  
DB.Maybe its just my thought process (also since i didnt write the  
collections classes) to do it entirely in-Python first, then look  
for deeper ORM integration second (i.e. actually use collection_class  
to make the approach more efficient).



--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-16 Thread Eric Ongerth

It occurs to me that a near analogue to this would be... storing a
collection of one man's children by different mothers.  While it's
somewhat useful to have a collection of the guy's children... what if
you want to look up his children by just one mother, or by each mother
in turn.  There's an easy workaround, just looking up the list of his
children then asking each child whom its mother is.  But that's not
nearly as efficient as having his children collection indexed by
mother.  That's basically all I'm trying to do here (though totally
not the problem domain i'm working in!)

Thanks again.

On Feb 16, 2:23 pm, Eric Ongerth [EMAIL PROTECTED] wrote:
 Awesome -- Mike, that's a heck of a great response and I'll try it all
 out.

 But one quick reply to your very first comment, before I go out and do
 so.

 You wrote:

 quote
 Im not sure you're going to be able to use the collection classes
 here
 - those are all built on the notion of mapped elements being
 appended and removed from a collection.but here you are
 appending and removing further subsets of elements.
 /quote

 Actually, I don't need or want the ability to append or remove entire
 subsets.  There will only be a single element appended or removed at a
 time.  It's just that when a Bar is added to one of these children
 collections, I want it to be filed under a dict slot whose key happens
 to be the Bar's parent attribute.  It should join all the other
 elements stored in a list which holds the contents of that dict slot.
 Know what I mean?  Similarly, when I remove a Bar from one of these
 children collections, we look at its parent attribute to determine
 which slot in the collection it should be removed from, then it gets
 removed from the list which holds the contents of that dict slot.
 (Sorry, nonstandard use of the word slot here, just to avoid any
 ambiguity in using the word value to speak of what's on the right
 side of the colon in a dict entry).

 My guess is that making this clear, changes your idea of what I'm
 trying to achieve.  Let me know if that's the case.  If not, I need to
 read more deeply into what you wrote.  In either case I'm going to try
 out your examples.  Thanks a bundle for the length and quality of
 response.

 On Feb 16, 2:03 pm, Michael Bayer [EMAIL PROTECTED] wrote:

  yet another adjustment to ListAdapter...

  class ListAdapter(object):
   def __init__(self, parent, key):
   self.__parent = parent
   self.__key = key

   def __cached(self):
   try:
   return self.__cached_data
   except AttributeError:
   self.__cached_data = [item.data for item in
  self.__parent._data if item.key == self.__key]
   return self.__cached_data
   __cached = property(__cached)

   def __delcached(self):
   try:
   del self.__cached_data
   except AttributeError:
   pass

   def __iter__(self):
   return iter(self.__cached)

   def __eq__(self, other):
   return list(self) == list(other)

   def __repr__(self):
   return repr(list(self))

   def append(self, item):
   self.__delcached()
   self.__parent._data.append(DictOfListElement(self.__key, item))

   def __getitem__(self, index):
   return self.__cached[index]

   def __setitem__(self, index, value):
  self.__delcached()
   [item for item in self.__parent._data if item.key ==
  self.__key][index].data = value

   # other list like methods
--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-15 Thread Eric Ongerth

In case I didn't make it clear enough -- I've already done the
following:

'children': relation(Bar,
collection_class=attribute_mapped_collection('foo'),
backref=backref('parent', remote_side=[bars.c.id])) } )

And that worked great -- if I only needed to have up to a SINGLE child
per bar per foo.  Because the dict in attribute_mapped_collection
expects scalar keys and scalar values, right?  It's not set up to
collect a whole list of values per key.  And that is what I need.  Any
given Foo is only going to appear once in the keys of any given Bar's
children DictOfLists, of course.  But the values mapped to that given
Foo need to be a list of Bars of any length.  Any given Bar will have
1..n children in the bars table; each of these child Bars will be
related to a single Foo, but the total number of Foos is  n, so a
parent Bar might have a number of child Bars for a given Foo, while
only having zero or one single child Bar for some other Foo.

There, I think that tells it more completely.  Sorry for the
metasyntactic variables.


On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote:
 If anyone out there has already implemented a custom DictOfLists
 collection class to map scalar keys to lists of values, I would be
 grateful for the opportunity to avoid reinventing the wheel.  If not,
 I guess I'll start working on it.

 I've experimented successfully with attribute_mapped_collection and
 column_mapped_collection and they work just great.  However, instead
 of mapping keys to single values, I need some of my mapper relations
 to map to a list of values.

 Here is more of the picture, for example.

 foos = Table('foos', metadata,
 Column('id', Integer, primary_key=True),
 Column('name', String(20)))

 bars = Table('bars', metadata,
 Column('id', Integer, primary_key=True),
 Column('foo_id', Integer, ForeignKey('foos.id')),
 Column('value', String(20)),
 Column('parent_id', Integer, ForeignKey('bars.id')))

 class Foo(object): pass
 class Bar(object): pass

 mapper(Foo, foos)

 mapper(Bar, bars, properties={
 'foo':relation(Foo, uselist=False, backref='bars'),
 'children':relation(Bar,
 backref=backref('parent',
 remote_side=[bars.c.id]))

 })

 ... So we have a relation of 1 Foo : many Bars.  And within the Bars
 we also have 'adjacency' (tree-like) relations between the various
 rows of the 'bars' table.  A Bar's children are kept in the standard
 list-like collection class.

 But what I really need is a *dict* instead of a list.  Ok, SA already
 takes care of that.  But I actually need a list-like collection to
 appear as the value for each key in the dict.  Specifically, I need
 each Bar to be able to have stored children *per Foo*.  And not keyed
 by the parent's foo, but the child's foo.

 Does that make sense?  I'll be working on this immediately, but if
 anyone can shorten my path to getting this straight I'd be very glad.
 I'm beginning to work out the use of a custom collection_class for
 this, but I haven't done all that much with metaclassing and the way
 forward isn't obvious (the SA instructions about this seem to assume
 the programmer is pretty experienced with custom subclassing etc.)
--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-15 Thread Eric Ongerth

Ok, I tried subclassing MappedCollection and it seems like I did all
right with my made-up appender, remover, and iterator functions.  At
least I fixed various errors and got this to at least function as the
collection_class for the mapper shown above.

But I can't figure out how to tell my DictOfLists to return a list
instead of a single item.  So there's a place where I'm trying to say:
for child in some_bar.children[some_foo]:
blah(child)
etc.

Sadly, while some_bar.children[some_foo] at least returns something,
it returns a scalar Bar instance, not a list of Bars as I want it too.

What's the next step?



On Feb 15, 8:21 pm, Eric Ongerth [EMAIL PROTECTED] wrote:
 In case I didn't make it clear enough -- I've already done the
 following:

 'children': relation(Bar,
 collection_class=attribute_mapped_collection('foo'),
 backref=backref('parent', remote_side=[bars.c.id])) } )

 And that worked great -- if I only needed to have up to a SINGLE child
 per bar per foo.  Because the dict in attribute_mapped_collection
 expects scalar keys and scalar values, right?  It's not set up to
 collect a whole list of values per key.  And that is what I need.  Any
 given Foo is only going to appear once in the keys of any given Bar's
 children DictOfLists, of course.  But the values mapped to that given
 Foo need to be a list of Bars of any length.  Any given Bar will have
 1..n children in the bars table; each of these child Bars will be
 related to a single Foo, but the total number of Foos is  n, so a
 parent Bar might have a number of child Bars for a given Foo, while
 only having zero or one single child Bar for some other Foo.

 There, I think that tells it more completely.  Sorry for the
 metasyntactic variables.

 On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote:

  If anyone out there has already implemented a custom DictOfLists
  collection class to map scalar keys to lists of values, I would be
  grateful for the opportunity to avoid reinventing the wheel.  If not,
  I guess I'll start working on it.

  I've experimented successfully with attribute_mapped_collection and
  column_mapped_collection and they work just great.  However, instead
  of mapping keys to single values, I need some of my mapper relations
  to map to a list of values.

  Here is more of the picture, for example.

  foos = Table('foos', metadata,
  Column('id', Integer, primary_key=True),
  Column('name', String(20)))

  bars = Table('bars', metadata,
  Column('id', Integer, primary_key=True),
  Column('foo_id', Integer, ForeignKey('foos.id')),
  Column('value', String(20)),
  Column('parent_id', Integer, ForeignKey('bars.id')))

  class Foo(object): pass
  class Bar(object): pass

  mapper(Foo, foos)

  mapper(Bar, bars, properties={
  'foo':relation(Foo, uselist=False, backref='bars'),
  'children':relation(Bar,
  backref=backref('parent',
  remote_side=[bars.c.id]))

  })

  ... So we have a relation of 1 Foo : many Bars.  And within the Bars
  we also have 'adjacency' (tree-like) relations between the various
  rows of the 'bars' table.  A Bar's children are kept in the standard
  list-like collection class.

  But what I really need is a *dict* instead of a list.  Ok, SA already
  takes care of that.  But I actually need a list-like collection to
  appear as the value for each key in the dict.  Specifically, I need
  each Bar to be able to have stored children *per Foo*.  And not keyed
  by the parent's foo, but the child's foo.

  Does that make sense?  I'll be working on this immediately, but if
  anyone can shorten my path to getting this straight I'd be very glad.
  I'm beginning to work out the use of a custom collection_class for
  this, but I haven't done all that much with metaclassing and the way
  forward isn't obvious (the SA instructions about this seem to assume
  the programmer is pretty experienced with custom subclassing etc.)
--~--~-~--~~~---~--~~
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: Has anyone implemented a dict of lists collection_class?

2008-02-15 Thread Eric Ongerth

Incidentally, I tried mocking this all up entirely outside of SA by
creating a DictOfLists class that subclasses the basic 'dict'.  That
worked fine, returns lists, adds and removes as desired, handles
everything as one would expect.  So I don't think I'm fumbling with
the basic mechanics of it.


On Feb 15, 11:41 pm, Eric Ongerth [EMAIL PROTECTED] wrote:
 Ok, I tried subclassing MappedCollection and it seems like I did all
 right with my made-up appender, remover, and iterator functions.  At
 least I fixed various errors and got this to at least function as the
 collection_class for the mapper shown above.

 But I can't figure out how to tell my DictOfLists to return a list
 instead of a single item.  So there's a place where I'm trying to say:
 for child in some_bar.children[some_foo]:
 blah(child)
 etc.

 Sadly, while some_bar.children[some_foo] at least returns something,
 it returns a scalar Bar instance, not a list of Bars as I want it too.

 What's the next step?

 On Feb 15, 8:21 pm, Eric Ongerth [EMAIL PROTECTED] wrote:

  In case I didn't make it clear enough -- I've already done the
  following:

  'children': relation(Bar,
  collection_class=attribute_mapped_collection('foo'),
  backref=backref('parent', remote_side=[bars.c.id])) } )

  And that worked great -- if I only needed to have up to a SINGLE child
  per bar per foo.  Because the dict in attribute_mapped_collection
  expects scalar keys and scalar values, right?  It's not set up to
  collect a whole list of values per key.  And that is what I need.  Any
  given Foo is only going to appear once in the keys of any given Bar's
  children DictOfLists, of course.  But the values mapped to that given
  Foo need to be a list of Bars of any length.  Any given Bar will have
  1..n children in the bars table; each of these child Bars will be
  related to a single Foo, but the total number of Foos is  n, so a
  parent Bar might have a number of child Bars for a given Foo, while
  only having zero or one single child Bar for some other Foo.

  There, I think that tells it more completely.  Sorry for the
  metasyntactic variables.

  On Feb 15, 8:13 pm, Eric Ongerth [EMAIL PROTECTED] wrote:

   If anyone out there has already implemented a custom DictOfLists
   collection class to map scalar keys to lists of values, I would be
   grateful for the opportunity to avoid reinventing the wheel.  If not,
   I guess I'll start working on it.

   I've experimented successfully with attribute_mapped_collection and
   column_mapped_collection and they work just great.  However, instead
   of mapping keys to single values, I need some of my mapper relations
   to map to a list of values.

   Here is more of the picture, for example.

   foos = Table('foos', metadata,
   Column('id', Integer, primary_key=True),
   Column('name', String(20)))

   bars = Table('bars', metadata,
   Column('id', Integer, primary_key=True),
   Column('foo_id', Integer, ForeignKey('foos.id')),
   Column('value', String(20)),
   Column('parent_id', Integer, ForeignKey('bars.id')))

   class Foo(object): pass
   class Bar(object): pass

   mapper(Foo, foos)

   mapper(Bar, bars, properties={
   'foo':relation(Foo, uselist=False, backref='bars'),
   'children':relation(Bar,
   backref=backref('parent',
   remote_side=[bars.c.id]))

   })

   ... So we have a relation of 1 Foo : many Bars.  And within the Bars
   we also have 'adjacency' (tree-like) relations between the various
   rows of the 'bars' table.  A Bar's children are kept in the standard
   list-like collection class.

   But what I really need is a *dict* instead of a list.  Ok, SA already
   takes care of that.  But I actually need a list-like collection to
   appear as the value for each key in the dict.  Specifically, I need
   each Bar to be able to have stored children *per Foo*.  And not keyed
   by the parent's foo, but the child's foo.

   Does that make sense?  I'll be working on this immediately, but if
   anyone can shorten my path to getting this straight I'd be very glad.
   I'm beginning to work out the use of a custom collection_class for
   this, but I haven't done all that much with metaclassing and the way
   forward isn't obvious (the SA instructions about this seem to assume
   the programmer is pretty experienced with custom subclassing etc.)
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---