From: Mike Bayer Date: Thu, 17 May 2007 15:11:34 +0000 (+0000) Subject: - fix to select_by(=) -style joins in conjunction X-Git-Tag: rel_0_3_8~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=779068fb41a216f65f6cd18d50b261e378ed67ac;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - fix to select_by(=) -style joins in conjunction with many-to-many relationships, bug introduced in r2556 - the "reverse_direction" flag in _create_lazy_clause works correctly for a many-to-many relationship (i.e. the reverse is on which clause, not which column in the clause, in the case of m2m) --- diff --git a/CHANGES b/CHANGES index 277f57e2f0..332611431a 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,8 @@ - session.get() and session.load() propigate **kwargs through to query - fix to polymorphic query which allows the original polymorphic_union to be embedded into a correlated subquery [ticket:577] + - fix to select_by(=) -style joins in conjunction + with many-to-many relationships, bug introduced in r2556 - mysql - support for column-level CHARACTER SET and COLLATE declarations, as well as ASCII, UNICODE, NATIONAL and BINARY shorthand. diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 171021da82..6677e4ab94 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -418,6 +418,8 @@ class PropertyLoader(StrategizedProperty): if logging.is_info_enabled(self.logger): self.logger.info(str(self) + " setup primary join " + str(self.primaryjoin)) self.logger.info(str(self) + " setup polymorphic primary join " + str(self.polymorphic_primaryjoin)) + self.logger.info(str(self) + " setup secondary join " + str(self.secondaryjoin)) + self.logger.info(str(self) + " setup polymorphic secondary join " + str(self.polymorphic_secondaryjoin)) self.logger.info(str(self) + " foreign keys " + str([str(c) for c in self.foreign_keys])) self.logger.info(str(self) + " remote columns " + str([str(c) for c in self.remote_side])) self.logger.info(str(self) + " relation direction " + (self.direction is sync.ONETOMANY and "one-to-many" or (self.direction is sync.MANYTOONE and "many-to-one" or "many-to-many"))) diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 033d0cac14..f1b159318f 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -253,7 +253,7 @@ class LazyLoader(AbstractRelationLoader): reverse = {} def should_bind(targetcol, othercol): - if reverse_direction: + if reverse_direction and not secondaryjoin: return targetcol in remote_side else: return othercol in remote_side @@ -293,10 +293,14 @@ class LazyLoader(AbstractRelationLoader): lazywhere = primaryjoin.copy_container() li = mapperutil.BinaryVisitor(visit_binary) - li.traverse(lazywhere) + + if not secondaryjoin or not reverse_direction: + li.traverse(lazywhere) if secondaryjoin is not None: secondaryjoin = secondaryjoin.copy_container() + if reverse_direction: + li.traverse(secondaryjoin) lazywhere = sql.and_(lazywhere, secondaryjoin) if hasattr(cls, 'parent_property'): diff --git a/test/orm/mapper.py b/test/orm/mapper.py index a9cc401029..4ce1be2fa7 100644 --- a/test/orm/mapper.py +++ b/test/orm/mapper.py @@ -346,8 +346,8 @@ class MapperTest(MapperSuperTest): self.assert_result(k, Keyword, *item_keyword_result[1]['keywords'][1]) - def testjoinvia(self): - """test the join_via and join_to functions""" + def testautojoin(self): + """test functions derived from Query's _join_to function.""" m = mapper(User, users, properties={ 'orders':relation(mapper(Order, orders, properties={ @@ -386,10 +386,10 @@ class MapperTest(MapperSuperTest): assert False except AttributeError: assert True - - def testjoinviam2m(self): - """test the join_via and join_to functions""" + def testautojoinm2m(self): + """test functions derived from Query's _join_to function.""" + m = mapper(Order, orders, properties = { 'items' : relation(mapper(Item, orderitems, properties = { 'keywords' : relation(mapper(Keyword, keywords), itemkeywords) @@ -402,10 +402,15 @@ class MapperTest(MapperSuperTest): l = q.filter(keywords.c.name=='square').join(['items', 'keywords']).list() self.assert_result(l, Order, order_result[1]) + # test comparing to an object instance + item = sess.query(Item).selectfirst() + l = sess.query(Item).select_by(keywords=item.keywords[0]) + assert item == l[0] def testcustomjoin(self): """test that the from_obj parameter to query.select() can be used to totally replace the FROM parameters of the generated query.""" + m = mapper(User, users, properties={ 'orders':relation(mapper(Order, orders, properties={ 'items':relation(mapper(Item, orderitems))