]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add prop.secondary to FROM for dynamic loader
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 17 Oct 2018 14:42:50 +0000 (10:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 17 Oct 2018 15:50:52 +0000 (11:50 -0400)
Fixed bug where "dynamic" loader needs to explicitly set the "secondary"
table in the FROM clause of the query, to suit the case where the secondary
is a join object that is otherwise not pulled into the query from its
columns alone.

Fixes: #4349
Change-Id: I397f62abd5603efa4fb273586d0f772bf8c8fbbf

doc/build/changelog/unreleased_12/4349.rst [new file with mode: 0644]
lib/sqlalchemy/orm/dynamic.py
test/orm/test_dynamic.py

diff --git a/doc/build/changelog/unreleased_12/4349.rst b/doc/build/changelog/unreleased_12/4349.rst
new file mode 100644 (file)
index 0000000..a2ce828
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+   :tags: bug, orm
+   :tickets: 4349
+
+   Fixed bug where "dynamic" loader needs to explicitly set the "secondary"
+   table in the FROM clause of the query, to suit the case where the secondary
+   is a join object that is otherwise not pulled into the query from its
+   columns alone.
+
index 73d9ef3bb7fd5eec288a2e5e8011365fe061c2d2..3c59f61d70c3fc58e199ff597823f65a14ef3519 100644 (file)
@@ -219,6 +219,10 @@ class AppenderMixin(object):
 
         mapper = object_mapper(instance)
         prop = mapper._props[self.attr.key]
+
+        if prop.secondary is not None:
+            self._set_select_from([prop.secondary], False)
+
         self._criterion = prop._with_parent(
             instance,
             alias_secondary=False)
@@ -284,6 +288,7 @@ class AppenderMixin(object):
             query = sess.query(self.attr.target_mapper)
 
         query._criterion = self._criterion
+        query._from_obj = self._from_obj
         query._order_by = self._order_by
 
         return query
index 8dd805f52963b403a1c0efe2b624d281b8d73b89..5c514ff1a532eac5ec4d9bdb43a5c2b117cbff3b 100644 (file)
@@ -262,6 +262,36 @@ class DynamicTest(_DynamicFixture, _fixtures.FixtureTest, AssertsCompiledSQL):
             [Item(id=2)]
         )
 
+    def test_secondary_as_join(self):
+        User, users = self.classes.User, self.tables.users
+        items, orders, order_items, Item = (self.tables.items,
+                                            self.tables.orders,
+                                            self.tables.order_items,
+                                            self.classes.Item)
+
+        mapper(User, users, properties={
+            'items': relationship(
+                Item,
+                secondary=order_items.join(orders),
+                lazy="dynamic"
+            )
+        })
+        mapper(Item, items)
+
+        sess = create_session()
+        u1 = sess.query(User).first()
+
+        self.assert_compile(
+            u1.items,
+            "SELECT items.id AS items_id, "
+            "items.description AS items_description "
+            "FROM items, order_items JOIN orders "
+            "ON orders.id = order_items.order_id "
+            "WHERE :param_1 = orders.user_id "
+            "AND items.id = order_items.item_id",
+            use_default_dialect=True
+        )
+
     def test_transient_count(self):
         User, Address = self._user_address_fixture()
         u1 = User()