]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add `_WILDCARD_TOKEN` special case in `_chop_path`
authorMatthew Martin <phy1729@gmail.com>
Sun, 11 Jun 2023 14:00:22 +0000 (10:00 -0400)
committersqla-tester <sqla-tester@sqlalchemy.org>
Sun, 11 Jun 2023 14:00:22 +0000 (10:00 -0400)
### Description
<!-- Describe your changes in detail -->

Add special case to `_chop_path` for initial `_WILDCARD_TOKEN` matching `_DEFAULT_TOKEN` to allow for a top level `undefer_group` load option with other load options. Fixes #9870.

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [ ] A documentation / typographical error fix
- Good to go, no issue or tests are needed
- [x] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #9931
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/9931
Pull-request-sha: c073f0904f12909ff660beef6576f6476a725592

Change-Id: Ic1158b3b0306e9a1bba86ab0b9f07700a6352398

doc/build/changelog/unreleased_20/9870.rst [new file with mode: 0644]
lib/sqlalchemy/orm/strategy_options.py
test/orm/test_deferred.py

diff --git a/doc/build/changelog/unreleased_20/9870.rst b/doc/build/changelog/unreleased_20/9870.rst
new file mode 100644 (file)
index 0000000..3c3a5dd
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 9870
+
+    Fixed regression in the 2.0 series where a query that used
+    :func:`.undefer_group` with :func:`_orm.selectinload` or
+    :func:`_orm.subqueryload` would raise an ``AttributeError``. Pull request
+    courtesy of Matthew Martin.
index 90b8dda8b096cbabab77370d5c04a2390403459d..d93ec0a273151c98d921a9f42146f2a6adf43ce0 100644 (file)
@@ -931,7 +931,10 @@ class _AbstractLoad(traversals.GenerativeOnTraversal, LoaderOption):
             zip(to_chop, path.natural_path)
         ):
             if isinstance(c_token, str):
-                if i == 0 and c_token.endswith(f":{_DEFAULT_TOKEN}"):
+                if i == 0 and (
+                    c_token.endswith(f":{_DEFAULT_TOKEN}")
+                    or c_token.endswith(f":{_WILDCARD_TOKEN}")
+                ):
                     return to_chop
                 elif (
                     c_token != f"{_RELATIONSHIP_TOKEN}:{_WILDCARD_TOKEN}"
index 74352992406ae1d8a2a5463e888d3151696d5a41..c93ac6d60ac0a1b457adab04e9370aa772f01b9a 100644 (file)
@@ -692,6 +692,75 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
             ],
         )
 
+    def test_undefer_group_with_load(self):
+        users, Order, User, orders = (
+            self.tables.users,
+            self.classes.Order,
+            self.classes.User,
+            self.tables.orders,
+        )
+
+        self.mapper_registry.map_imperatively(
+            User,
+            users,
+        )
+        self.mapper_registry.map_imperatively(
+            Order,
+            orders,
+            properties=util.OrderedDict(
+                [
+                    ("userident", deferred(orders.c.user_id, group="primary")),
+                    (
+                        "description",
+                        deferred(orders.c.description, group="primary"),
+                    ),
+                    ("opened", deferred(orders.c.isopen, group="primary")),
+                    ("user", relationship(User)),
+                ]
+            ),
+        )
+
+        sess = fixture_session()
+        q = (
+            sess.query(Order)
+            .filter(Order.id == 3)
+            .options(
+                selectinload(Order.user),
+                undefer_group("primary"),
+            )
+        )
+
+        def go():
+            result = q.all()
+            print(result)
+            o = result[0]
+            eq_(o.opened, 1)
+            eq_(o.userident, 7)
+            eq_(o.description, "order 3")
+            u = o.user
+            eq_(u.id, 7)
+
+        self.sql_eq_(
+            go,
+            [
+                (
+                    "SELECT orders.id AS orders_id, "
+                    "orders.user_id AS orders_user_id, "
+                    "orders.address_id AS orders_address_id, "
+                    "orders.description AS orders_description, "
+                    "orders.isopen AS orders_isopen "
+                    "FROM orders WHERE orders.id = :id_1",
+                    {"id_1": 3},
+                ),
+                (
+                    "SELECT users.id AS users_id, users.name AS users_name "
+                    "FROM users WHERE users.id IN "
+                    "(__[POSTCOMPILE_primary_keys])",
+                    [{"primary_keys": [7]}],
+                ),
+            ],
+        )
+
     def test_undefer_group_from_relationship_lazyload(self):
         users, Order, User, orders = (
             self.tables.users,