]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
* adding 'isouter=False' to sqlalchemy.orm.query.Query (https://bitbucket.org/zzzeek...
authorjonathan vanasco <jonathan@2xlp.com>
Fri, 3 Oct 2014 17:15:52 +0000 (13:15 -0400)
committerjonathan vanasco <jonathan@2xlp.com>
Fri, 3 Oct 2014 17:15:52 +0000 (13:15 -0400)
$ python setup.py develop
$ pip install nose
$ pip install mock
$ ./sqla_nose.py test.orm.test_joins
.....................................................................................................
----------------------------------------------------------------------
Ran 101 tests in 1.222s

OK

$ ./sqla_nose.py test.orm
......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................S......................................................................................................................................................................................................................................................................................................................S.......................................................................................................................................................................................................................................................................................................................................................S.......S..S.SSS.SS...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................S................................S..S........................S...........................................................................................SSS.S.........SSSSSSSS......SSSSSSSSS........SS...SS...............S.............................S..............................................................SS..SS..............................................................................................................S.
----------------------------------------------------------------------
Ran 3103 tests in 82.607s

OK (SKIP=46)

lib/sqlalchemy/orm/query.py
test/orm/test_joins.py

index 7b2ea7977e4a19a077786c59ddc7a2ecdcc64b43..eaa3a8dcd0ae77745ee6f3177bd605ed22668410 100644 (file)
@@ -1740,6 +1740,8 @@ class Query(object):
          anonymously aliased.  Subsequent calls to :meth:`~.Query.filter`
          and similar will adapt the incoming criterion to the target
          alias, until :meth:`~.Query.reset_joinpoint` is called.
+        :param isouter=False: If True, the join used will be a left outer join,
+         just as if the ``outerjoin()`` method were called.
         :param from_joinpoint=False: When using ``aliased=True``, a setting
          of True here will cause the join to be from the most recent
          joined target, rather than starting back from the original
@@ -1757,13 +1759,15 @@ class Query(object):
             SQLAlchemy versions was the primary ORM-level joining interface.
 
         """
-        aliased, from_joinpoint = kwargs.pop('aliased', False),\
-            kwargs.pop('from_joinpoint', False)
+        aliased, from_joinpoint, isouter = kwargs.pop('aliased', False),\
+            kwargs.pop('from_joinpoint', False),\
+            kwargs.pop('isouter', False)
         if kwargs:
             raise TypeError("unknown arguments: %s" %
                             ','.join(kwargs.keys))
+        isouter = isouter
         return self._join(props,
-                          outerjoin=False, create_aliases=aliased,
+                          outerjoin=isouter, create_aliases=aliased,
                           from_joinpoint=from_joinpoint)
 
     def outerjoin(self, *props, **kwargs):
@@ -3385,7 +3389,6 @@ class _BundleEntity(_QueryEntity):
 
         self.supports_single_entity = self.bundle.single_entity
 
-
     @property
     def entity_zero(self):
         for ent in self._entities:
index 40bc01b5d6f4b673324cdd86efed9e21bddc18d4..188af2b380709a1adc013af3f86a08acddee6c7c 100644 (file)
@@ -721,6 +721,13 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
                 filter_by(id=3).outerjoin('orders','address').filter_by(id=1).all()
         assert [User(id=7, name='jack')] == result
 
+    def test_overlapping_paths_join_isouter(self):
+        User = self.classes.User
+
+        result = create_session().query(User).join('orders', 'items', isouter=True).\
+                filter_by(id=3).join('orders','address', isouter=True).filter_by(id=1).all()
+        assert [User(id=7, name='jack')] == result
+
     def test_from_joinpoint(self):
         Item, User, Order = (self.classes.Item,
                                 self.classes.User,
@@ -1088,7 +1095,6 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
             [User(name='fred')]
         )
 
-
     def test_aliased_classes(self):
         User, Address = self.classes.User, self.classes.Address
 
@@ -1237,7 +1243,6 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
     def test_joins_from_adapted_entities(self):
         User = self.classes.User
 
-
         # test for #1853
 
         session = create_session()
@@ -1274,6 +1279,45 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
                             'anon_2 ON anon_2.id = anon_1.users_id',
                             use_default_dialect=True)
 
+    def test_joins_from_adapted_entities_isouter(self):
+        User = self.classes.User
+
+        # test for #1853
+
+        session = create_session()
+        first = session.query(User)
+        second = session.query(User)
+        unioned = first.union(second)
+        subquery = session.query(User.id).subquery()
+        join = subquery, subquery.c.id == User.id
+        joined = unioned.join(*join, isouter=True)
+        self.assert_compile(joined,
+                            'SELECT anon_1.users_id AS '
+                            'anon_1_users_id, anon_1.users_name AS '
+                            'anon_1_users_name FROM (SELECT users.id '
+                            'AS users_id, users.name AS users_name '
+                            'FROM users UNION SELECT users.id AS '
+                            'users_id, users.name AS users_name FROM '
+                            'users) AS anon_1 LEFT OUTER JOIN (SELECT '
+                            'users.id AS id FROM users) AS anon_2 ON '
+                            'anon_2.id = anon_1.users_id',
+                            use_default_dialect=True)
+
+        first = session.query(User.id)
+        second = session.query(User.id)
+        unioned = first.union(second)
+        subquery = session.query(User.id).subquery()
+        join = subquery, subquery.c.id == User.id
+        joined = unioned.join(*join, isouter=True)
+        self.assert_compile(joined,
+                            'SELECT anon_1.users_id AS anon_1_users_id '
+                            'FROM (SELECT users.id AS users_id FROM '
+                            'users UNION SELECT users.id AS users_id '
+                            'FROM users) AS anon_1 LEFT OUTER JOIN '
+                            '(SELECT users.id AS id FROM users) AS '
+                            'anon_2 ON anon_2.id = anon_1.users_id',
+                            use_default_dialect=True)
+
     def test_reset_joinpoint(self):
         User = self.classes.User
 
@@ -1282,6 +1326,9 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
             result = create_session().query(User).join('orders', 'items', aliased=aliased).filter_by(id=3).reset_joinpoint().join('orders','address', aliased=aliased).filter_by(id=1).all()
             assert [User(id=7, name='jack')] == result
 
+            result = create_session().query(User).join('orders', 'items', aliased=aliased, isouter=True).filter_by(id=3).reset_joinpoint().join('orders','address', aliased=aliased, isouter=True).filter_by(id=1).all()
+            assert [User(id=7, name='jack')] == result
+
             result = create_session().query(User).outerjoin('orders', 'items', aliased=aliased).filter_by(id=3).reset_joinpoint().outerjoin('orders','address', aliased=aliased).filter_by(id=1).all()
             assert [User(id=7, name='jack')] == result