From: Mike Bayer Date: Sat, 24 Jan 2009 15:43:05 +0000 (+0000) Subject: moved the non-expire of unloaded deferred attributes into the attributes package X-Git-Tag: rel_0_5_2~1 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=febf00ea5d44e96117be882e7e125fd4e6115c59;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git moved the non-expire of unloaded deferred attributes into the attributes package --- diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 70b0738c95..729ab12772 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -160,7 +160,8 @@ class InstrumentedAttribute(QueryableAttribute): class _ProxyImpl(object): accepts_scalar_loader = False - + dont_expire_missing = False + def __init__(self, key): self.key = key @@ -230,7 +231,9 @@ class AttributeImpl(object): def __init__(self, class_, key, callable_, trackparent=False, extension=None, - compare_function=None, active_history=False, parent_token=None, **kwargs): + compare_function=None, active_history=False, parent_token=None, + dont_expire_missing=False, + **kwargs): """Construct an AttributeImpl. \class_ @@ -268,6 +271,11 @@ class AttributeImpl(object): Allows multiple AttributeImpls to all match a single owner attribute. + dont_expire_missing + if True, don't add an "expiry" callable to this attribute + during state.expire_attributes(None), if no value is present + for this key. + """ self.class_ = class_ self.key = key @@ -280,7 +288,8 @@ class AttributeImpl(object): self.is_equal = compare_function self.extensions = util.to_list(extension or []) self.active_history = active_history - + self.dont_expire_missing = dont_expire_missing + def hasparent(self, state, optimistic=False): """Return the boolean value of a `hasparent` flag attached to the given item. @@ -1006,12 +1015,19 @@ class InstanceState(object): attribute_names = self.manager.keys() self.expired = True self.modified = False + filter_deferred = True + else: + filter_deferred = False for key in attribute_names: + impl = self.manager[key].impl + if not filter_deferred or \ + not impl.dont_expire_missing or \ + key in self.dict: + self.expired_attributes.add(key) + if impl.accepts_scalar_loader: + self.callables[key] = self self.dict.pop(key, None) self.committed_state.pop(key, None) - self.expired_attributes.add(key) - if self.manager.get_impl(key).accepts_scalar_loader: - self.callables[key] = self def reset(self, key): """remove the given attribute and any callables associated with it.""" diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 6f125bc841..1cd8e055b0 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -776,11 +776,6 @@ class Mapper(object): raise sa_exc.InvalidRequestError("Mapper '%s' has no property '%s'" % (str(self), key)) return prop - @util.memoized_property - def _deferred_props(self): - return [p.key for p in self._props.values() if - isinstance(p, ColumnProperty) and getattr(p, 'deferred', False)] - @property def iterate_properties(self): """return an iterator of all MapperProperty objects.""" diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index ea8174726a..4fb6c18593 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1518,14 +1518,7 @@ class Session(object): return util.IdentitySet(self._new.values()) -def _expire_state(state, attribute_names): - if attribute_names is None: - state.expired = True - state.modified= False - # dont add unloaded deferred attributes to the list of attrs - attribute_names = set(state.manager.keys()).\ - difference([k for k in state.manager.mapper._deferred_props if k not in state.dict]) - state.expire_attributes(attribute_names) +_expire_state = attributes.InstanceState.expire_attributes UOWEventHandler = unitofwork.UOWEventHandler diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 2a78c90de9..91b2f359a9 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -228,6 +228,7 @@ class DeferredColumnLoader(LoaderStrategy): copy_function=self.columns[0].type.copy_value, mutable_scalars=self.columns[0].type.is_mutable(), callable_=self.class_level_loader, + dont_expire_missing=True ) def setup_query(self, context, entity, path, adapter, only_load_props=None, **kwargs):