fix: backward pagination indexing error when using bigger last argument than total number of elements (#1344)

Co-authored-by: Thomas Leonard <thomas@loftorbital.com>
This commit is contained in:
Thomas Leonard 2022-09-06 14:00:13 +02:00 committed by GitHub
parent 5f1731dca3
commit 2aeb86ba3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 11 deletions

View File

@ -146,36 +146,38 @@ class DjangoConnectionField(ConnectionField):
iterable = maybe_queryset(iterable) iterable = maybe_queryset(iterable)
if isinstance(iterable, QuerySet): if isinstance(iterable, QuerySet):
list_length = iterable.count() array_length = iterable.count()
else: else:
list_length = len(iterable) array_length = len(iterable)
list_slice_length = ( array_slice_length = (
min(max_limit, list_length) if max_limit is not None else list_length min(max_limit, array_length) if max_limit is not None else array_length
) )
# If after is higher than list_length, connection_from_list_slice # If after is higher than list_length, connection_from_list_slice
# would try to do a negative slicing which makes django throw an # would try to do a negative slicing which makes django throw an
# AssertionError # AssertionError
after = min(get_offset_with_default(args.get("after"), -1) + 1, list_length) slice_start = min(
get_offset_with_default(args.get("after"), -1) + 1, array_length
)
if max_limit is not None and args.get("first", None) is None: if max_limit is not None and args.get("first", None) is None:
if args.get("last", None) is not None: if args.get("last", None) is not None:
after = list_length - args["last"] slice_start = max(array_length - args["last"], 0)
else: else:
args["first"] = max_limit args["first"] = max_limit
connection = connection_from_array_slice( connection = connection_from_array_slice(
iterable[after:], iterable[slice_start:],
args, args,
slice_start=after, slice_start=slice_start,
array_length=list_length, array_length=array_length,
array_slice_length=list_slice_length, array_slice_length=array_slice_length,
connection_type=partial(connection_adapter, connection), connection_type=partial(connection_adapter, connection),
edge_type=connection.Edge, edge_type=connection.Edge,
page_info_type=page_info_adapter, page_info_type=page_info_adapter,
) )
connection.iterable = iterable connection.iterable = iterable
connection.length = list_length connection.length = array_length
return connection return connection
@classmethod @classmethod

View File

@ -1593,3 +1593,78 @@ def test_connection_should_allow_offset_filtering_with_after():
"allReporters": {"edges": [{"node": {"firstName": "Jane", "lastName": "Roe"}},]} "allReporters": {"edges": [{"node": {"firstName": "Jane", "lastName": "Roe"}},]}
} }
assert result.data == expected assert result.data == expected
def test_connection_should_succeed_if_last_higher_than_number_of_objects():
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)
fields = "__all__"
class Query(graphene.ObjectType):
all_reporters = DjangoConnectionField(ReporterType)
schema = graphene.Schema(query=Query)
query = """
query ReporterPromiseConnectionQuery ($last: Int) {
allReporters(last: $last) {
edges {
node {
firstName
lastName
}
}
}
}
"""
result = schema.execute(query, variable_values=dict(last=2))
assert not result.errors
expected = {"allReporters": {"edges": []}}
assert result.data == expected
Reporter.objects.create(first_name="John", last_name="Doe")
Reporter.objects.create(first_name="Some", last_name="Guy")
Reporter.objects.create(first_name="Jane", last_name="Roe")
Reporter.objects.create(first_name="Some", last_name="Lady")
result = schema.execute(query, variable_values=dict(last=2))
assert not result.errors
expected = {
"allReporters": {
"edges": [
{"node": {"firstName": "Jane", "lastName": "Roe"}},
{"node": {"firstName": "Some", "lastName": "Lady"}},
]
}
}
assert result.data == expected
result = schema.execute(query, variable_values=dict(last=4))
assert not result.errors
expected = {
"allReporters": {
"edges": [
{"node": {"firstName": "John", "lastName": "Doe"}},
{"node": {"firstName": "Some", "lastName": "Guy"}},
{"node": {"firstName": "Jane", "lastName": "Roe"}},
{"node": {"firstName": "Some", "lastName": "Lady"}},
]
}
}
assert result.data == expected
result = schema.execute(query, variable_values=dict(last=20))
assert not result.errors
expected = {
"allReporters": {
"edges": [
{"node": {"firstName": "John", "lastName": "Doe"}},
{"node": {"firstName": "Some", "lastName": "Guy"}},
{"node": {"firstName": "Jane", "lastName": "Roe"}},
{"node": {"firstName": "Some", "lastName": "Lady"}},
]
}
}
assert result.data == expected