Coverage for databases/tests/test_find_many.py: 100%
125 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
1import pytest
3import prisma
4from prisma import Prisma
7@pytest.mark.asyncio
8async def test_find_many(client: Prisma) -> None:
9 """Filters and ordering work as suggested"""
10 posts = [
11 await client.post.create({'title': 'Test post 1', 'published': False}),
12 await client.post.create({'title': 'Test post 2', 'published': False}),
13 ]
14 found = await client.post.find_many(where={'title': 'Test post 1'})
15 assert len(found) == 1
16 assert found[0].id == posts[0].id
18 posts = await client.post.find_many(where={'OR': [{'title': 'Test post 1'}, {'title': 'Test post 2'}]})
19 assert len(posts) == 2
21 posts = await client.post.find_many(where={'title': {'contains': 'Test post'}})
22 assert len(posts) == 2
24 posts = await client.post.find_many(where={'title': {'startswith': 'Test post'}})
25 assert len(posts) == 2
27 posts = await client.post.find_many(where={'title': {'not_in': ['Test post 1']}})
28 assert len(posts) == 1
29 assert posts[0].title == 'Test post 2'
31 posts = await client.post.find_many(where={'title': {'equals': 'Test post 2'}})
32 assert len(posts) == 1
33 assert posts[0].title == 'Test post 2'
35 posts = await client.post.find_many(where={'title': 'Test post 2'})
36 assert len(posts) == 1
37 assert posts[0].title == 'Test post 2'
39 posts = await client.post.find_many(order={'title': 'desc'})
40 assert len(posts) == 2
41 assert posts[0].title == 'Test post 2'
42 assert posts[1].title == 'Test post 1'
44 posts = await client.post.find_many(order={'title': 'asc'})
45 assert len(posts) == 2
46 assert posts[0].title == 'Test post 1'
47 assert posts[1].title == 'Test post 2'
50@pytest.mark.asyncio
51async def test_cursor(client: Prisma) -> None:
52 """Cursor argument correctly paginates results"""
53 posts = [
54 await client.post.create({'title': 'Foo 1', 'published': False}),
55 await client.post.create({'title': 'Foo 2', 'published': False}),
56 await client.post.create({'title': 'Foo 3', 'published': False}),
57 await client.post.create({'title': 'Foo 4', 'published': False}),
58 ]
59 found = await client.post.find_many(
60 cursor={
61 'id': posts[1].id,
62 },
63 order={
64 'title': 'asc',
65 },
66 )
67 assert len(found) == 3
68 assert found[0].title == 'Foo 2'
69 assert found[1].title == 'Foo 3'
70 assert found[2].title == 'Foo 4'
72 found = await client.post.find_many(
73 cursor={
74 'id': posts[3].id,
75 },
76 order={
77 'title': 'asc',
78 },
79 )
80 assert len(found) == 1
81 assert found[0].title == 'Foo 4'
84@pytest.mark.asyncio
85async def test_filtering_one_to_one_relation(client: Prisma) -> None:
86 """Filtering by a 1-1 relational field and negating the filter"""
87 async with client.batch_() as batcher:
88 batcher.user.create(
89 {
90 'name': 'Robert',
91 'profile': {
92 'create': {
93 'description': 'My very cool bio.',
94 'country': 'Scotland',
95 }
96 },
97 },
98 )
99 batcher.user.create(
100 {
101 'name': 'Tegan',
102 'profile': {
103 'create': {
104 'description': 'Hello world, this is my bio.',
105 'country': 'Scotland',
106 },
107 },
108 },
109 )
110 batcher.user.create({'name': 'Callum'})
112 users = await client.user.find_many(
113 where={
114 'profile': {
115 'is': {
116 'description': {
117 'contains': 'cool',
118 }
119 }
120 }
121 }
122 )
123 assert len(users) == 1
124 assert users[0].name == 'Robert'
125 assert users[0].profile is None
127 users = await client.user.find_many(
128 where={
129 'profile': {
130 'is': {
131 'description': {
132 'contains': 'bio',
133 },
134 },
135 },
136 },
137 order={
138 'name': 'asc',
139 },
140 )
141 assert len(users) == 2
142 assert users[0].name == 'Robert'
143 assert users[1].name == 'Tegan'
145 users = await client.user.find_many(
146 where={
147 'profile': {
148 'is_not': {
149 'description': {
150 'contains': 'bio',
151 }
152 }
153 }
154 }
155 )
156 assert len(users) == 1
157 assert users[0].name == 'Callum'
160@pytest.mark.asyncio
161async def test_filtering_one_to_many_relation(client: Prisma) -> None:
162 """Filtering by a 1-M relational field and negating the filter"""
163 async with client.batch_() as batcher:
164 batcher.user.create(
165 {
166 'name': 'Robert',
167 'posts': {
168 'create': [
169 {'title': 'My first post', 'published': True},
170 {'title': 'My second post', 'published': False},
171 ]
172 },
173 }
174 )
175 batcher.user.create(
176 {
177 'name': 'Tegan',
178 'posts': {
179 'create': [
180 {'title': 'Hello, world!', 'published': True},
181 {'title': 'My test post', 'published': False},
182 ]
183 },
184 }
185 )
186 batcher.user.create({'name': 'Callum'})
188 # I guess it makes sense that a record with no relations also matches this
189 # TODO: this needs to be documented
190 users = await client.user.find_many(
191 where={
192 'posts': {
193 'every': {
194 'title': {
195 'contains': 'post',
196 }
197 }
198 }
199 },
200 )
201 assert len(users) == 2
202 assert users[0].name == 'Robert'
203 assert users[1].name == 'Callum'
205 users = await client.user.find_many(
206 where={
207 'posts': {
208 'some': {
209 'title': {
210 'contains': 'post',
211 }
212 }
213 }
214 },
215 order={
216 'name': 'asc',
217 },
218 )
219 assert len(users) == 2
220 assert users[0].name == 'Robert'
221 assert users[1].name == 'Tegan'
223 users = await client.user.find_many(
224 where={
225 'posts': {
226 'none': {
227 'title': {
228 'contains': 'post',
229 }
230 }
231 }
232 }
233 )
234 assert len(users) == 1
235 assert users[0].name == 'Callum'
237 users = await client.user.find_many(
238 where={
239 'posts': {
240 'some': {
241 'title': 'foo',
242 }
243 }
244 }
245 )
246 assert len(users) == 0
249@pytest.mark.asyncio
250async def test_ordering(client: Prisma) -> None:
251 """Ordering by `asc` and `desc` correctly changes the order of the returned records"""
252 async with client.batch_() as batcher:
253 batcher.post.create({'title': 'Test post 1', 'published': False})
254 batcher.post.create({'title': 'Test post 2', 'published': False})
255 batcher.post.create({'title': 'Test post 3', 'published': True})
257 found = await client.post.find_many(
258 where={'title': {'contains': 'Test'}},
259 order={'published': 'asc'},
260 )
261 assert len(found) == 3
262 assert found[0].published is False
263 assert found[1].published is False
264 assert found[2].published is True
266 found = await client.post.find_many(
267 where={'title': {'contains': 'Test'}},
268 order={'published': 'desc'},
269 )
270 assert len(found) == 3
271 assert found[0].published is True
272 assert found[1].published is False
273 assert found[2].published is False
275 # multiple fields in the same `order` dictionary are not supported
276 with pytest.raises(prisma.errors.DataError):
277 await client.post.find_many(
278 where={
279 'title': {
280 'contains': 'Test',
281 },
282 },
283 order={ # type: ignore
284 'published': 'desc',
285 'title': 'desc',
286 },
287 )
290@pytest.mark.asyncio
291@pytest.mark.skip(reason='incorrect error is raised here - requires an overhaul of the error system')
292async def test_too_many_fields_error(client: Prisma) -> None:
293 """Passing in multiple fields in order is not supported"""
294 with pytest.raises(prisma.errors.DataError) as exc:
295 await client.post.find_many(
296 where={
297 'title': {
298 'contains': 'Test',
299 },
300 },
301 order={ # type: ignore
302 'published': 'desc',
303 'title': 'desc',
304 },
305 )
307 assert exc.match(r'Expected a minimum of 0 and at most 1 fields to be present, got 2')
310@pytest.mark.asyncio
311async def test_order_field_not_nullable(client: Prisma) -> None:
312 """Order by fields, if present, cannot be None"""
313 with pytest.raises(prisma.errors.FieldNotFoundError, match=r'orderBy.desc'):
314 await client.post.find_many(order={'desc': None}) # type: ignore
317@pytest.mark.asyncio
318async def test_distinct(client: Prisma) -> None:
319 """Filtering by distinct combinations of fields"""
320 users = [
321 await client.user.create(
322 data={
323 'name': 'Robert',
324 },
325 ),
326 await client.user.create(
327 data={
328 'name': 'Tegan',
329 },
330 ),
331 await client.user.create(
332 data={
333 'name': 'Patrick',
334 },
335 ),
336 ]
337 async with client.batch_() as batcher:
338 batcher.profile.create(
339 {
340 'city': 'Paris',
341 'country': 'France',
342 'description': 'Foo',
343 'user_id': users[0].id,
344 }
345 )
346 batcher.profile.create(
347 {
348 'city': 'Lyon',
349 'country': 'France',
350 'description': 'Foo',
351 'user_id': users[1].id,
352 }
353 )
354 batcher.profile.create(
355 {
356 'city': 'Paris',
357 'country': 'Denmark',
358 'description': 'Foo',
359 'user_id': users[2].id,
360 }
361 )
363 results = await client.profile.find_many(
364 distinct=['country'],
365 order={
366 'country': 'asc',
367 },
368 )
369 assert len(results) == 2
370 assert results[0].country == 'Denmark'
371 assert results[1].country == 'France'
373 results = await client.profile.find_many(
374 distinct=['city'],
375 order={
376 'city': 'asc',
377 },
378 )
379 assert len(results) == 2
380 assert results[0].city == 'Lyon'
381 assert results[1].city == 'Paris'
383 results = await client.profile.find_many(
384 distinct=['city', 'country'],
385 order=[
386 {
387 'city': 'asc',
388 },
389 {
390 'country': 'asc',
391 },
392 ],
393 )
394 assert len(results) == 3
395 assert results[0].city == 'Lyon'
396 assert results[0].country == 'France'
397 assert results[1].city == 'Paris'
398 assert results[1].country == 'Denmark'
399 assert results[2].city == 'Paris'
400 assert results[2].country == 'France'