1use crate::prelude::*;
2
3#[driver_test(
5 requires(sql),
6 scenario(crate::scenarios::has_many_belongs_to_with_flags)
7)]
8pub async fn preload_has_many_ordered_per_parent(test: &mut Test) -> Result<()> {
9 let mut db = setup(test).await;
10
11 toasty::create!(User::[
12 {
13 name: "alice",
14 todos: [
15 { title: "b", complete: false, priority: 2 },
16 { title: "a", complete: false, priority: 2 },
17 { title: "c", complete: false, priority: 1 },
18 ]
19 },
20 {
21 name: "bob",
22 todos: [
23 { title: "z", complete: false, priority: 1 },
24 { title: "y", complete: false, priority: 1 },
25 { title: "x", complete: false, priority: 3 },
26 ]
27 },
28 ])
29 .exec(&mut db)
30 .await?;
31
32 let tuple_ordered: Vec<User> = User::all()
33 .order_by(User::fields().name().asc())
34 .include(User::fields().todos().order_by((
35 Todo::fields().priority().desc(),
36 Todo::fields().title().asc(),
37 )))
38 .exec(&mut db)
39 .await?;
40
41 assert_struct!(tuple_ordered, [
42 { name: "alice", todos.get(): [{ title: "a" }, { title: "b" }, { title: "c" }] },
43 { name: "bob", todos.get(): [{ title: "x" }, { title: "y" }, { title: "z" }] },
44 ]);
45
46 let chained_ordered: Vec<User> = User::all()
47 .order_by(User::fields().name().asc())
48 .include(
49 User::fields()
50 .todos()
51 .order_by(Todo::fields().priority().desc())
52 .order_by(Todo::fields().title().asc()),
53 )
54 .exec(&mut db)
55 .await?;
56
57 assert_struct!(chained_ordered, [
58 { name: "alice", todos.get(): [{ title: "a" }, { title: "b" }, { title: "c" }] },
59 { name: "bob", todos.get(): [{ title: "x" }, { title: "y" }, { title: "z" }] },
60 ]);
61
62 Ok(())
63}
64
65#[driver_test(
67 requires(sql),
68 scenario(crate::scenarios::has_many_belongs_to::id_uuid)
69)]
70pub async fn preload_has_many_filter_and_order(test: &mut Test) -> Result<()> {
71 let mut db = setup(test).await;
72
73 let user = toasty::create!(User {
74 name: "alice",
75 todos: [{ title: "a" }, { title: "c" }, { title: "b" }]
76 })
77 .exec(&mut db)
78 .await?;
79
80 let loaded = User::filter_by_id(user.id)
81 .include(
82 User::fields()
83 .todos()
84 .filter(Todo::fields().title().ne("c"))
85 .order_by(Todo::fields().title().desc()),
86 )
87 .get(&mut db)
88 .await?;
89
90 assert_struct!(loaded.todos.get(), [
91 { title: "b" },
92 { title: "a" },
93 ]);
94
95 Ok(())
96}
97
98#[driver_test(requires(sql), scenario(crate::scenarios::user_post_comment))]
100pub async fn preload_nested_relations_ordered_at_each_level(test: &mut Test) -> Result<()> {
101 let mut db = setup(test).await;
102
103 let user = toasty::create!(User {
104 name: "alice",
105 posts: [
106 {
107 title: "b",
108 comments: [{ body: "a" }, { body: "c" }, { body: "b" }]
109 },
110 {
111 title: "a",
112 comments: [{ body: "x" }, { body: "z" }, { body: "y" }]
113 },
114 ]
115 })
116 .exec(&mut db)
117 .await?;
118
119 let loaded = User::filter_by_id(user.id)
120 .include(
121 User::fields()
122 .posts()
123 .order_by(Post::fields().title().asc()),
124 )
125 .include(
126 User::fields()
127 .posts()
128 .comments()
129 .order_by(Comment::fields().body().desc()),
130 )
131 .get(&mut db)
132 .await?;
133
134 assert_struct!(loaded.posts.get(), [
135 { title: "a", comments.get(): [{ body: "z" }, { body: "y" }, { body: "x" }] },
136 { title: "b", comments.get(): [{ body: "c" }, { body: "b" }, { body: "a" }] },
137 ]);
138
139 Ok(())
140}
141
142#[driver_test(requires(sql))]
144pub async fn preload_modifiers_with_reserved_field_names(test: &mut Test) -> Result<()> {
145 #[derive(Debug, toasty::Model)]
146 struct Parent {
147 #[key]
148 #[auto]
149 id: uuid::Uuid,
150
151 #[has_many]
152 children: toasty::Deferred<Vec<Child>>,
153 }
154
155 #[derive(Debug, toasty::Model)]
156 struct Child {
157 #[key]
158 #[auto]
159 id: uuid::Uuid,
160
161 filter: String,
162 order_by: String,
163 rank: i64,
164
165 #[index]
166 parent_id: uuid::Uuid,
167
168 #[belongs_to(key = parent_id, references = id)]
169 parent: toasty::Deferred<Parent>,
170 }
171
172 let mut db = test.setup_db(models!(Parent, Child)).await;
173
174 let parent = toasty::create!(Parent {
175 children: [
176 { filter: "a", order_by: "a", rank: 1 },
177 { filter: "b", order_by: "b", rank: 3 },
178 { filter: "c", order_by: "c", rank: 2 },
179 ]
180 })
181 .exec(&mut db)
182 .await?;
183
184 let parent = Parent::filter_by_id(parent.id)
185 .include(
186 Parent::fields()
187 .children()
188 .filter(Child::fields().rank().gt(1))
189 .order_by(Child::fields().rank().desc()),
190 )
191 .get(&mut db)
192 .await?;
193
194 assert_struct!(parent.children.get(), [
195 { rank: 3 },
196 { rank: 2 },
197 ]);
198
199 Ok(())
200}
201
202#[driver_test(
204 requires(sql),
205 scenario(crate::scenarios::has_many_belongs_to::id_uuid)
206)]
207pub async fn preload_has_many_repeated_ordering_last_wins(test: &mut Test) -> Result<()> {
208 use toasty_core::{driver::Operation, stmt::Statement};
209
210 let mut db = setup(test).await;
211
212 let user = toasty::create!(User {
213 name: "alice",
214 todos: [{ title: "a" }, { title: "c" }, { title: "b" }]
215 })
216 .exec(&mut db)
217 .await?;
218
219 let loaded = User::filter_by_id(user.id)
220 .include(
221 User::fields()
222 .todos()
223 .order_by(Todo::fields().title().asc()),
224 )
225 .include(
226 User::fields()
227 .todos()
228 .order_by(Todo::fields().title().desc()),
229 )
230 .get(&mut db)
231 .await?;
232
233 assert_struct!(loaded.todos.get(), [
234 { title: "c" },
235 { title: "b" },
236 { title: "a" },
237 ]);
238
239 test.log().clear();
240
241 let loaded = User::filter_by_id(user.id)
242 .include(
243 User::fields()
244 .todos()
245 .order_by(Todo::fields().title().desc()),
246 )
247 .include(User::fields().todos())
248 .get(&mut db)
249 .await?;
250
251 assert_eq!(loaded.todos.get().len(), 3);
252
253 let _ = test.log().pop_last_op(); assert_struct!(test.log().pop_last_op(), Operation::QuerySql({
255 stmt: Statement::Query({ order_by: None }),
256 }));
257
258 Ok(())
259}
260
261#[driver_test(
263 requires(sql),
264 scenario(crate::scenarios::has_many_belongs_to_with_flags)
265)]
266pub async fn preload_has_many_limit_per_parent(test: &mut Test) -> Result<()> {
267 let mut db = setup(test).await;
268
269 toasty::create!(User::[
270 {
271 name: "alice",
272 todos: [
273 { title: "b", complete: false, priority: 2 },
274 { title: "a", complete: false, priority: 2 },
275 { title: "c", complete: false, priority: 1 },
276 ]
277 },
278 {
279 name: "bob",
280 todos: [
281 { title: "z", complete: false, priority: 1 },
282 { title: "y", complete: false, priority: 1 },
283 { title: "x", complete: false, priority: 3 },
284 ]
285 },
286 ])
287 .exec(&mut db)
288 .await?;
289
290 let users: Vec<User> = User::all()
291 .order_by(User::fields().name().asc())
292 .include(
293 User::fields()
294 .todos()
295 .order_by(Todo::fields().title().asc())
296 .limit(2),
297 )
298 .exec(&mut db)
299 .await?;
300
301 assert_struct!(users, [
302 { name: "alice", todos.get(): [{ title: "a" }, { title: "b" }] },
303 { name: "bob", todos.get(): [{ title: "x" }, { title: "y" }] },
304 ]);
305
306 Ok(())
307}
308
309#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
313pub async fn preload_has_many_limit_without_order(test: &mut Test) -> Result<()> {
314 let mut db = setup(test).await;
315
316 for (name, titles) in [("alice", ["a", "b", "c"]), ("bob", ["x", "y", "z"])] {
320 let user = toasty::create!(User { name }).exec(&mut db).await?;
321
322 for title in titles {
323 user.todos().create().title(title).exec(&mut db).await?;
324 }
325 }
326
327 let users: Vec<User> = User::all()
328 .include(User::fields().todos().limit(2))
329 .exec(&mut db)
330 .await?;
331
332 assert_struct!(users, [
333 { todos.get().len(): 2 },
334 { todos.get().len(): 2 },
335 ]);
336
337 Ok(())
338}
339
340#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::has_many_belongs_to))]
342pub async fn preload_has_many_limit_with_filter(test: &mut Test) -> Result<()> {
343 let mut db = setup(test).await;
344
345 let user = toasty::create!(User { name: "alice" })
349 .exec(&mut db)
350 .await?;
351
352 for title in ["a", "c", "b", "d"] {
353 user.todos().create().title(title).exec(&mut db).await?;
354 }
355
356 let loaded = User::filter_by_id(user.id)
357 .include(
358 User::fields()
359 .todos()
360 .filter(Todo::fields().title().ne("c"))
361 .order_by(Todo::fields().title().desc())
362 .limit(2),
363 )
364 .get(&mut db)
365 .await?;
366
367 assert_struct!(loaded.todos.get(), [
368 { title: "d" },
369 { title: "b" },
370 ]);
371
372 Ok(())
373}
374
375#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::has_many_belongs_to))]
378pub async fn preload_has_many_limit_bounds(test: &mut Test) -> Result<()> {
379 let mut db = setup(test).await;
380
381 let user = toasty::create!(User { name: "alice" })
385 .exec(&mut db)
386 .await?;
387
388 for title in ["a", "b"] {
389 user.todos().create().title(title).exec(&mut db).await?;
390 }
391
392 let loaded = User::filter_by_id(user.id)
393 .include(
394 User::fields()
395 .todos()
396 .order_by(Todo::fields().title().asc())
397 .limit(10),
398 )
399 .get(&mut db)
400 .await?;
401
402 assert_struct!(loaded.todos.get(), [
403 { title: "a" },
404 { title: "b" },
405 ]);
406
407 let loaded = User::filter_by_id(user.id)
408 .include(User::fields().todos().limit(0))
409 .get(&mut db)
410 .await?;
411
412 assert!(loaded.todos.get().is_empty());
413
414 Ok(())
415}
416
417#[driver_test(requires(sql), scenario(crate::scenarios::user_post_comment))]
419pub async fn preload_nested_relations_limited_at_each_level(test: &mut Test) -> Result<()> {
420 let mut db = setup(test).await;
421
422 let user = toasty::create!(User {
423 name: "alice",
424 posts: [
425 {
426 title: "a",
427 comments: [{ body: "a" }, { body: "c" }, { body: "b" }]
428 },
429 {
430 title: "b",
431 comments: [{ body: "x" }, { body: "z" }, { body: "y" }]
432 },
433 {
434 title: "c",
435 comments: [{ body: "q" }]
436 },
437 ]
438 })
439 .exec(&mut db)
440 .await?;
441
442 let loaded = User::filter_by_id(user.id)
443 .include(
444 User::fields()
445 .posts()
446 .order_by(Post::fields().title().asc())
447 .limit(2),
448 )
449 .include(
450 User::fields()
451 .posts()
452 .comments()
453 .order_by(Comment::fields().body().desc())
454 .limit(2),
455 )
456 .get(&mut db)
457 .await?;
458
459 assert_struct!(loaded.posts.get(), [
460 { title: "a", comments.get(): [{ body: "c" }, { body: "b" }] },
461 { title: "b", comments.get(): [{ body: "z" }, { body: "y" }] },
462 ]);
463
464 Ok(())
465}
466
467#[driver_test(
469 requires(sql),
470 scenario(crate::scenarios::has_many_belongs_to_with_flags)
471)]
472pub async fn preload_has_many_offset_per_parent(test: &mut Test) -> Result<()> {
473 let mut db = setup(test).await;
474
475 toasty::create!(User::[
476 {
477 name: "alice",
478 todos: [
479 { title: "b", complete: false, priority: 2 },
480 { title: "a", complete: false, priority: 2 },
481 { title: "c", complete: false, priority: 1 },
482 ]
483 },
484 {
485 name: "bob",
486 todos: [
487 { title: "z", complete: false, priority: 1 },
488 { title: "y", complete: false, priority: 1 },
489 { title: "x", complete: false, priority: 3 },
490 ]
491 },
492 ])
493 .exec(&mut db)
494 .await?;
495
496 let users: Vec<User> = User::all()
497 .order_by(User::fields().name().asc())
498 .include(
499 User::fields()
500 .todos()
501 .order_by(Todo::fields().title().asc())
502 .limit(2)
503 .offset(1),
504 )
505 .exec(&mut db)
506 .await?;
507
508 assert_struct!(users, [
509 { name: "alice", todos.get(): [{ title: "b" }, { title: "c" }] },
510 { name: "bob", todos.get(): [{ title: "y" }, { title: "z" }] },
511 ]);
512
513 Ok(())
514}
515
516#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
520pub async fn preload_has_many_offset_without_order(test: &mut Test) -> Result<()> {
521 let mut db = setup(test).await;
522
523 for (name, titles) in [("alice", ["a", "b", "c"]), ("bob", ["x", "y", "z"])] {
527 let user = toasty::create!(User { name }).exec(&mut db).await?;
528
529 for title in titles {
530 user.todos().create().title(title).exec(&mut db).await?;
531 }
532 }
533
534 let users: Vec<User> = User::all()
535 .include(User::fields().todos().limit(2).offset(2))
536 .exec(&mut db)
537 .await?;
538
539 assert_struct!(users, [
540 { todos.get().len(): 1 },
541 { todos.get().len(): 1 },
542 ]);
543
544 Ok(())
545}
546
547#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::has_many_belongs_to))]
549pub async fn preload_has_many_offset_with_filter(test: &mut Test) -> Result<()> {
550 let mut db = setup(test).await;
551
552 let user = toasty::create!(User { name: "alice" })
556 .exec(&mut db)
557 .await?;
558
559 for title in ["a", "c", "b", "d"] {
560 user.todos().create().title(title).exec(&mut db).await?;
561 }
562
563 let loaded = User::filter_by_id(user.id)
564 .include(
565 User::fields()
566 .todos()
567 .filter(Todo::fields().title().ne("c"))
568 .order_by(Todo::fields().title().desc())
569 .limit(2)
570 .offset(1),
571 )
572 .get(&mut db)
573 .await?;
574
575 assert_struct!(loaded.todos.get(), [
576 { title: "b" },
577 { title: "a" },
578 ]);
579
580 Ok(())
581}
582
583#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::has_many_belongs_to))]
586pub async fn preload_has_many_offset_bounds(test: &mut Test) -> Result<()> {
587 let mut db = setup(test).await;
588
589 let user = toasty::create!(User { name: "alice" })
593 .exec(&mut db)
594 .await?;
595
596 for title in ["a", "b"] {
597 user.todos().create().title(title).exec(&mut db).await?;
598 }
599
600 let loaded = User::filter_by_id(user.id)
601 .include(
602 User::fields()
603 .todos()
604 .order_by(Todo::fields().title().asc())
605 .limit(10)
606 .offset(10),
607 )
608 .get(&mut db)
609 .await?;
610
611 assert!(loaded.todos.get().is_empty());
612
613 let loaded = User::filter_by_id(user.id)
614 .include(
615 User::fields()
616 .todos()
617 .order_by(Todo::fields().title().asc())
618 .limit(10)
619 .offset(0),
620 )
621 .get(&mut db)
622 .await?;
623
624 assert_struct!(loaded.todos.get(), [
625 { title: "a" },
626 { title: "b" },
627 ]);
628
629 Ok(())
630}
631
632#[driver_test(requires(sql), scenario(crate::scenarios::user_post_comment))]
634pub async fn preload_nested_relations_offset_at_each_level(test: &mut Test) -> Result<()> {
635 let mut db = setup(test).await;
636
637 let user = toasty::create!(User {
638 name: "alice",
639 posts: [
640 {
641 title: "a",
642 comments: [{ body: "a" }, { body: "c" }, { body: "b" }]
643 },
644 {
645 title: "b",
646 comments: [{ body: "x" }, { body: "z" }, { body: "y" }]
647 },
648 {
649 title: "c",
650 comments: [{ body: "q" }]
651 },
652 ]
653 })
654 .exec(&mut db)
655 .await?;
656
657 let loaded = User::filter_by_id(user.id)
658 .include(
659 User::fields()
660 .posts()
661 .order_by(Post::fields().title().asc())
662 .limit(2)
663 .offset(1),
664 )
665 .include(
666 User::fields()
667 .posts()
668 .comments()
669 .order_by(Comment::fields().body().asc())
670 .limit(2)
671 .offset(1),
672 )
673 .get(&mut db)
674 .await?;
675
676 assert_struct!(loaded.posts.get(), [
677 { title: "b", comments.get(): [{ body: "y" }, { body: "z" }] },
678 { title: "c", comments.get(): [] },
679 ]);
680
681 Ok(())
682}
683
684#[driver_test(scenario(crate::scenarios::has_one_optional_belongs_to::id_uuid))]
686pub async fn preload_has_one_ordering_rejected(test: &mut Test) -> Result<()> {
687 let mut db = setup(test).await;
688
689 let err = assert_err!(
690 User::all()
691 .include(
692 User::fields()
693 .profile()
694 .order_by(Profile::fields().bio().asc()),
695 )
696 .exec(&mut db)
697 .await
698 );
699
700 assert!(err.is_invalid_statement(), "unexpected error: {err}");
701
702 Ok(())
703}
704
705#[driver_test(id(ID), scenario(crate::scenarios::has_one_optional_belongs_to))]
707pub async fn preload_has_one_limit_rejected(test: &mut Test) -> Result<()> {
708 let mut db = setup(test).await;
709
710 let err = assert_err!(
711 User::all()
712 .include(User::fields().profile().limit(1))
713 .exec(&mut db)
714 .await
715 );
716
717 assert!(err.is_invalid_statement(), "unexpected error: {err}");
718
719 Ok(())
720}