From bb6ec17708e56170bcccf7e32703d0ba37b160d2 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 22 Feb 2008 23:17:15 +0000 Subject: - the value of a bindparam() can be a callable, in which case it's evaluated at statement execution time to get the value. - expressions used in filter(), filter_by() and others, when they make usage of a clause generated from a relation using the identity of a child object (e.g. filter(Parent.child==)), evaluate the actual primary key value of at execution time so that the autoflush step of the Query can complete, thereby populating the PK value of in the case that was pending. - cleanup of attributes.get_committed_value() to never return the NO_VALUE value; evaluates to None --- lib/sqlalchemy/orm/attributes.py | 5 ++++- lib/sqlalchemy/orm/strategies.py | 4 +++- lib/sqlalchemy/orm/unitofwork.py | 4 ++-- lib/sqlalchemy/sql/compiler.py | 13 +++++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 5cc9cb309..298a7f511 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -246,7 +246,10 @@ class AttributeImpl(object): """return the unchanged value of this attribute""" if self.key in state.committed_state: - return state.committed_state.get(self.key) + if state.committed_state[self.key] is NO_VALUE: + return None + else: + return state.committed_state.get(self.key) else: return self.get(state) diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index bdc8ab9a9..81a5895f4 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -294,7 +294,9 @@ class LazyLoader(AbstractRelationLoader): mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent if bindparam.key in bind_to_col: # use the "committed" (database) version to get query column values - bindparam.value = mapper._get_committed_attr_by_column(instance, bind_to_col[bindparam.key]) + # also its a deferred value; so that when used by Query, the committed value is used + # after an autoflush occurs + bindparam.value = lambda: mapper._get_committed_attr_by_column(instance, bind_to_col[bindparam.key]) return visitors.traverse(criterion, clone=True, visit_bindparam=visit_bindparam) def _lazy_none_clause(self, reverse_direction=False): diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index e60b22043..48b6ea4cb 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -136,8 +136,8 @@ class UnitOfWork(object): delattr(state, 'insert_order') o = state.obj() - # prevent against last minute dereferences of "dirty" - # objects TODO: identify a code path where state.obj() is None + # prevent against last minute dereferences of the object + # TODO: identify a code path where state.obj() is None if o is not None: self.identity_map[state.dict['_instance_key']] = o state.commit_all() diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 8d8cfa38f..c5ff974e5 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -213,10 +213,19 @@ class DefaultCompiler(engine.Compiled): pd[name] = params[paramname] break else: - pd[name] = bindparam.value + if callable(bindparam.value): + pd[name] = bindparam.value() + else: + pd[name] = bindparam.value return pd else: - return dict([(self.bind_names[bindparam], bindparam.value) for bindparam in self.bind_names]) + pd = {} + for bindparam in self.bind_names: + if callable(bindparam.value): + pd[self.bind_names[bindparam]] = bindparam.value() + else: + pd[self.bind_names[bindparam]] = bindparam.value + return pd params = property(construct_params) -- cgit v1.2.1