diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-09-22 16:55:36 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-09-22 16:55:36 +0000 |
commit | 6b0a907fbdd33b9d9333ec1b72287580a2568d07 (patch) | |
tree | 89303fa82c0e239ea855ff7f19f0f7a1c8a27e03 /lib/sqlalchemy/orm/dynamic.py | |
parent | 7f6bf93da869a5b59c53d0d10a50da3c23c4b738 (diff) | |
download | sqlalchemy-6b0a907fbdd33b9d9333ec1b72287580a2568d07.tar.gz |
- merged sa_entity branch. the big change here is the attributes system
deals primarily with the InstanceState and almost never with the instrumented object
directly. This reduces lookups and complexity since we need the state for just about
everything, now its the one place for everything internally.
we also merged the new weak referencing identity map, which will go out in beta6 and
we'll see how that goes !
Diffstat (limited to 'lib/sqlalchemy/orm/dynamic.py')
-rw-r--r-- | lib/sqlalchemy/orm/dynamic.py | 79 |
1 files changed, 40 insertions, 39 deletions
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py index aa5105150..1b91bd977 100644 --- a/lib/sqlalchemy/orm/dynamic.py +++ b/lib/sqlalchemy/orm/dynamic.py @@ -6,32 +6,30 @@ from sqlalchemy.orm import attributes, object_session from sqlalchemy.orm.query import Query from sqlalchemy.orm.mapper import has_identity, object_mapper -class DynamicCollectionAttribute(attributes.InstrumentedAttribute): +class DynamicAttributeImpl(attributes.AttributeImpl): def __init__(self, class_, attribute_manager, key, typecallable, target_mapper, **kwargs): - super(DynamicCollectionAttribute, self).__init__(class_, attribute_manager, key, typecallable, **kwargs) + super(DynamicAttributeImpl, self).__init__(class_, attribute_manager, key, typecallable, **kwargs) self.target_mapper = target_mapper - def get(self, obj, passive=False): + def get(self, state, passive=False): if passive: - return self.get_history(obj, passive=True).added_items() + return self.get_history(state, passive=True).added_items() else: - return AppenderQuery(self, obj) + return AppenderQuery(self, state) - def commit_to_state(self, state, obj, value=attributes.NO_VALUE): + def commit_to_state(self, state, value=attributes.NO_VALUE): # we have our own AttributeHistory therefore dont need CommittedState # instead, we reset the history stored on the attribute - obj.__dict__[self.key] = CollectionHistory(self, obj) + state.dict[self.key] = CollectionHistory(self, state) - def get_collection(self, obj, user_data=None): - return self.get_history(obj)._added_items + def get_collection(self, state, user_data=None): + return self.get_history(state)._added_items - def set(self, obj, value, initiator): + def set(self, state, value, initiator): if initiator is self: return - state = obj._state - - old_collection = self.get(obj).assign(value) + old_collection = self.get(state).assign(value) # TODO: emit events ??? state.modified = True @@ -39,35 +37,36 @@ class DynamicCollectionAttribute(attributes.InstrumentedAttribute): def delete(self, *args, **kwargs): raise NotImplementedError() - def get_history(self, obj, passive=False): + def get_history(self, state, passive=False): try: - return obj.__dict__[self.key] + return state.dict[self.key] except KeyError: - obj.__dict__[self.key] = c = CollectionHistory(self, obj) + state.dict[self.key] = c = CollectionHistory(self, state) return c - def append(self, obj, value, initiator): + def append(self, state, value, initiator): if initiator is not self: - self.get_history(obj)._added_items.append(value) - self.fire_append_event(obj, value, self) + self.get_history(state)._added_items.append(value) + self.fire_append_event(state, value, self) - def remove(self, obj, value, initiator): + def remove(self, state, value, initiator): if initiator is not self: - self.get_history(obj)._deleted_items.append(value) - self.fire_remove_event(obj, value, self) + self.get_history(state)._deleted_items.append(value) + self.fire_remove_event(state, value, self) class AppenderQuery(Query): - def __init__(self, attr, instance): + def __init__(self, attr, state): super(AppenderQuery, self).__init__(attr.target_mapper, None) - self.instance = instance + self.state = state self.attr = attr def __session(self): - sess = object_session(self.instance) - if sess is not None and self.instance in sess and sess.autoflush: + instance = self.state.obj() + sess = object_session(instance) + if sess is not None and instance in sess and sess.autoflush: sess.flush() - if not has_identity(self.instance): + if not has_identity(instance): return None else: return sess @@ -75,21 +74,21 @@ class AppenderQuery(Query): def __len__(self): sess = self.__session() if sess is None: - return len(self.attr.get_history(self.instance)._added_items) + return len(self.attr.get_history(self.state)._added_items) else: return self._clone(sess).count() def __iter__(self): sess = self.__session() if sess is None: - return iter(self.attr.get_history(self.instance)._added_items) + return iter(self.attr.get_history(self.state)._added_items) else: return iter(self._clone(sess)) def __getitem__(self, index): sess = self.__session() if sess is None: - return self.attr.get_history(self.instance)._added_items.__getitem__(index) + return self.attr.get_history(self.state)._added_items.__getitem__(index) else: return self._clone(sess).__getitem__(index) @@ -97,39 +96,41 @@ class AppenderQuery(Query): # note we're returning an entirely new Query class instance here # without any assignment capabilities; # the class of this query is determined by the session. + instance = self.state.obj() if sess is None: - sess = object_session(self.instance) + sess = object_session(instance) if sess is None: try: - sess = object_mapper(self.instance).get_session() + sess = object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key)) - return sess.query(self.attr.target_mapper).with_parent(self.instance) + return sess.query(self.attr.target_mapper).with_parent(instance) def assign(self, collection): - if has_identity(self.instance): + instance = self.state.obj() + if has_identity(instance): oldlist = list(self) else: oldlist = [] - self.attr.get_history(self.instance).replace(oldlist, collection) + self.attr.get_history(self.state).replace(oldlist, collection) return oldlist def append(self, item): - self.attr.append(self.instance, item, None) + self.attr.append(self.state, item, None) def remove(self, item): - self.attr.remove(self.instance, item, None) + self.attr.remove(self.state, item, None) class CollectionHistory(attributes.AttributeHistory): """Overrides AttributeHistory to receive append/remove events directly.""" - def __init__(self, attr, obj): + def __init__(self, attr, state): self._deleted_items = [] self._added_items = [] self._unchanged_items = [] - self._obj = obj + self._state = state def replace(self, olditems, newitems): self._added_items = newitems |