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

1import pytest 

2 

3import prisma 

4from prisma import Prisma 

5 

6 

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 

17 

18 posts = await client.post.find_many(where={'OR': [{'title': 'Test post 1'}, {'title': 'Test post 2'}]}) 

19 assert len(posts) == 2 

20 

21 posts = await client.post.find_many(where={'title': {'contains': 'Test post'}}) 

22 assert len(posts) == 2 

23 

24 posts = await client.post.find_many(where={'title': {'startswith': 'Test post'}}) 

25 assert len(posts) == 2 

26 

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' 

30 

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' 

34 

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' 

38 

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' 

43 

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' 

48 

49 

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' 

71 

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' 

82 

83 

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'}) 

111 

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 

126 

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' 

144 

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' 

158 

159 

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'}) 

187 

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' 

204 

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' 

222 

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' 

236 

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 

247 

248 

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}) 

256 

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 

265 

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 

274 

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 ) 

288 

289 

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 ) 

306 

307 assert exc.match(r'Expected a minimum of 0 and at most 1 fields to be present, got 2') 

308 

309 

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 

315 

316 

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 ) 

362 

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' 

372 

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' 

382 

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'