1
1
import datetime
2
2
import re
3
3
from django .db .models import Count , Prefetch
4
+ from asgiref .sync import sync_to_async , async_to_sync
4
5
5
6
import pytest
6
7
14
15
FilmDetails as FilmDetailsModel ,
15
16
Reporter as ReporterModel ,
16
17
)
18
+ from .async_test_helper import assert_async_result_equal
17
19
18
20
19
21
class TestDjangoListField :
@@ -75,6 +77,7 @@ class Query(ObjectType):
75
77
76
78
result = schema .execute (query )
77
79
80
+ assert_async_result_equal (schema , query , result )
78
81
assert not result .errors
79
82
assert result .data == {
80
83
"reporters" : [{"firstName" : "Tara" }, {"firstName" : "Debra" }]
@@ -102,6 +105,7 @@ class Query(ObjectType):
102
105
result = schema .execute (query )
103
106
assert not result .errors
104
107
assert result .data == {"reporters" : []}
108
+ assert_async_result_equal (schema , query , result )
105
109
106
110
ReporterModel .objects .create (first_name = "Tara" , last_name = "West" )
107
111
ReporterModel .objects .create (first_name = "Debra" , last_name = "Payne" )
@@ -112,6 +116,7 @@ class Query(ObjectType):
112
116
assert result .data == {
113
117
"reporters" : [{"firstName" : "Tara" }, {"firstName" : "Debra" }]
114
118
}
119
+ assert_async_result_equal (schema , query , result )
115
120
116
121
def test_override_resolver (self ):
117
122
class Reporter (DjangoObjectType ):
@@ -139,6 +144,37 @@ def resolve_reporters(_, info):
139
144
ReporterModel .objects .create (first_name = "Debra" , last_name = "Payne" )
140
145
141
146
result = schema .execute (query )
147
+ assert not result .errors
148
+ assert result .data == {"reporters" : [{"firstName" : "Tara" }]}
149
+
150
+ def test_override_resolver_async_execution (self ):
151
+ class Reporter (DjangoObjectType ):
152
+ class Meta :
153
+ model = ReporterModel
154
+ fields = ("first_name" ,)
155
+
156
+ class Query (ObjectType ):
157
+ reporters = DjangoListField (Reporter )
158
+
159
+ @staticmethod
160
+ @sync_to_async
161
+ def resolve_reporters (_ , info ):
162
+ return ReporterModel .objects .filter (first_name = "Tara" )
163
+
164
+ schema = Schema (query = Query )
165
+
166
+ query = """
167
+ query {
168
+ reporters {
169
+ firstName
170
+ }
171
+ }
172
+ """
173
+
174
+ ReporterModel .objects .create (first_name = "Tara" , last_name = "West" )
175
+ ReporterModel .objects .create (first_name = "Debra" , last_name = "Payne" )
176
+
177
+ result = async_to_sync (schema .execute_async )(query )
142
178
143
179
assert not result .errors
144
180
assert result .data == {"reporters" : [{"firstName" : "Tara" }]}
@@ -203,6 +239,7 @@ class Query(ObjectType):
203
239
{"firstName" : "Debra" , "articles" : []},
204
240
]
205
241
}
242
+ assert_async_result_equal (schema , query , result )
206
243
207
244
def test_override_resolver_nested_list_field (self ):
208
245
class Article (DjangoObjectType ):
@@ -261,6 +298,7 @@ class Query(ObjectType):
261
298
{"firstName" : "Debra" , "articles" : []},
262
299
]
263
300
}
301
+ assert_async_result_equal (schema , query , result )
264
302
265
303
def test_get_queryset_filter (self ):
266
304
class Reporter (DjangoObjectType ):
@@ -306,6 +344,7 @@ def resolve_reporters(_, info):
306
344
307
345
assert not result .errors
308
346
assert result .data == {"reporters" : [{"firstName" : "Tara" }]}
347
+ assert_async_result_equal (schema , query , result )
309
348
310
349
def test_resolve_list (self ):
311
350
"""Resolving a plain list should work (and not call get_queryset)"""
@@ -354,6 +393,55 @@ def resolve_reporters(_, info):
354
393
assert not result .errors
355
394
assert result .data == {"reporters" : [{"firstName" : "Debra" }]}
356
395
396
+ def test_resolve_list_async (self ):
397
+ """Resolving a plain list should work (and not call get_queryset) when running under async"""
398
+
399
+ class Reporter (DjangoObjectType ):
400
+ class Meta :
401
+ model = ReporterModel
402
+ fields = ("first_name" , "articles" )
403
+
404
+ @classmethod
405
+ def get_queryset (cls , queryset , info ):
406
+ # Only get reporters with at least 1 article
407
+ return queryset .annotate (article_count = Count ("articles" )).filter (
408
+ article_count__gt = 0
409
+ )
410
+
411
+ class Query (ObjectType ):
412
+ reporters = DjangoListField (Reporter )
413
+
414
+ @staticmethod
415
+ @sync_to_async
416
+ def resolve_reporters (_ , info ):
417
+ return [ReporterModel .objects .get (first_name = "Debra" )]
418
+
419
+ schema = Schema (query = Query )
420
+
421
+ query = """
422
+ query {
423
+ reporters {
424
+ firstName
425
+ }
426
+ }
427
+ """
428
+
429
+ r1 = ReporterModel .objects .create (first_name = "Tara" , last_name = "West" )
430
+ ReporterModel .objects .create (first_name = "Debra" , last_name = "Payne" )
431
+
432
+ ArticleModel .objects .create (
433
+ headline = "Amazing news" ,
434
+ reporter = r1 ,
435
+ pub_date = datetime .date .today (),
436
+ pub_date_time = datetime .datetime .now (),
437
+ editor = r1 ,
438
+ )
439
+
440
+ result = async_to_sync (schema .execute_async )(query )
441
+
442
+ assert not result .errors
443
+ assert result .data == {"reporters" : [{"firstName" : "Debra" }]}
444
+
357
445
def test_get_queryset_foreign_key (self ):
358
446
class Article (DjangoObjectType ):
359
447
class Meta :
@@ -413,6 +501,7 @@ class Query(ObjectType):
413
501
{"firstName" : "Debra" , "articles" : []},
414
502
]
415
503
}
504
+ assert_async_result_equal (schema , query , result )
416
505
417
506
def test_resolve_list_external_resolver (self ):
418
507
"""Resolving a plain list from external resolver should work (and not call get_queryset)"""
@@ -461,6 +550,54 @@ class Query(ObjectType):
461
550
assert not result .errors
462
551
assert result .data == {"reporters" : [{"firstName" : "Debra" }]}
463
552
553
+ def test_resolve_list_external_resolver_async (self ):
554
+ """Resolving a plain list from external resolver should work (and not call get_queryset)"""
555
+
556
+ class Reporter (DjangoObjectType ):
557
+ class Meta :
558
+ model = ReporterModel
559
+ fields = ("first_name" , "articles" )
560
+
561
+ @classmethod
562
+ def get_queryset (cls , queryset , info ):
563
+ # Only get reporters with at least 1 article
564
+ return queryset .annotate (article_count = Count ("articles" )).filter (
565
+ article_count__gt = 0
566
+ )
567
+
568
+ @sync_to_async
569
+ def resolve_reporters (_ , info ):
570
+ return [ReporterModel .objects .get (first_name = "Debra" )]
571
+
572
+ class Query (ObjectType ):
573
+ reporters = DjangoListField (Reporter , resolver = resolve_reporters )
574
+
575
+ schema = Schema (query = Query )
576
+
577
+ query = """
578
+ query {
579
+ reporters {
580
+ firstName
581
+ }
582
+ }
583
+ """
584
+
585
+ r1 = ReporterModel .objects .create (first_name = "Tara" , last_name = "West" )
586
+ ReporterModel .objects .create (first_name = "Debra" , last_name = "Payne" )
587
+
588
+ ArticleModel .objects .create (
589
+ headline = "Amazing news" ,
590
+ reporter = r1 ,
591
+ pub_date = datetime .date .today (),
592
+ pub_date_time = datetime .datetime .now (),
593
+ editor = r1 ,
594
+ )
595
+
596
+ result = async_to_sync (schema .execute_async )(query )
597
+
598
+ assert not result .errors
599
+ assert result .data == {"reporters" : [{"firstName" : "Debra" }]}
600
+
464
601
def test_get_queryset_filter_external_resolver (self ):
465
602
class Reporter (DjangoObjectType ):
466
603
class Meta :
@@ -505,6 +642,7 @@ class Query(ObjectType):
505
642
506
643
assert not result .errors
507
644
assert result .data == {"reporters" : [{"firstName" : "Tara" }]}
645
+ assert_async_result_equal (schema , query , result )
508
646
509
647
def test_select_related_and_prefetch_related_are_respected (
510
648
self , django_assert_num_queries
@@ -647,3 +785,4 @@ def resolve_articles(root, info):
647
785
r'SELECT .* FROM "tests_film" INNER JOIN "tests_film_reporters" .* LEFT OUTER JOIN "tests_filmdetails"' ,
648
786
captured .captured_queries [1 ]["sql" ],
649
787
)
788
+ assert_async_result_equal (schema , query , result )
0 commit comments