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