Skip to content

Commit c002034

Browse files
authored
DjangoConnectionField slice: use max_limit first, if set (#965)
1 parent 40e9c66 commit c002034

File tree

3 files changed

+110
-30
lines changed

3 files changed

+110
-30
lines changed

graphene_django/debug/tests/test_query.py

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import graphene
2+
import pytest
23
from graphene.relay import Node
34
from graphene_django import DjangoConnectionField, DjangoObjectType
45

@@ -24,7 +25,7 @@ class Meta:
2425

2526
class Query(graphene.ObjectType):
2627
reporter = graphene.Field(ReporterType)
27-
debug = graphene.Field(DjangoDebug, name="_debug")
28+
debug = graphene.Field(DjangoDebug, name="__debug")
2829

2930
def resolve_reporter(self, info, **args):
3031
return Reporter.objects.first()
@@ -34,7 +35,7 @@ def resolve_reporter(self, info, **args):
3435
reporter {
3536
lastName
3637
}
37-
_debug {
38+
__debug {
3839
sql {
3940
rawSql
4041
}
@@ -43,7 +44,9 @@ def resolve_reporter(self, info, **args):
4344
"""
4445
expected = {
4546
"reporter": {"lastName": "ABA"},
46-
"_debug": {"sql": [{"rawSql": str(Reporter.objects.order_by("pk")[:1].query)}]},
47+
"__debug": {
48+
"sql": [{"rawSql": str(Reporter.objects.order_by("pk")[:1].query)}]
49+
},
4750
}
4851
schema = graphene.Schema(query=Query)
4952
result = schema.execute(
@@ -53,7 +56,10 @@ def resolve_reporter(self, info, **args):
5356
assert result.data == expected
5457

5558

56-
def test_should_query_nested_field():
59+
@pytest.mark.parametrize("max_limit,does_count", [(None, True), (100, False)])
60+
def test_should_query_nested_field(graphene_settings, max_limit, does_count):
61+
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = max_limit
62+
5763
r1 = Reporter(last_name="ABA")
5864
r1.save()
5965
r2 = Reporter(last_name="Griffin")
@@ -111,11 +117,18 @@ def resolve_reporter(self, info, **args):
111117
assert not result.errors
112118
query = str(Reporter.objects.order_by("pk")[:1].query)
113119
assert result.data["__debug"]["sql"][0]["rawSql"] == query
114-
assert "COUNT" in result.data["__debug"]["sql"][1]["rawSql"]
115-
assert "tests_reporter_pets" in result.data["__debug"]["sql"][2]["rawSql"]
116-
assert "COUNT" in result.data["__debug"]["sql"][3]["rawSql"]
117-
assert "tests_reporter_pets" in result.data["__debug"]["sql"][4]["rawSql"]
118-
assert len(result.data["__debug"]["sql"]) == 5
120+
if does_count:
121+
assert "COUNT" in result.data["__debug"]["sql"][1]["rawSql"]
122+
assert "tests_reporter_pets" in result.data["__debug"]["sql"][2]["rawSql"]
123+
assert "COUNT" in result.data["__debug"]["sql"][3]["rawSql"]
124+
assert "tests_reporter_pets" in result.data["__debug"]["sql"][4]["rawSql"]
125+
assert len(result.data["__debug"]["sql"]) == 5
126+
else:
127+
assert len(result.data["__debug"]["sql"]) == 3
128+
for i in range(len(result.data["__debug"]["sql"])):
129+
assert "COUNT" not in result.data["__debug"]["sql"][i]["rawSql"]
130+
assert "tests_reporter_pets" in result.data["__debug"]["sql"][1]["rawSql"]
131+
assert "tests_reporter_pets" in result.data["__debug"]["sql"][2]["rawSql"]
119132

120133
assert result.data["reporter"] == expected["reporter"]
121134

@@ -133,7 +146,7 @@ class Meta:
133146

134147
class Query(graphene.ObjectType):
135148
all_reporters = graphene.List(ReporterType)
136-
debug = graphene.Field(DjangoDebug, name="_debug")
149+
debug = graphene.Field(DjangoDebug, name="__debug")
137150

138151
def resolve_all_reporters(self, info, **args):
139152
return Reporter.objects.all()
@@ -143,7 +156,7 @@ def resolve_all_reporters(self, info, **args):
143156
allReporters {
144157
lastName
145158
}
146-
_debug {
159+
__debug {
147160
sql {
148161
rawSql
149162
}
@@ -152,7 +165,7 @@ def resolve_all_reporters(self, info, **args):
152165
"""
153166
expected = {
154167
"allReporters": [{"lastName": "ABA"}, {"lastName": "Griffin"}],
155-
"_debug": {"sql": [{"rawSql": str(Reporter.objects.all().query)}]},
168+
"__debug": {"sql": [{"rawSql": str(Reporter.objects.all().query)}]},
156169
}
157170
schema = graphene.Schema(query=Query)
158171
result = schema.execute(
@@ -162,7 +175,10 @@ def resolve_all_reporters(self, info, **args):
162175
assert result.data == expected
163176

164177

165-
def test_should_query_connection():
178+
@pytest.mark.parametrize("max_limit,does_count", [(None, True), (100, False)])
179+
def test_should_query_connection(graphene_settings, max_limit, does_count):
180+
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = max_limit
181+
166182
r1 = Reporter(last_name="ABA")
167183
r1.save()
168184
r2 = Reporter(last_name="Griffin")
@@ -175,7 +191,7 @@ class Meta:
175191

176192
class Query(graphene.ObjectType):
177193
all_reporters = DjangoConnectionField(ReporterType)
178-
debug = graphene.Field(DjangoDebug, name="_debug")
194+
debug = graphene.Field(DjangoDebug, name="__debug")
179195

180196
def resolve_all_reporters(self, info, **args):
181197
return Reporter.objects.all()
@@ -189,7 +205,7 @@ def resolve_all_reporters(self, info, **args):
189205
}
190206
}
191207
}
192-
_debug {
208+
__debug {
193209
sql {
194210
rawSql
195211
}
@@ -203,12 +219,22 @@ def resolve_all_reporters(self, info, **args):
203219
)
204220
assert not result.errors
205221
assert result.data["allReporters"] == expected["allReporters"]
206-
assert "COUNT" in result.data["_debug"]["sql"][0]["rawSql"]
207-
query = str(Reporter.objects.all()[:1].query)
208-
assert result.data["_debug"]["sql"][1]["rawSql"] == query
209-
222+
if does_count:
223+
assert len(result.data["__debug"]["sql"]) == 2
224+
assert "COUNT" in result.data["__debug"]["sql"][0]["rawSql"]
225+
query = str(Reporter.objects.all()[:1].query)
226+
assert result.data["__debug"]["sql"][1]["rawSql"] == query
227+
else:
228+
assert len(result.data["__debug"]["sql"]) == 1
229+
assert "COUNT" not in result.data["__debug"]["sql"][0]["rawSql"]
230+
query = str(Reporter.objects.all()[:1].query)
231+
assert result.data["__debug"]["sql"][0]["rawSql"] == query
232+
233+
234+
@pytest.mark.parametrize("max_limit,does_count", [(None, True), (100, False)])
235+
def test_should_query_connectionfilter(graphene_settings, max_limit, does_count):
236+
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = max_limit
210237

211-
def test_should_query_connectionfilter():
212238
from ...filter import DjangoFilterConnectionField
213239

214240
r1 = Reporter(last_name="ABA")
@@ -224,7 +250,7 @@ class Meta:
224250
class Query(graphene.ObjectType):
225251
all_reporters = DjangoFilterConnectionField(ReporterType, fields=["last_name"])
226252
s = graphene.String(resolver=lambda *_: "S")
227-
debug = graphene.Field(DjangoDebug, name="_debug")
253+
debug = graphene.Field(DjangoDebug, name="__debug")
228254

229255
def resolve_all_reporters(self, info, **args):
230256
return Reporter.objects.all()
@@ -238,7 +264,7 @@ def resolve_all_reporters(self, info, **args):
238264
}
239265
}
240266
}
241-
_debug {
267+
__debug {
242268
sql {
243269
rawSql
244270
}
@@ -252,6 +278,13 @@ def resolve_all_reporters(self, info, **args):
252278
)
253279
assert not result.errors
254280
assert result.data["allReporters"] == expected["allReporters"]
255-
assert "COUNT" in result.data["_debug"]["sql"][0]["rawSql"]
256-
query = str(Reporter.objects.all()[:1].query)
257-
assert result.data["_debug"]["sql"][1]["rawSql"] == query
281+
if does_count:
282+
assert len(result.data["__debug"]["sql"]) == 2
283+
assert "COUNT" in result.data["__debug"]["sql"][0]["rawSql"]
284+
query = str(Reporter.objects.all()[:1].query)
285+
assert result.data["__debug"]["sql"][1]["rawSql"] == query
286+
else:
287+
assert len(result.data["__debug"]["sql"]) == 1
288+
assert "COUNT" not in result.data["__debug"]["sql"][0]["rawSql"]
289+
query = str(Reporter.objects.all()[:1].query)
290+
assert result.data["__debug"]["sql"][0]["rawSql"] == query

graphene_django/fields.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,15 @@ def resolve_queryset(cls, connection, queryset, info, args):
127127
return connection._meta.node.get_queryset(queryset, info)
128128

129129
@classmethod
130-
def resolve_connection(cls, connection, args, iterable):
130+
def resolve_connection(cls, connection, args, iterable, max_limit=None):
131131
iterable = maybe_queryset(iterable)
132+
# When slicing from the end, need to retrieve the iterable length.
133+
if args.get("last"):
134+
max_limit = None
132135
if isinstance(iterable, QuerySet):
133-
_len = iterable.count()
136+
_len = max_limit or iterable.count()
134137
else:
135-
_len = len(iterable)
138+
_len = max_limit or len(iterable)
136139
connection = connection_from_list_slice(
137140
iterable,
138141
args,
@@ -189,7 +192,9 @@ def connection_resolver(
189192
# thus the iterable gets refiltered by resolve_queryset
190193
# but iterable might be promise
191194
iterable = queryset_resolver(connection, iterable, info, args)
192-
on_resolve = partial(cls.resolve_connection, connection, args)
195+
on_resolve = partial(
196+
cls.resolve_connection, connection, args, max_limit=max_limit
197+
)
193198

194199
if Promise.is_thenable(iterable):
195200
return Promise.resolve(iterable).then(on_resolve)

graphene_django/tests/test_query.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,48 @@ class Query(graphene.ObjectType):
10841084
assert result.data == expected
10851085

10861086

1087+
REPORTERS = [
1088+
dict(
1089+
first_name="First {}".format(i),
1090+
last_name="Last {}".format(i),
1091+
email="johndoe+{}@example.com".format(i),
1092+
a_choice=1,
1093+
)
1094+
for i in range(6)
1095+
]
1096+
1097+
1098+
def test_should_return_max_limit(graphene_settings):
1099+
graphene_settings.RELAY_CONNECTION_MAX_LIMIT = 4
1100+
reporters = [Reporter(**kwargs) for kwargs in REPORTERS]
1101+
Reporter.objects.bulk_create(reporters)
1102+
1103+
class ReporterType(DjangoObjectType):
1104+
class Meta:
1105+
model = Reporter
1106+
interfaces = (Node,)
1107+
1108+
class Query(graphene.ObjectType):
1109+
all_reporters = DjangoConnectionField(ReporterType)
1110+
1111+
schema = graphene.Schema(query=Query)
1112+
query = """
1113+
query AllReporters {
1114+
allReporters {
1115+
edges {
1116+
node {
1117+
id
1118+
}
1119+
}
1120+
}
1121+
}
1122+
"""
1123+
1124+
result = schema.execute(query)
1125+
assert not result.errors
1126+
assert len(result.data["allReporters"]["edges"]) == 4
1127+
1128+
10871129
def test_should_preserve_prefetch_related(django_assert_num_queries):
10881130
class ReporterType(DjangoObjectType):
10891131
class Meta:
@@ -1130,7 +1172,7 @@ def resolve_films(root, info):
11301172
}
11311173
"""
11321174
schema = graphene.Schema(query=Query)
1133-
with django_assert_num_queries(3) as captured:
1175+
with django_assert_num_queries(2) as captured:
11341176
result = schema.execute(query)
11351177
assert not result.errors
11361178

0 commit comments

Comments
 (0)