1- from unittest . mock import MagicMock
1+ from functools import reduce
22
33import pytest
44from django .db import models
2525 )
2626
2727
28- STORE = {"events" : []}
29-
30-
3128class Event (models .Model ):
3229 name = models .CharField (max_length = 50 )
3330 tags = ArrayField (models .CharField (max_length = 50 ))
3431 tag_ids = ArrayField (models .IntegerField ())
3532 random_field = ArrayField (models .BooleanField ())
3633
34+ def __repr__ (self ):
35+ return f"Event [{ self .name } ]"
36+
3737
3838@pytest .fixture
3939def EventFilterSet ():
@@ -48,6 +48,14 @@ class Meta:
4848 tags__contains = ArrayFilter (field_name = "tags" , lookup_expr = "contains" )
4949 tags__overlap = ArrayFilter (field_name = "tags" , lookup_expr = "overlap" )
5050 tags = ArrayFilter (field_name = "tags" , lookup_expr = "exact" )
51+ tags__len = ArrayFilter (
52+ field_name = "tags" , lookup_expr = "len" , input_type = graphene .Int
53+ )
54+ tags__len__in = ArrayFilter (
55+ field_name = "tags" ,
56+ method = "tags__len__in_filter" ,
57+ input_type = graphene .List (graphene .Int ),
58+ )
5159
5260 # Those are actually not usable and only to check type declarations
5361 tags_ids__contains = ArrayFilter (field_name = "tag_ids" , lookup_expr = "contains" )
@@ -61,6 +69,14 @@ class Meta:
6169 )
6270 random_field = ArrayFilter (field_name = "random_field" , lookup_expr = "exact" )
6371
72+ def tags__len__in_filter (self , queryset , _name , value ):
73+ if not value :
74+ return queryset .none ()
75+ return reduce (
76+ lambda q1 , q2 : q1 .union (q2 ),
77+ [queryset .filter (tags__len = v ) for v in value ],
78+ ).distinct ()
79+
6480 return EventFilterSet
6581
6682
@@ -83,68 +99,94 @@ def Query(EventType):
8399 we are running unit tests in sqlite which does not have ArrayFields.
84100 """
85101
102+ events = [
103+ Event (name = "Live Show" , tags = ["concert" , "music" , "rock" ]),
104+ Event (name = "Musical" , tags = ["movie" , "music" ]),
105+ Event (name = "Ballet" , tags = ["concert" , "dance" ]),
106+ Event (name = "Speech" , tags = []),
107+ ]
108+
86109 class Query (graphene .ObjectType ):
87110 events = DjangoFilterConnectionField (EventType )
88111
89112 def resolve_events (self , info , ** kwargs ):
90- events = [
91- Event (name = "Live Show" , tags = ["concert" , "music" , "rock" ]),
92- Event (name = "Musical" , tags = ["movie" , "music" ]),
93- Event (name = "Ballet" , tags = ["concert" , "dance" ]),
94- Event (name = "Speech" , tags = []),
95- ]
96-
97- STORE ["events" ] = events
98-
99- m_queryset = MagicMock (spec = QuerySet )
100- m_queryset .model = Event
101-
102- def filter_events (** kwargs ):
103- if "tags__contains" in kwargs :
104- STORE ["events" ] = list (
105- filter (
106- lambda e : set (kwargs ["tags__contains" ]).issubset (
107- set (e .tags )
108- ),
109- STORE ["events" ],
113+ class FakeQuerySet (QuerySet ):
114+ def __init__ (self , model = None ):
115+ self .model = Event
116+ self .__store = list (events )
117+
118+ def all (self ):
119+ return self
120+
121+ def filter (self , ** kwargs ):
122+ queryset = FakeQuerySet ()
123+ queryset .__store = list (self .__store )
124+ if "tags__contains" in kwargs :
125+ queryset .__store = list (
126+ filter (
127+ lambda e : set (kwargs ["tags__contains" ]).issubset (
128+ set (e .tags )
129+ ),
130+ queryset .__store ,
131+ )
132+ )
133+ if "tags__overlap" in kwargs :
134+ queryset .__store = list (
135+ filter (
136+ lambda e : not set (kwargs ["tags__overlap" ]).isdisjoint (
137+ set (e .tags )
138+ ),
139+ queryset .__store ,
140+ )
110141 )
111- )
112- if "tags__overlap" in kwargs :
113- STORE ["events" ] = list (
114- filter (
115- lambda e : not set (kwargs ["tags__overlap" ]).isdisjoint (
116- set (e .tags )
117- ),
118- STORE ["events" ],
142+ if "tags__exact" in kwargs :
143+ queryset .__store = list (
144+ filter (
145+ lambda e : set (kwargs ["tags__exact" ]) == set (e .tags ),
146+ queryset .__store ,
147+ )
119148 )
120- )
121- if "tags__exact" in kwargs :
122- STORE [ "events" ] = list (
123- filter (
124- lambda e : set ( kwargs [ "tags__exact" ]) == set ( e . tags ) ,
125- STORE [ "events" ],
149+ if "tags__len" in kwargs :
150+ queryset . __store = list (
151+ filter (
152+ lambda e : len ( e . tags ) == kwargs [ "tags__len" ],
153+ queryset . __store ,
154+ )
126155 )
127- )
156+ return queryset
157+
158+ def union (self , * args ):
159+ queryset = FakeQuerySet ()
160+ queryset .__store = self .__store
161+ for arg in args :
162+ queryset .__store += arg .__store
163+ return queryset
128164
129- def mock_queryset_filter (* args , ** kwargs ):
130- filter_events (** kwargs )
131- return m_queryset
165+ def none (self ):
166+ queryset = FakeQuerySet ()
167+ queryset .__store = []
168+ return queryset
132169
133- def mock_queryset_none (* args , ** kwargs ):
134- STORE ["events" ] = []
135- return m_queryset
170+ def count (self ):
171+ return len (self .__store )
136172
137- def mock_queryset_count (* args , ** kwargs ):
138- return len (STORE ["events" ])
173+ def distinct (self ):
174+ queryset = FakeQuerySet ()
175+ queryset .__store = []
176+ for event in self .__store :
177+ if event not in queryset .__store :
178+ queryset .__store .append (event )
179+ queryset .__store = sorted (queryset .__store , key = lambda e : e .name )
180+ return queryset
139181
140- m_queryset .all .return_value = m_queryset
141- m_queryset .filter .side_effect = mock_queryset_filter
142- m_queryset .none .side_effect = mock_queryset_none
143- m_queryset .count .side_effect = mock_queryset_count
144- m_queryset .__getitem__ .side_effect = lambda index : STORE [
145- "events"
146- ].__getitem__ (index )
182+ def __getitem__ (self , index ):
183+ return self .__store [index ]
147184
148- return m_queryset
185+ return FakeQuerySet ()
149186
150187 return Query
188+
189+
190+ @pytest .fixture
191+ def schema (Query ):
192+ return graphene .Schema (query = Query )
0 commit comments