From eeaef9d1ab6b43f02e0e8166b1512033b1abc08d Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Fri, 16 Oct 2026 09:25:47 -0700 Subject: [PATCH 1/2] fix(api): Reverse previous-page ordering for descending paginators BasePaginator.build_queryset assigned the reversed ordering to queryset.query.order_b, a typo for order_by, when the queryset was already ordered by the descending key and a previous-page cursor needed ascending order. The assignment was silently dropped, so the previous page was filtered as if ascending but still sorted descending, returning the wrong rows. The ordering is now written to order_by, matching the sibling branch. --- src/sentry/api/paginator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/api/paginator.py b/src/sentry/api/paginator.py index a6a822d155a7..764bfcd73128 100644 --- a/src/sentry/api/paginator.py +++ b/src/sentry/api/paginator.py @@ -130,7 +130,7 @@ def build_queryset(self, value: object, is_prev: bool) -> QuerySet[Model]: new_order_by = list(source.query.order_by) index = new_order_by.index(f"-{self.key}") new_order_by[index] = new_order_by[index][1:] - source.query.order_b = tuple(new_order_by) # type: ignore[attr-defined] # fixed in #127799 + source.query.order_by = tuple(new_order_by) else: if asc: queryset = queryset.order_by(self.key) From aab5698bee0daca532976df75d99ea9ab1e5be73 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Sat, 31 Oct 2026 10:16:05 -0700 Subject: [PATCH 2/2] test(api): cover previous-page ordering for descending querysets Exercise the branch that reverses an explicitly descending queryset for a previous-page cursor. Without the order_by fix, the previous page returns the current row instead of the preceding page. --- tests/sentry/api/test_paginator.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/sentry/api/test_paginator.py b/tests/sentry/api/test_paginator.py index 2b15e2a25bf2..e95bfe4fa177 100644 --- a/tests/sentry/api/test_paginator.py +++ b/tests/sentry/api/test_paginator.py @@ -332,6 +332,26 @@ def test_descending(self) -> None: assert result3.next assert not result3.prev + def test_prev_page_with_explicit_descending_queryset(self) -> None: + joined = timezone.now() + + res1 = self.create_user("foo@example.com", date_joined=joined) + res2 = self.create_user("bar@example.com", date_joined=joined + timedelta(seconds=1)) + res3 = self.create_user("baz@example.com", date_joined=joined + timedelta(seconds=2)) + + paginator = DateTimePaginator( + User.objects.order_by("-date_joined"), order_by="-date_joined" + ) + + result1 = paginator.get_result(limit=2, cursor=None) + assert list(result1) == [res3, res2] + + result2 = paginator.get_result(limit=2, cursor=result1.next) + assert list(result2) == [res1] + + result3 = paginator.get_result(limit=2, cursor=result2.prev) + assert list(result3) == [res3, res2] + def test_prev_descending_with_new(self) -> None: joined = timezone.now()