1use crate::prelude::*;
5use hashbrown::HashMap;
6
7#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
8pub async fn crud_user_todos(test: &mut Test) -> Result<()> {
9 let mut db = setup(test).await;
10
11 let user = User::create().name("User 1").exec(&mut db).await?;
13
14 assert_eq!(0, user.todos().exec(&mut db).await?.len());
16
17 let todo = user
19 .todos()
20 .create()
21 .title("hello world")
22 .exec(&mut db)
23 .await?;
24
25 let list = Todo::filter_by_id(todo.id).exec(&mut db).await?;
27
28 assert_eq!(1, list.len());
29 assert_eq!(todo.id, list[0].id);
30
31 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
33
34 assert_eq!(1, list.len());
35 assert_eq!(todo.id, list[0].id);
36
37 let user_reload = User::get_by_id(&mut db, &todo.user_id).await?;
39 assert_eq!(user.id, user_reload.id);
40
41 let mut created = HashMap::new();
42 let mut ids = vec![todo.id];
43 created.insert(todo.id, todo);
44
45 for i in 0..5 {
47 let title = format!("hello world {i}");
48
49 let todo = if i.is_even() {
50 user.todos().create().title(title).exec(&mut db).await?
52 } else {
53 Todo::create()
55 .user(&user)
56 .title(title)
57 .exec(&mut db)
58 .await?
59 };
60
61 ids.push(todo.id);
62 assert_none!(created.insert(todo.id, todo));
63 }
64
65 let list = user.todos().exec(&mut db).await?;
67
68 assert_eq!(6, list.len());
69
70 let loaded: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
71 assert_eq!(6, loaded.len());
72
73 for (id, expect) in &created {
74 assert_eq!(expect.title, loaded[id].title);
75 }
76
77 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
79 assert_eq!(6, list.len());
80
81 let by_id: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
82
83 assert_eq!(6, by_id.len());
84
85 for (id, expect) in by_id {
86 assert_eq!(expect.title, loaded[&id].title);
87 }
88
89 let user2 = User::create().name("User 2").exec(&mut db).await?;
91
92 assert_eq!(0, user2.todos().exec(&mut db).await?.len());
94
95 let u2_todo = user2
97 .todos()
98 .create()
99 .title("user 2 todo")
100 .exec(&mut db)
101 .await?;
102
103 {
104 let u1_todos = user.todos().exec(&mut db).await?;
105
106 for todo in u1_todos {
107 assert_ne!(u2_todo.id, todo.id);
108 }
109 }
110
111 let todo = Todo::get_by_id(&mut db, &ids[0]).await?;
113 todo.delete().exec(&mut db).await?;
114
115 assert_err!(Todo::get_by_id(&mut db, &ids[0]).await);
117
118 assert_err!(user.todos().get_by_id(&mut db, &ids[0]).await);
120
121 user.todos()
123 .filter_by_id(ids[1])
124 .delete()
125 .exec(&mut db)
126 .await?;
127
128 assert_err!(Todo::get_by_id(&mut db, &ids[1]).await);
130
131 assert_err!(user.todos().get_by_id(&mut db, &ids[1]).await);
133
134 user.todos()
136 .filter_by_id(ids[2])
137 .update()
138 .title("batch update 1")
139 .exec(&mut db)
140 .await?;
141
142 let todo = Todo::get_by_id(&mut db, &ids[2]).await?;
143 assert_eq!(todo.title, "batch update 1");
144
145 user2
147 .todos()
148 .filter_by_id(ids[2])
149 .update()
150 .title("batch update 2")
151 .exec(&mut db)
152 .await?;
153
154 let todo = Todo::get_by_id(&mut db, &ids[2]).await?;
155 assert_eq!(todo.title, "batch update 1");
156
157 let id = user.id;
158
159 user.delete().exec(&mut db).await?;
161 assert_err!(User::get_by_id(&mut db, &id).await);
162 assert_err!(Todo::get_by_id(&mut db, &ids[2]).await);
163 Ok(())
164}
165
166#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
167pub async fn has_many_insert_on_update(test: &mut Test) -> Result<()> {
168 let mut db = setup(test).await;
169
170 let mut user = User::create().name("Alice").exec(&mut db).await?;
172 assert!(user.todos().exec(&mut db).await?.is_empty());
173
174 user.update()
176 .name("Bob")
177 .todos(toasty::stmt::insert(Todo::create().title("change name")))
178 .exec(&mut db)
179 .await?;
180
181 assert_eq!("Bob", user.name);
182 let todos: Vec<_> = user.todos().exec(&mut db).await?;
183 assert_eq!(1, todos.len());
184 assert_eq!(todos[0].title, "change name");
185 Ok(())
186}
187
188#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
194pub async fn has_many_apply_empty_is_noop(test: &mut Test) -> Result<()> {
195 let mut db = setup(test).await;
196
197 let mut user = User::create().name("Alice").exec(&mut db).await?;
198 user.todos()
199 .create()
200 .title("existing")
201 .exec(&mut db)
202 .await?;
203
204 user.update()
205 .name("Bob")
206 .todos(toasty::stmt::apply::<toasty::stmt::List<Todo>>([]))
207 .exec(&mut db)
208 .await?;
209
210 assert_eq!(user.name, "Bob");
211 let todos: Vec<_> = user.todos().exec(&mut db).await?;
212 assert_eq!(todos.len(), 1);
213 assert_eq!(todos[0].title, "existing");
214 Ok(())
215}
216
217#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
218pub async fn has_many_apply_multiple_inserts(test: &mut Test) -> Result<()> {
219 let mut db = setup(test).await;
220
221 let mut user = User::create().name("Alice").exec(&mut db).await?;
222
223 user.update()
224 .todos(toasty::stmt::apply([
225 toasty::stmt::insert(Todo::create().title("Buy groceries")),
226 toasty::stmt::insert(Todo::create().title("Walk the dog")),
227 ]))
228 .exec(&mut db)
229 .await?;
230
231 let mut titles: Vec<_> = user
232 .todos()
233 .exec(&mut db)
234 .await?
235 .into_iter()
236 .map(|t| t.title)
237 .collect();
238 titles.sort();
239 assert_eq!(titles, ["Buy groceries", "Walk the dog"]);
240 Ok(())
241}
242
243#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
246pub async fn has_many_update_remove(test: &mut Test) -> Result<()> {
247 let mut db = setup(test).await;
248
249 let mut user = User::create().name("Alice").exec(&mut db).await?;
250 let old_todo = user.todos().create().title("old").exec(&mut db).await?;
251
252 user.update()
253 .todos(toasty::stmt::remove(&old_todo))
254 .exec(&mut db)
255 .await?;
256
257 assert_eq!(0, user.todos().exec(&mut db).await?.len());
258 Ok(())
259}
260
261#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
266pub async fn has_many_apply_insert_and_remove(test: &mut Test) -> Result<()> {
267 let mut db = setup(test).await;
268
269 let mut user = User::create().name("Alice").exec(&mut db).await?;
270 let old_todo = user.todos().create().title("old").exec(&mut db).await?;
271
272 user.update()
273 .todos(toasty::stmt::apply([
274 toasty::stmt::insert(Todo::create().title("new")),
275 toasty::stmt::remove(&old_todo),
276 ]))
277 .exec(&mut db)
278 .await?;
279
280 let titles: Vec<_> = user
281 .todos()
282 .exec(&mut db)
283 .await?
284 .into_iter()
285 .map(|t| t.title)
286 .collect();
287 assert_eq!(titles, ["new"]);
288 Ok(())
289}
290
291#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
296pub async fn has_many_apply_remove_then_insert(test: &mut Test) -> Result<()> {
297 let mut db = setup(test).await;
298
299 let mut user = User::create().name("Alice").exec(&mut db).await?;
300 let old_todo = user.todos().create().title("old").exec(&mut db).await?;
301
302 user.update()
303 .todos(toasty::stmt::apply([
304 toasty::stmt::remove(&old_todo),
305 toasty::stmt::insert(Todo::create().title("new")),
306 ]))
307 .exec(&mut db)
308 .await?;
309
310 let titles: Vec<_> = user
311 .todos()
312 .exec(&mut db)
313 .await?
314 .into_iter()
315 .map(|t| t.title)
316 .collect();
317 assert_eq!(titles, ["new"]);
318 Ok(())
319}
320
321#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
325pub async fn has_many_apply_two_inserts_and_remove(test: &mut Test) -> Result<()> {
326 let mut db = setup(test).await;
327
328 let mut user = User::create().name("Alice").exec(&mut db).await?;
329 let old_todo = user.todos().create().title("old").exec(&mut db).await?;
330
331 user.update()
332 .todos(toasty::stmt::apply([
333 toasty::stmt::insert(Todo::create().title("a")),
334 toasty::stmt::insert(Todo::create().title("b")),
335 toasty::stmt::remove(&old_todo),
336 ]))
337 .exec(&mut db)
338 .await?;
339
340 let mut titles: Vec<_> = user
341 .todos()
342 .exec(&mut db)
343 .await?
344 .into_iter()
345 .map(|t| t.title)
346 .collect();
347 titles.sort();
348 assert_eq!(titles, ["a", "b"]);
349 Ok(())
350}
351
352#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
356pub async fn has_many_apply_multiple_removes(test: &mut Test) -> Result<()> {
357 let mut db = setup(test).await;
358
359 let mut user = User::create().name("Alice").exec(&mut db).await?;
360 let t1 = user.todos().create().title("t1").exec(&mut db).await?;
361 let t2 = user.todos().create().title("t2").exec(&mut db).await?;
362 let t3 = user.todos().create().title("keep").exec(&mut db).await?;
363
364 user.update()
365 .todos(toasty::stmt::apply([
366 toasty::stmt::remove(&t1),
367 toasty::stmt::remove(&t2),
368 ]))
369 .exec(&mut db)
370 .await?;
371
372 let titles: Vec<_> = user
373 .todos()
374 .exec(&mut db)
375 .await?
376 .into_iter()
377 .map(|t| t.title)
378 .collect();
379 assert_eq!(titles, ["keep"]);
380
381 assert_err!(Todo::get_by_id(&mut db, &t1.id).await);
383 assert_err!(Todo::get_by_id(&mut db, &t2.id).await);
384 assert_ok!(Todo::get_by_id(&mut db, &t3.id).await);
385 Ok(())
386}
387
388#[driver_test(id(ID), scenario(crate::scenarios::has_many_nullable_fk))]
393pub async fn has_many_apply_insert_and_remove_nullable_fk(test: &mut Test) -> Result<()> {
394 let mut db = setup(test).await;
395
396 let mut user = User::create().exec(&mut db).await?;
397 let old_todo = user.todos().create().title("old").exec(&mut db).await?;
398
399 user.update()
400 .todos(toasty::stmt::apply([
401 toasty::stmt::insert(Todo::create().title("new")),
402 toasty::stmt::remove(&old_todo),
403 ]))
404 .exec(&mut db)
405 .await?;
406
407 let titles: Vec<_> = user
408 .todos()
409 .exec(&mut db)
410 .await?
411 .into_iter()
412 .map(|t| t.title)
413 .collect();
414 assert_eq!(titles, ["new"]);
415
416 let reloaded = Todo::get_by_id(&mut db, &old_todo.id).await?;
418 assert_none!(reloaded.user_id);
419 Ok(())
420}
421
422#[driver_test(id(ID), scenario(crate::scenarios::has_many_unique_title))]
431pub async fn has_many_apply_swap_unique_required_fk(test: &mut Test) -> Result<()> {
432 let mut db = setup(test).await;
433
434 let mut user = User::create().exec(&mut db).await?;
435 let old = user.todos().create().title("X").exec(&mut db).await?;
436
437 user.update()
438 .todos(toasty::stmt::apply([
439 toasty::stmt::remove(&old),
440 toasty::stmt::insert(Todo::create().title("X")),
441 ]))
442 .exec(&mut db)
443 .await?;
444
445 let titles: Vec<_> = user
446 .todos()
447 .exec(&mut db)
448 .await?
449 .into_iter()
450 .map(|t| t.title)
451 .collect();
452 assert_eq!(titles, ["X"]);
453 Ok(())
454}
455
456#[driver_test(id(ID), scenario(crate::scenarios::has_many_unique_title))]
463pub async fn has_many_apply_swap_unique_with_extra_insert(test: &mut Test) -> Result<()> {
464 let mut db = setup(test).await;
465
466 let mut user = User::create().exec(&mut db).await?;
467 let old = user.todos().create().title("X").exec(&mut db).await?;
468
469 user.update()
470 .todos(toasty::stmt::apply([
471 toasty::stmt::insert(Todo::create().title("Y")),
472 toasty::stmt::remove(&old),
473 toasty::stmt::insert(Todo::create().title("X")),
474 ]))
475 .exec(&mut db)
476 .await?;
477
478 let mut titles: Vec<_> = user
479 .todos()
480 .exec(&mut db)
481 .await?
482 .into_iter()
483 .map(|t| t.title)
484 .collect();
485 titles.sort();
486 assert_eq!(titles, ["X", "Y"]);
487 Ok(())
488}
489
490#[driver_test(id(ID), scenario(crate::scenarios::has_many_nullable_fk))]
500pub async fn has_many_apply_insert_remove_same_item(test: &mut Test) -> Result<()> {
501 use toasty_core::{
502 driver::Operation,
503 stmt::{Assignment, ExprSet, Statement, Update},
504 };
505
506 fn fk_writes(test: &Test) -> Vec<&'static str> {
511 fn classify(update: &Update, out: &mut Vec<&'static str>) {
512 for (_, assignment) in update.assignments.iter() {
513 if let Assignment::Set(expr) = assignment {
514 out.push(if expr.is_value_null() {
515 "unlink"
516 } else {
517 "link"
518 });
519 }
520 }
521 }
522
523 let mut out = vec![];
524 while !test.log().is_empty() {
525 let Operation::QuerySql(q) = test.log().pop().0 else {
526 continue;
527 };
528 match &q.stmt {
529 Statement::Update(update) => classify(update, &mut out),
533 Statement::Query(query) => {
537 for cte in query.with.iter().flat_map(|with| &with.ctes) {
538 if let ExprSet::Update(update) = &cte.query.body {
539 classify(update, &mut out);
540 }
541 }
542 }
543 _ => {}
544 }
545 }
546 out
547 }
548
549 let mut db = setup(test).await;
550
551 let mut keep = User::create().exec(&mut db).await?;
553 let kt = keep.todos().create().title("t").exec(&mut db).await?;
554 test.log().clear();
555 keep.update()
556 .todos(toasty::stmt::apply([
557 toasty::stmt::remove(&kt),
558 toasty::stmt::insert(&kt),
559 ]))
560 .exec(&mut db)
561 .await?;
562 if test.capability().sql {
563 assert_eq!(fk_writes(test), ["unlink", "link"]);
565 }
566 assert_eq!(keep.todos().exec(&mut db).await?.len(), 1);
567
568 let mut drop = User::create().exec(&mut db).await?;
570 let dt = drop.todos().create().title("t").exec(&mut db).await?;
571 test.log().clear();
572 drop.update()
573 .todos(toasty::stmt::apply([
574 toasty::stmt::insert(&dt),
575 toasty::stmt::remove(&dt),
576 ]))
577 .exec(&mut db)
578 .await?;
579 if test.capability().sql {
580 assert_eq!(fk_writes(test), ["link", "unlink"]);
582 }
583 assert_eq!(drop.todos().exec(&mut db).await?.len(), 0);
584 Ok(())
585}
586
587#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
594pub async fn has_many_apply_nested(test: &mut Test) -> Result<()> {
595 let mut db = setup(test).await;
596
597 let mut user = User::create().name("Alice").exec(&mut db).await?;
598 let old1 = user.todos().create().title("old1").exec(&mut db).await?;
599 let old2 = user.todos().create().title("old2").exec(&mut db).await?;
600
601 user.update()
602 .todos(toasty::stmt::apply([
603 toasty::stmt::apply([
604 toasty::stmt::insert(Todo::create().title("a")),
605 toasty::stmt::insert(Todo::create().title("b")),
606 ]),
607 toasty::stmt::apply([toasty::stmt::remove(&old1), toasty::stmt::remove(&old2)]),
608 toasty::stmt::insert(Todo::create().title("c")),
609 ]))
610 .exec(&mut db)
611 .await?;
612
613 let mut titles: Vec<_> = user
614 .todos()
615 .exec(&mut db)
616 .await?
617 .into_iter()
618 .map(|t| t.title)
619 .collect();
620 titles.sort();
621 assert_eq!(titles, ["a", "b", "c"]);
622 Ok(())
623}
624
625#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
633pub async fn has_many_apply_combinations(test: &mut Test) -> Result<()> {
634 let mut db = setup(test).await;
635
636 for num_existing in 0..=3usize {
637 for num_insert in 0..=3usize {
638 for num_remove in 0..=num_existing {
639 if num_insert == 0 && num_remove == 0 {
643 continue;
644 }
645
646 let mut user = User::create()
647 .name(format!("u-{num_existing}-{num_insert}-{num_remove}"))
648 .exec(&mut db)
649 .await?;
650
651 let mut existing = Vec::new();
653 for i in 0..num_existing {
654 existing.push(
655 user.todos()
656 .create()
657 .title(format!("e{i}"))
658 .exec(&mut db)
659 .await?,
660 );
661 }
662
663 let mut ops: Vec<toasty::stmt::Assignment<toasty::stmt::List<Todo>>> = Vec::new();
665 for i in 0..num_insert {
666 ops.push(toasty::stmt::insert(Todo::create().title(format!("n{i}"))));
667 }
668 for todo in &existing[..num_remove] {
669 ops.push(toasty::stmt::remove(todo));
670 }
671
672 user.update()
673 .todos(toasty::stmt::apply(ops))
674 .exec(&mut db)
675 .await?;
676
677 let mut expected: Vec<String> = existing[num_remove..]
679 .iter()
680 .map(|t| t.title.clone())
681 .collect();
682 for i in 0..num_insert {
683 expected.push(format!("n{i}"));
684 }
685 expected.sort();
686
687 let mut actual: Vec<String> = user
688 .todos()
689 .exec(&mut db)
690 .await?
691 .into_iter()
692 .map(|t| t.title)
693 .collect();
694 actual.sort();
695
696 assert_eq!(
697 actual, expected,
698 "existing={num_existing} insert={num_insert} remove={num_remove}"
699 );
700 }
701 }
702 }
703 Ok(())
704}
705
706#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
707pub async fn scoped_find_by_id(test: &mut Test) -> Result<()> {
708 let mut db = setup(test).await;
709
710 let user1 = User::create().name("User 1").exec(&mut db).await?;
712 let user2 = User::create().name("User 2").exec(&mut db).await?;
713
714 let todo = user1
716 .todos()
717 .create()
718 .title("hello world")
719 .exec(&mut db)
720 .await?;
721
722 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
724 assert_eq!(reloaded.id, todo.id);
725 assert_eq!(reloaded.title, todo.title);
726
727 assert_none!(
729 user2
730 .todos()
731 .filter_by_id(todo.id)
732 .first()
733 .exec(&mut db)
734 .await?
735 );
736
737 let reloaded = User::filter_by_id(user1.id)
738 .todos()
739 .get_by_id(&mut db, &todo.id)
740 .await?;
741
742 assert_eq!(reloaded.id, todo.id);
743 assert_eq!(reloaded.title, todo.title);
744
745 user2
747 .todos()
748 .filter_by_id(todo.id)
749 .delete()
750 .exec(&mut db)
751 .await?;
752 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
753 assert_eq!(reloaded.id, todo.id);
754 Ok(())
755}
756
757#[driver_test(id(ID))]
760pub async fn has_many_on_target_pk(_test: &mut Test) {}
761
762#[driver_test(id(ID))]
765pub async fn has_many_when_target_indexes_fk_and_pk(_test: &mut Test) {}
766
767#[driver_test(id(ID), scenario(crate::scenarios::composite_has_many_belongs_to))]
769pub async fn has_many_when_fk_is_composite(test: &mut Test) -> Result<()> {
770 let mut db = setup(test).await;
771
772 let user = User::create().name("User 1").exec(&mut db).await?;
774
775 assert_eq!(0, user.todos().exec(&mut db).await?.len());
777
778 let todo = user
780 .todos()
781 .create()
782 .title("hello world")
783 .exec(&mut db)
784 .await?;
785
786 let list = Todo::filter_by_user_id_and_id(user.id, todo.id)
788 .exec(&mut db)
789 .await?;
790
791 assert_eq!(1, list.len());
792 assert_eq!(todo.id, list[0].id);
793
794 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
796
797 assert_eq!(1, list.len());
798 assert_eq!(todo.id, list[0].id);
799
800 let mut created = HashMap::new();
801 let mut ids = vec![todo.id];
802 created.insert(todo.id, todo);
803
804 for i in 0..5 {
806 let title = format!("hello world {i}");
807
808 let todo = if i.is_even() {
809 user.todos().create().title(title).exec(&mut db).await?
811 } else {
812 Todo::create()
814 .user(&user)
815 .title(title)
816 .exec(&mut db)
817 .await?
818 };
819
820 ids.push(todo.id);
821 assert_none!(created.insert(todo.id, todo));
822 }
823
824 let list = user.todos().exec(&mut db).await?;
826
827 assert_eq!(6, list.len());
828
829 let loaded: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
830 assert_eq!(6, loaded.len());
831
832 for (id, expect) in &created {
833 assert_eq!(expect.title, loaded[id].title);
834 }
835
836 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
838 assert_eq!(6, list.len());
839
840 let by_id: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
841
842 assert_eq!(6, by_id.len());
843
844 for (id, expect) in by_id {
845 assert_eq!(expect.title, loaded[&id].title);
846 }
847
848 let user2 = User::create().name("User 2").exec(&mut db).await?;
850
851 assert_eq!(0, user2.todos().exec(&mut db).await?.len());
853
854 let u2_todo = user2
856 .todos()
857 .create()
858 .title("user 2 todo")
859 .exec(&mut db)
860 .await?;
861
862 let u1_todos = user.todos().exec(&mut db).await?;
863
864 for todo in u1_todos {
865 assert_ne!(u2_todo.id, todo.id);
866 }
867
868 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await?;
870 todo.delete().exec(&mut db).await?;
871
872 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await);
874
875 assert_err!(user.todos().get_by_id(&mut db, &ids[0]).await);
877
878 user.todos()
880 .filter_by_id(ids[1])
881 .delete()
882 .exec(&mut db)
883 .await?;
884
885 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[1]).await);
887
888 assert_err!(user.todos().get_by_id(&mut db, &ids[1]).await);
890
891 user.todos()
893 .filter_by_id(ids[2])
894 .update()
895 .title("batch update 1")
896 .exec(&mut db)
897 .await?;
898 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
899 assert_eq!(todo.title, "batch update 1");
900
901 user2
903 .todos()
904 .filter_by_id(ids[2])
905 .update()
906 .title("batch update 2")
907 .exec(&mut db)
908 .await?;
909 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
910 assert_eq!(todo.title, "batch update 1");
911 Ok(())
912}
913
914#[driver_test(id(ID))]
916pub async fn has_many_when_pk_is_composite(_test: &mut Test) {}
917
918#[driver_test(id(ID))]
920pub async fn has_many_when_fk_and_pk_are_composite(_test: &mut Test) {}
921
922#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
923pub async fn belongs_to_required(test: &mut Test) {
924 let mut db = setup(test).await;
925
926 assert_err!(Todo::create().exec(&mut db).await);
927}
928
929#[driver_test(id(ID), scenario(crate::scenarios::has_many_nullable_fk))]
930pub async fn delete_when_belongs_to_optional(test: &mut Test) -> Result<()> {
931 let mut db = setup(test).await;
932
933 let user = User::create().exec(&mut db).await?;
934 let mut ids = vec![];
935
936 for _ in 0..3 {
937 let todo = user.todos().create().title("todo").exec(&mut db).await?;
938 ids.push(todo.id);
939 }
940
941 user.delete().exec(&mut db).await?;
943
944 for id in ids {
946 let todo = Todo::get_by_id(&mut db, id).await?;
947 assert_none!(todo.user_id);
948 }
949
950 Ok(())
952}
953
954#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
955pub async fn associate_new_user_with_todo_on_update_via_creation(test: &mut Test) -> Result<()> {
956 let mut db = setup(test).await;
957
958 let u1 = User::create()
960 .name("User 1")
961 .todos([Todo::create().title("hello world")])
962 .exec(&mut db)
963 .await?;
964
965 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
967 assert_eq!(1, todos.len());
968 let mut todo = todos.into_iter().next().unwrap();
969
970 todo.update()
971 .user(User::create().name("User 2"))
972 .exec(&mut db)
973 .await?;
974 Ok(())
975}
976
977#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
978pub async fn associate_new_user_with_todo_on_update_query_via_creation(
979 test: &mut Test,
980) -> Result<()> {
981 let mut db = setup(test).await;
982
983 let u1 = User::create()
985 .name("User 1")
986 .todos([Todo::create().title("a todo")])
987 .exec(&mut db)
988 .await?;
989
990 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
992 assert_eq!(1, todos.len());
993 let todo = todos.into_iter().next().unwrap();
994
995 Todo::filter_by_id(todo.id)
996 .update()
997 .user(User::create().name("User 2"))
998 .exec(&mut db)
999 .await?;
1000 Ok(())
1001}
1002
1003#[driver_test(id(ID))]
1004#[should_panic]
1005pub async fn update_user_with_null_todo_is_err(test: &mut Test) -> Result<()> {
1006 #[derive(Debug, toasty::Model)]
1007 struct User {
1008 #[key]
1009 #[auto]
1010 id: ID,
1011
1012 #[has_many]
1013 todos: toasty::Deferred<Vec<Todo>>,
1014 }
1015
1016 #[derive(Debug, toasty::Model)]
1017 struct Todo {
1018 #[key]
1019 #[auto]
1020 id: ID,
1021
1022 #[index]
1023 user_id: ID,
1024
1025 #[belongs_to(key = user_id, references = id)]
1026 user: toasty::Deferred<User>,
1027 }
1028
1029 use toasty::stmt::{self, IntoExpr};
1030
1031 let mut db = test.setup_db(models!(User, Todo)).await;
1032
1033 let u1 = User::create().todos([Todo::create()]).exec(&mut db).await?;
1035
1036 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
1038 assert_eq!(1, todos.len());
1039 let todo = todos.into_iter().next().unwrap();
1040
1041 let mut stmt: stmt::Update<Todo> =
1043 stmt::Update::new(stmt::Query::from_expr((&todo).into_expr()));
1044 stmt.set(2, toasty_core::stmt::Value::Null);
1045 stmt.exec(&mut db).await?;
1046
1047 let u1_reloaded = User::get_by_id(&mut db, &u1.id).await?;
1049 assert_eq!(u1_reloaded.id, u1.id);
1050 Ok(())
1051}
1052
1053#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
1054pub async fn assign_todo_that_already_has_user_on_create(test: &mut Test) -> Result<()> {
1055 let mut db = setup(test).await;
1056
1057 let todo = Todo::create()
1058 .title("a todo")
1059 .user(User::create().name("User 1"))
1060 .exec(&mut db)
1061 .await?;
1062
1063 let u1 = todo.user().exec(&mut db).await?;
1064
1065 let u2 = User::create()
1066 .name("User 2")
1067 .todos([&todo])
1068 .exec(&mut db)
1069 .await?;
1070
1071 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
1072
1073 assert_eq!(u2.id, todo_reload.user_id);
1074
1075 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
1077 assert_eq!(0, todos.len());
1078
1079 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
1081 assert_eq!(1, todos.len());
1082 assert_eq!(todo.id, todos[0].id);
1083 Ok(())
1084}
1085
1086#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
1087pub async fn assign_todo_that_already_has_user_on_update(test: &mut Test) -> Result<()> {
1088 let mut db = setup(test).await;
1089
1090 let todo = Todo::create()
1091 .title("a todo")
1092 .user(User::create().name("User 1"))
1093 .exec(&mut db)
1094 .await?;
1095
1096 let u1 = todo.user().exec(&mut db).await?;
1097
1098 let mut u2 = User::create().name("User 2").exec(&mut db).await?;
1099
1100 u2.update()
1102 .todos(toasty::stmt::insert(&todo))
1103 .exec(&mut db)
1104 .await?;
1105
1106 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
1107
1108 assert_eq!(u2.id, todo_reload.user_id);
1109
1110 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
1112 assert_eq!(0, todos.len());
1113
1114 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
1116 assert_eq!(1, todos.len());
1117 assert_eq!(todo.id, todos[0].id);
1118 Ok(())
1119}
1120
1121#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
1122pub async fn assign_existing_user_to_todo(test: &mut Test) -> Result<()> {
1123 let mut db = setup(test).await;
1124
1125 let mut todo = Todo::create()
1126 .title("hello")
1127 .user(User::create().name("User 1"))
1128 .exec(&mut db)
1129 .await?;
1130
1131 let u1 = todo.user().exec(&mut db).await?;
1132
1133 let u2 = User::create().name("User 2").exec(&mut db).await?;
1134
1135 todo.update().user(&u2).exec(&mut db).await?;
1137
1138 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
1139
1140 assert_eq!(u2.id, todo_reload.user_id);
1141
1142 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
1144 assert_eq!(0, todos.len());
1145
1146 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
1148 assert_eq!(1, todos.len());
1149 assert_eq!(todo.id, todos[0].id);
1150 Ok(())
1151}
1152
1153#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
1154pub async fn assign_todo_to_user_on_update_query(test: &mut Test) -> Result<()> {
1155 let mut db = setup(test).await;
1156
1157 let user = User::create().name("User 1").exec(&mut db).await?;
1158
1159 User::filter_by_id(user.id)
1160 .update()
1161 .todos(toasty::stmt::insert(Todo::create().title("hello")))
1162 .exec(&mut db)
1163 .await?;
1164
1165 let todos: Vec<_> = user.todos().exec(&mut db).await?;
1166 assert_eq!(1, todos.len());
1167 assert_eq!("hello", todos[0].title);
1168 Ok(())
1169}
1170
1171#[driver_test(id(ID), scenario(crate::scenarios::composite_has_many_belongs_to))]
1172pub async fn has_many_when_fk_is_composite_with_snippets(test: &mut Test) -> Result<()> {
1173 let mut db = setup(test).await;
1174
1175 let user1 = User::create().name("User 1").exec(&mut db).await?;
1177 let user2 = User::create().name("User 2").exec(&mut db).await?;
1178
1179 user1
1181 .todos()
1182 .create()
1183 .title("hello world")
1184 .exec(&mut db)
1185 .await?;
1186
1187 let todo2 = user2
1188 .todos()
1189 .create()
1190 .title("hello world")
1191 .exec(&mut db)
1192 .await?;
1193
1194 Todo::update_by_user_id(user1.id)
1196 .title("Title 2")
1197 .exec(&mut db)
1198 .await?;
1199
1200 let todo = Todo::get_by_user_id(&mut db, user1.id).await?;
1201 assert!(todo.title == "Title 2");
1202
1203 Todo::update_by_user_id_and_id(user2.id, todo2.id)
1204 .title("Title 3")
1205 .exec(&mut db)
1206 .await?;
1207
1208 let todo = Todo::get_by_user_id_and_id(&mut db, user2.id, todo2.id).await?;
1209 assert!(todo.title == "Title 3");
1210
1211 Todo::delete_by_user_id(&mut db, user1.id).await?;
1213 assert_err!(Todo::get_by_user_id(&mut db, user1.id).await);
1214
1215 Todo::delete_by_user_id_and_id(&mut db, user2.id, todo2.id).await?;
1216 assert_err!(Todo::get_by_user_id_and_id(&mut db, user2.id, todo2.id).await);
1217
1218 Ok(())
1219}