From e3e15357202d4c7918fe6a3b8d2d002e4ede3de2 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 1 Jun 2008 14:15:41 +0000 Subject: [PATCH] merged r4829 of rel_0_4, [ticket:1058] --- CHANGES | 10 ++++++++++ lib/sqlalchemy/orm/properties.py | 2 +- lib/sqlalchemy/orm/strategies.py | 6 +++++- test/orm/query.py | 6 +++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index ff6a0c07d7..841a622755 100644 --- a/CHANGES +++ b/CHANGES @@ -72,6 +72,16 @@ user_defined_state 0.4.7 ===== +- orm + - The contains() operator when used with many-to-many + will alias() the secondary (association) table so + that multiple contains() calls will not conflict + with each other [ticket:1058] + +- mysql + - Added 'CALL' to the list of SQL keywords which return + result rows. + - oracle - Oracle get_default_schema_name() "normalizes" the name before returning, meaning it returns a lower-case name diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 98f19131ba..c7300f2160 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -426,7 +426,7 @@ class PropertyLoader(StrategizedProperty): def _optimized_compare(self, value, value_is_parent=False): if value is not None: value = attributes.instance_state(value) - return self._get_strategy(strategies.LazyLoader).lazy_clause(value, reverse_direction=not value_is_parent) + return self._get_strategy(strategies.LazyLoader).lazy_clause(value, reverse_direction=not value_is_parent, alias_secondary=True) def __str__(self): return str(self.parent.class_.__name__) + "." + self.key diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 76cf4de18b..d40937a18c 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -294,7 +294,7 @@ class LazyLoader(AbstractRelationLoader): self.is_class_level = True self._register_attribute(self.parent.class_, callable_=self.class_level_loader) - def lazy_clause(self, state, reverse_direction=False): + def lazy_clause(self, state, reverse_direction=False, alias_secondary=False): if state is None: return self._lazy_none_clause(reverse_direction) @@ -310,6 +310,10 @@ class LazyLoader(AbstractRelationLoader): # 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_state_attr_by_column(state, bind_to_col[bindparam.key]) + + if self.parent_property.secondary and alias_secondary: + criterion = sql_util.ClauseAdapter(self.parent_property.secondary.alias()).traverse(criterion) + return visitors.cloned_traverse(criterion, {}, {'bindparam':visit_bindparam}) def _lazy_none_clause(self, reverse_direction=False): diff --git a/test/orm/query.py b/test/orm/query.py index 48e7d5b940..f816419187 100644 --- a/test/orm/query.py +++ b/test/orm/query.py @@ -450,6 +450,10 @@ class FilterTest(QueryTest): assert [Order(id=4), Order(id=5)] == sess.query(Order).filter(~Order.items.contains(item)).all() + item2 = sess.query(Item).get(5) + assert [Order(id=3)] == sess.query(Order).filter(Order.items.contains(item)).filter(Order.items.contains(item2)).all() + + def test_comparison(self): """test scalar comparison to an object instance""" @@ -471,7 +475,7 @@ class FilterTest(QueryTest): # m2m self.assertEquals(sess.query(Item).filter(Item.keywords==None).all(), [Item(id=4), Item(id=5)]) self.assertEquals(sess.query(Item).filter(Item.keywords!=None).all(), [Item(id=1),Item(id=2), Item(id=3)]) - + def test_filter_by(self): sess = create_session() user = sess.query(User).get(8) -- 2.47.3