mirror of
https://github.com/graphql-python/graphene-django.git
synced 2024-11-28 12:33:43 +03:00
Fix backward Relay pagination (#1046)
* Fix backward Relay pagination * linting Co-authored-by: Thomas Leonard <thomas@loftorbital.com>
This commit is contained in:
parent
4c0c821b74
commit
454b74052e
|
@ -147,9 +147,6 @@ class DjangoConnectionField(ConnectionField):
|
||||||
|
|
||||||
if isinstance(iterable, QuerySet):
|
if isinstance(iterable, QuerySet):
|
||||||
list_length = iterable.count()
|
list_length = iterable.count()
|
||||||
list_slice_length = (
|
|
||||||
min(max_limit, list_length) if max_limit is not None else list_length
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
list_length = len(iterable)
|
list_length = len(iterable)
|
||||||
list_slice_length = (
|
list_slice_length = (
|
||||||
|
@ -162,6 +159,10 @@ class DjangoConnectionField(ConnectionField):
|
||||||
after = min(get_offset_with_default(args.get("after"), -1) + 1, list_length)
|
after = min(get_offset_with_default(args.get("after"), -1) + 1, list_length)
|
||||||
|
|
||||||
if max_limit is not None and "first" not in args:
|
if max_limit is not None and "first" not in args:
|
||||||
|
if "last" in args:
|
||||||
|
args["first"] = list_length
|
||||||
|
list_slice_length = list_length
|
||||||
|
else:
|
||||||
args["first"] = max_limit
|
args["first"] = max_limit
|
||||||
|
|
||||||
connection = connection_from_list_slice(
|
connection = connection_from_list_slice(
|
||||||
|
|
|
@ -1213,6 +1213,103 @@ def test_should_have_next_page(graphene_settings):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestBackwardPagination:
|
||||||
|
def setup_schema(self, graphene_settings, max_limit):
|
||||||
|
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = max_limit
|
||||||
|
reporters = [Reporter(**kwargs) for kwargs in REPORTERS]
|
||||||
|
Reporter.objects.bulk_create(reporters)
|
||||||
|
|
||||||
|
class ReporterType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = Reporter
|
||||||
|
interfaces = (Node,)
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
all_reporters = DjangoConnectionField(ReporterType)
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query)
|
||||||
|
return schema
|
||||||
|
|
||||||
|
def do_queries(self, schema):
|
||||||
|
# Simply last 3
|
||||||
|
query_last = """
|
||||||
|
query {
|
||||||
|
allReporters(last: 3) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = schema.execute(query_last)
|
||||||
|
assert not result.errors
|
||||||
|
assert len(result.data["allReporters"]["edges"]) == 3
|
||||||
|
assert [
|
||||||
|
e["node"]["firstName"] for e in result.data["allReporters"]["edges"]
|
||||||
|
] == ["First 3", "First 4", "First 5"]
|
||||||
|
|
||||||
|
# Use a combination of first and last
|
||||||
|
query_first_and_last = """
|
||||||
|
query {
|
||||||
|
allReporters(first: 4, last: 3) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = schema.execute(query_first_and_last)
|
||||||
|
assert not result.errors
|
||||||
|
assert len(result.data["allReporters"]["edges"]) == 3
|
||||||
|
assert [
|
||||||
|
e["node"]["firstName"] for e in result.data["allReporters"]["edges"]
|
||||||
|
] == ["First 1", "First 2", "First 3"]
|
||||||
|
|
||||||
|
# Use a combination of first and last and after
|
||||||
|
query_first_last_and_after = """
|
||||||
|
query queryAfter($after: String) {
|
||||||
|
allReporters(first: 4, last: 3, after: $after) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
after = base64.b64encode(b"arrayconnection:0").decode()
|
||||||
|
result = schema.execute(
|
||||||
|
query_first_last_and_after, variable_values=dict(after=after)
|
||||||
|
)
|
||||||
|
assert not result.errors
|
||||||
|
assert len(result.data["allReporters"]["edges"]) == 3
|
||||||
|
assert [
|
||||||
|
e["node"]["firstName"] for e in result.data["allReporters"]["edges"]
|
||||||
|
] == ["First 2", "First 3", "First 4"]
|
||||||
|
|
||||||
|
def test_should_query(self, graphene_settings):
|
||||||
|
"""
|
||||||
|
Backward pagination should work as expected
|
||||||
|
"""
|
||||||
|
schema = self.setup_schema(graphene_settings, max_limit=100)
|
||||||
|
self.do_queries(schema)
|
||||||
|
|
||||||
|
def test_should_query_with_low_max_limit(self, graphene_settings):
|
||||||
|
"""
|
||||||
|
When doing backward pagination (using last) in combination with a max limit higher than the number of objects
|
||||||
|
we should really retrieve the last ones.
|
||||||
|
"""
|
||||||
|
schema = self.setup_schema(graphene_settings, max_limit=4)
|
||||||
|
self.do_queries(schema)
|
||||||
|
|
||||||
|
|
||||||
def test_should_preserve_prefetch_related(django_assert_num_queries):
|
def test_should_preserve_prefetch_related(django_assert_num_queries):
|
||||||
class ReporterType(DjangoObjectType):
|
class ReporterType(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user