diff options
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 5 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 13 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/state.py | 31 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 4 |
6 files changed, 41 insertions, 20 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 5a6e24dfa..a8c525657 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1484,7 +1484,7 @@ class Mapper(object): ) if readonly: - _expire_state(state, readonly) + _expire_state(state, state.dict, readonly) # if specified, eagerly refresh whatever has # been expired. @@ -1524,7 +1524,7 @@ class Mapper(object): deferred_props = [prop.key for prop in [self._columntoproperty[c] for c in postfetch_cols]] if deferred_props: - _expire_state(state, deferred_props) + _expire_state(state, state.dict, deferred_props) # synchronize newly inserted ids from one table to the next # TODO: this still goes a little too often. would be nice to diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 8dbc6b3db..bb92f39e4 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -115,7 +115,7 @@ class ColumnProperty(StrategizedProperty): impl = dest_state.get_impl(self.key) impl.set(dest_state, dest_dict, value, None) else: - dest_state.expire_attributes([self.key]) + dest_state.expire_attributes(dest_dict, [self.key]) def get_col_value(self, column, value): return value @@ -636,7 +636,7 @@ class RelationProperty(StrategizedProperty): return if not "merge" in self.cascade: - dest_state.expire_attributes([self.key]) + dest_state.expire_attribute(dest_dict, [self.key]) return if self.key not in source_dict: diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index ed5535151..456f1f19c 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1873,8 +1873,9 @@ class Query(object): state.commit(dict_, list(to_evaluate)) - # expire attributes with pending changes (there was no autoflush, so they are overwritten) - state.expire_attributes(set(evaluated_keys).difference(to_evaluate)) + # expire attributes with pending changes + # (there was no autoflush, so they are overwritten) + state.expire_attributes(dict_, set(evaluated_keys).difference(to_evaluate)) elif synchronize_session == 'fetch': target_mapper = self._mapper_zero() diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 0e5e939b1..d5246bee0 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -289,14 +289,14 @@ class SessionTransaction(object): assert not self.session._deleted for s in self.session.identity_map.all_states(): - _expire_state(s, None, instance_dict=self.session.identity_map) + _expire_state(s, s.dict, None, instance_dict=self.session.identity_map) def _remove_snapshot(self): assert self._is_transaction_boundary if not self.nested and self.session.expire_on_commit: for s in self.session.identity_map.all_states(): - _expire_state(s, None, instance_dict=self.session.identity_map) + _expire_state(s, s.dict, None, instance_dict=self.session.identity_map) def _connection_for_bind(self, bind): self._assert_is_active() @@ -915,7 +915,7 @@ class Session(object): """Expires all persistent instances within this Session.""" for state in self.identity_map.all_states(): - _expire_state(state, None, instance_dict=self.identity_map) + _expire_state(state, state.dict, None, instance_dict=self.identity_map) def expire(self, instance, attribute_names=None): """Expire the attributes on an instance. @@ -936,14 +936,15 @@ class Session(object): raise exc.UnmappedInstanceError(instance) self._validate_persistent(state) if attribute_names: - _expire_state(state, attribute_names=attribute_names, instance_dict=self.identity_map) + _expire_state(state, state.dict, + attribute_names=attribute_names, instance_dict=self.identity_map) else: # pre-fetch the full cascade since the expire is going to # remove associations cascaded = list(_cascade_state_iterator('refresh-expire', state)) - _expire_state(state, None, instance_dict=self.identity_map) + _expire_state(state, state.dict, None, instance_dict=self.identity_map) for (state, m, o) in cascaded: - _expire_state(state, None, instance_dict=self.identity_map) + _expire_state(state, state.dict, None, instance_dict=self.identity_map) def prune(self): """Remove unreferenced instances cached in the identity map. diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 4bb9219f4..a9494a50e 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -239,9 +239,30 @@ class InstanceState(object): return set( key for key in self.manager.iterkeys() if key not in self.committed_state and key not in self.dict) - - def expire_attributes(self, attribute_names, instance_dict=None): - self.expired_attributes = set(self.expired_attributes) + + def expire_attribute_pre_commit(self, dict_, key): + """a fast expire that can be called by column loaders during a load. + + The additional bookkeeping is finished up in commit_all(). + + This method is actually called a lot with joined-table + loading, when the second table isn't present in the result. + + """ + # TODO: yes, this is still a little too busy. + # need to more cleanly separate out handling + # for the various AttributeImpls and the contracts + # they wish to maintain with their strategies + if not self.expired_attributes: + self.expired_attributes = set(self.expired_attributes) + + dict_.pop(key, None) + self.callables[key] = self + self.expired_attributes.add(key) + + def expire_attributes(self, dict_, attribute_names, instance_dict=None): + if not self.expired_attributes: + self.expired_attributes = set(self.expired_attributes) if attribute_names is None: attribute_names = self.manager.keys() @@ -258,7 +279,6 @@ class InstanceState(object): filter_deferred = True else: filter_deferred = False - dict_ = self.dict for key in attribute_names: impl = self.manager[key].impl @@ -354,8 +374,7 @@ class InstanceState(object): self.committed_state = {} self.pending = {} - - # unexpire attributes which have loaded + if self.expired_attributes: for key in self.expired_attributes.intersection(dict_): self.callables.pop(key, None) diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 5e81d33ca..4d5ec3da4 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -121,7 +121,7 @@ class ColumnLoader(LoaderStrategy): else: def new_execute(state, dict_, row, isnew): if isnew: - state.expire_attributes([key]) + state.expire_attribute_pre_commit(dict_, key) return new_execute, None log.class_logger(ColumnLoader) @@ -168,7 +168,7 @@ class CompositeColumnLoader(ColumnLoader): if c not in row: def new_execute(state, dict_, row, isnew): if isnew: - state.expire_attributes([key]) + state.expire_attribute_pre_commit(dict_, key) break else: def new_execute(state, dict_, row, isnew): |
