diff --git a/strawberry_django/pagination.py b/strawberry_django/pagination.py index 424701b1..cc3ec8c0 100644 --- a/strawberry_django/pagination.py +++ b/strawberry_django/pagination.py @@ -1,3 +1,4 @@ +import sys from typing import TYPE_CHECKING, List, Optional, TypeVar, Union import strawberry @@ -103,9 +104,13 @@ def apply_window_pagination( partition_by=related_field_id, ), ) + if offset: queryset = queryset.filter(_strawberry_row_number__gt=offset) - if limit >= 0: + + # Limit == -1 means no limit. sys.maxsize is set by relay when paginating + # from the end to as a way to mimic a "not limit" as well + if limit >= 0 and limit != sys.maxsize: queryset = queryset.filter(_strawberry_row_number__lte=offset + limit) return queryset diff --git a/tests/test_pagination.py b/tests/test_pagination.py index f8ef5f69..892744e7 100644 --- a/tests/test_pagination.py +++ b/tests/test_pagination.py @@ -1,3 +1,4 @@ +import sys from typing import List, cast import pytest @@ -6,7 +7,11 @@ from strawberry.types import ExecutionResult import strawberry_django -from strawberry_django.pagination import OffsetPaginationInput, apply +from strawberry_django.pagination import ( + OffsetPaginationInput, + apply, + apply_window_pagination, +) from tests import models, utils from tests.projects.faker import MilestoneFactory, ProjectFactory @@ -96,3 +101,47 @@ def fruits(self, pagination: OffsetPaginationInput) -> List[Fruit]: assert result.data["fruits"] == [ {"id": "1", "name": "strawberry"}, ] + + +@pytest.mark.django_db(transaction=True) +def test_apply_window_pagination(): + color = models.Color.objects.create(name="Red") + + for i in range(10): + models.Fruit.objects.create(name=f"fruit{i}", color=color) + + queryset = apply_window_pagination( + models.Fruit.objects.all(), + related_field_id="color_id", + offset=1, + limit=1, + ) + + assert queryset.count() == 1 + fruit = queryset.get() + assert fruit.name == "fruit1" + assert fruit._strawberry_row_number == 2 # type: ignore + assert fruit._strawberry_total_count == 10 # type: ignore + + +@pytest.mark.parametrize("limit", [-1, sys.maxsize]) +@pytest.mark.django_db(transaction=True) +def test_apply_window_pagination_with_no_limites(limit): + color = models.Color.objects.create(name="Red") + + for i in range(10): + models.Fruit.objects.create(name=f"fruit{i}", color=color) + + queryset = apply_window_pagination( + models.Fruit.objects.all(), + related_field_id="color_id", + offset=2, + limit=limit, + ) + + assert queryset.count() == 8 + first_fruit = queryset.first() + assert first_fruit is not None + assert first_fruit.name == "fruit2" + assert first_fruit._strawberry_row_number == 3 # type: ignore + assert first_fruit._strawberry_total_count == 10 # type: ignore diff --git a/tests/test_queries.py b/tests/test_queries.py index fe23f422..dcc46e74 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -1,6 +1,7 @@ import io import textwrap from typing import List, Optional, cast +from unittest import mock import pytest import strawberry @@ -312,4 +313,4 @@ def fruit(self) -> Fruit: } } """) - assert result.data == {"fruit": {"colorId": 1, "name": "Banana"}} + assert result.data == {"fruit": {"colorId": mock.ANY, "name": "Banana"}}