From: Mike Bayer Date: Wed, 7 Sep 2005 05:34:57 +0000 (+0000) Subject: moved dirty flags, dirty attributes to unitofwork X-Git-Tag: rel_0_1_0~781 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0336e1f5123047770f571c0a14c22ab2b766b4e1;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git moved dirty flags, dirty attributes to unitofwork --- diff --git a/lib/sqlalchemy/objectstore.py b/lib/sqlalchemy/objectstore.py index 7bcf00fd8f..b1e454e024 100644 --- a/lib/sqlalchemy/objectstore.py +++ b/lib/sqlalchemy/objectstore.py @@ -15,13 +15,53 @@ # along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""maintains all currently loaded objects in memory, +using the "identity map" pattern. Also provides a "unit of work" object which tracks changes +to objects so that they may be properly persisted within a transactional scope.""" + import thread +import sqlalchemy.util as util +import weakref def get_id_key(ident, class_, table, selectable): + """returns an identity-map key for use in storing/retrieving an item from the identity map, given + a tuple of the object's primary key values. + + ident - a tuple of primary key values corresponding to the object to be stored. these values + should be in the same order as the primary keys of the table + class_ - a reference to the object's class + table - a Table object where the object's primary fields are stored. + selectable - a Selectable object which represents all the object's column-based fields. this Selectable + may be synonymous with the table argument or can be a larger construct containing that table. + return value: a tuple object which is used as an identity key. + """ return (class_, table, tuple(ident)) def get_instance_key(object, class_, table, selectable): + """returns an identity-map key for use in storing/retrieving an item from the identity map, given + the object instance itself. + + object - the object to be stored. it is assumed that the object's primary key attributes are + populated. + class_ - a reference to the object's class + table - a Table object where the object's primary fields are stored. + selectable - a Selectable object which represents all the object's column-based fields. this Selectable + may be synonymous with the table argument or can be a larger construct containing that table. + return value: a tuple object which is used as an identity key. + """ return (class_, table, tuple([getattr(object, column.key, None) for column in selectable.primary_keys])) def get_row_key(row, class_, table, selectable): + """returns an identity-map key for use in storing/retrieving an item from the identity map, given + a result set row. + + row - a sqlalchemy.dbengine.RowProxy instance or other map corresponding result-set column + names to their values within a row. + class_ - a reference to the object's class + table - a Table object where the object's primary fields are stored. + selectable - a Selectable object which represents all the object's column-based fields. this Selectable + may be synonymous with the table argument or can be a larger construct containing that table. + return value: a tuple object which is used as an identity key. + """ return (class_, table, tuple([row[column.label] for column in selectable.primary_keys])) identity_map = {} @@ -34,6 +74,7 @@ def get(key): return val def put(key, obj, scope='thread'): + if isinstance(obj, dict): raise "cant put a dict in the object store" @@ -68,19 +109,52 @@ def has_key(key): class UnitOfWork: def __init__(self): - pass + self.dirty = util.HashSet() + self.clean = util.HashSet() + self.deleted = util.HashSet() + self.attribute_history = weakref.WeakKeyDictionary() + + def attribute_set(self, obj, key, value): + self.register_attribute(obj, key).setattr(value) + def attribute_deleted(self, obj, key, value): + self.register_attribute(obj, key).delattr(value) + + def register_attribute(self, obj, key): + try: + attributes = self.attribute_history[obj] + except KeyError: + attributes = self.attribute_history.setdefault(obj, {}) + try: + return attributes[key] + except KeyError: + return attributes.setdefault(key, util.PropHistory(obj.__dict__.get(key, None))) def register_clean(self, obj): - pass + self.clean.append(obj) + try: + del self.dirty[obj] + except KeyError: + pass def register_new(self, obj): pass def register_dirty(self, obj): - pass + self.dirty.append(obj) + try: + del self.clean[obj] + except KeyError: + pass + + def is_dirty(self, obj): + return self.dirty.contains(obj) def register_deleted(self, obj): pass + def commit(self): + for item in self.dirty: + self.clean.append(item) + self.dirty.clear() - \ No newline at end of file +uow = util.ScopedRegistry(lambda: UnitOfWork(), "thread") \ No newline at end of file