1use crate::prelude::*;
5use std::collections::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))]
189pub async fn scoped_find_by_id(test: &mut Test) -> Result<()> {
190 let mut db = setup(test).await;
191
192 let user1 = User::create().name("User 1").exec(&mut db).await?;
194 let user2 = User::create().name("User 2").exec(&mut db).await?;
195
196 let todo = user1
198 .todos()
199 .create()
200 .title("hello world")
201 .exec(&mut db)
202 .await?;
203
204 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
206 assert_eq!(reloaded.id, todo.id);
207 assert_eq!(reloaded.title, todo.title);
208
209 assert_none!(
211 user2
212 .todos()
213 .filter_by_id(todo.id)
214 .first()
215 .exec(&mut db)
216 .await?
217 );
218
219 let reloaded = User::filter_by_id(user1.id)
220 .todos()
221 .get_by_id(&mut db, &todo.id)
222 .await?;
223
224 assert_eq!(reloaded.id, todo.id);
225 assert_eq!(reloaded.title, todo.title);
226
227 user2
229 .todos()
230 .filter_by_id(todo.id)
231 .delete()
232 .exec(&mut db)
233 .await?;
234 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
235 assert_eq!(reloaded.id, todo.id);
236 Ok(())
237}
238
239#[driver_test(id(ID))]
242pub async fn has_many_on_target_pk(_test: &mut Test) {}
243
244#[driver_test(id(ID))]
247pub async fn has_many_when_target_indexes_fk_and_pk(_test: &mut Test) {}
248
249#[driver_test(id(ID))]
251pub async fn has_many_when_fk_is_composite(test: &mut Test) -> Result<()> {
252 #[derive(Debug, toasty::Model)]
253 struct User {
254 #[key]
255 #[auto]
256 id: ID,
257
258 #[has_many]
259 todos: toasty::HasMany<Todo>,
260 }
261
262 #[derive(Debug, toasty::Model)]
263 #[key(partition = user_id, local = id)]
264 struct Todo {
265 #[auto]
266 id: uuid::Uuid,
267
268 user_id: ID,
269
270 #[belongs_to(key = user_id, references = id)]
271 user: toasty::BelongsTo<User>,
272
273 title: String,
274 }
275
276 let mut db = test.setup_db(models!(User, Todo)).await;
277
278 let user = User::create().exec(&mut db).await?;
280
281 assert_eq!(0, user.todos().exec(&mut db).await?.len());
283
284 let todo = user
286 .todos()
287 .create()
288 .title("hello world")
289 .exec(&mut db)
290 .await?;
291
292 let list = Todo::filter_by_user_id_and_id(user.id, todo.id)
294 .exec(&mut db)
295 .await?;
296
297 assert_eq!(1, list.len());
298 assert_eq!(todo.id, list[0].id);
299
300 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
302
303 assert_eq!(1, list.len());
304 assert_eq!(todo.id, list[0].id);
305
306 let mut created = HashMap::new();
307 let mut ids = vec![todo.id];
308 created.insert(todo.id, todo);
309
310 for i in 0..5 {
312 let title = format!("hello world {i}");
313
314 let todo = if i.is_even() {
315 user.todos().create().title(title).exec(&mut db).await?
317 } else {
318 Todo::create()
320 .user(&user)
321 .title(title)
322 .exec(&mut db)
323 .await?
324 };
325
326 ids.push(todo.id);
327 assert_none!(created.insert(todo.id, todo));
328 }
329
330 let list = user.todos().exec(&mut db).await?;
332
333 assert_eq!(6, list.len());
334
335 let loaded: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
336 assert_eq!(6, loaded.len());
337
338 for (id, expect) in &created {
339 assert_eq!(expect.title, loaded[id].title);
340 }
341
342 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
344 assert_eq!(6, list.len());
345
346 let by_id: HashMap<_, _> = list.into_iter().map(|todo| (todo.id, todo)).collect();
347
348 assert_eq!(6, by_id.len());
349
350 for (id, expect) in by_id {
351 assert_eq!(expect.title, loaded[&id].title);
352 }
353
354 let user2 = User::create().exec(&mut db).await?;
356
357 assert_eq!(0, user2.todos().exec(&mut db).await?.len());
359
360 let u2_todo = user2
362 .todos()
363 .create()
364 .title("user 2 todo")
365 .exec(&mut db)
366 .await?;
367
368 let u1_todos = user.todos().exec(&mut db).await?;
369
370 for todo in u1_todos {
371 assert_ne!(u2_todo.id, todo.id);
372 }
373
374 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await?;
376 todo.delete().exec(&mut db).await?;
377
378 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await);
380
381 assert_err!(user.todos().get_by_id(&mut db, &ids[0]).await);
383
384 user.todos()
386 .filter_by_id(ids[1])
387 .delete()
388 .exec(&mut db)
389 .await?;
390
391 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[1]).await);
393
394 assert_err!(user.todos().get_by_id(&mut db, &ids[1]).await);
396
397 user.todos()
399 .filter_by_id(ids[2])
400 .update()
401 .title("batch update 1")
402 .exec(&mut db)
403 .await?;
404 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
405 assert_eq!(todo.title, "batch update 1");
406
407 user2
409 .todos()
410 .filter_by_id(ids[2])
411 .update()
412 .title("batch update 2")
413 .exec(&mut db)
414 .await?;
415 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
416 assert_eq!(todo.title, "batch update 1");
417 Ok(())
418}
419
420#[driver_test(id(ID))]
422pub async fn has_many_when_pk_is_composite(_test: &mut Test) {}
423
424#[driver_test(id(ID))]
426pub async fn has_many_when_fk_and_pk_are_composite(_test: &mut Test) {}
427
428#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
429pub async fn belongs_to_required(test: &mut Test) {
430 let mut db = setup(test).await;
431
432 assert_err!(Todo::create().exec(&mut db).await);
433}
434
435#[driver_test(id(ID))]
436pub async fn delete_when_belongs_to_optional(test: &mut Test) -> Result<()> {
437 #[derive(Debug, toasty::Model)]
438 struct User {
439 #[key]
440 #[auto]
441 id: ID,
442
443 #[has_many]
444 todos: toasty::HasMany<Todo>,
445 }
446
447 #[derive(Debug, toasty::Model)]
448 struct Todo {
449 #[key]
450 #[auto]
451 id: ID,
452
453 #[index]
454 user_id: Option<ID>,
455
456 #[belongs_to(key = user_id, references = id)]
457 user: toasty::BelongsTo<Option<User>>,
458 }
459
460 let mut db = test.setup_db(models!(User, Todo)).await;
461
462 let user = User::create().exec(&mut db).await?;
463 let mut ids = vec![];
464
465 for _ in 0..3 {
466 let todo = user.todos().create().exec(&mut db).await?;
467 ids.push(todo.id);
468 }
469
470 user.delete().exec(&mut db).await?;
472
473 for id in ids {
475 let todo = Todo::get_by_id(&mut db, id).await?;
476 assert_none!(todo.user_id);
477 }
478
479 Ok(())
481}
482
483#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
484pub async fn associate_new_user_with_todo_on_update_via_creation(test: &mut Test) -> Result<()> {
485 let mut db = setup(test).await;
486
487 let u1 = User::create()
489 .name("User 1")
490 .todo(Todo::create().title("hello world"))
491 .exec(&mut db)
492 .await?;
493
494 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
496 assert_eq!(1, todos.len());
497 let mut todo = todos.into_iter().next().unwrap();
498
499 todo.update()
500 .user(User::create().name("User 2"))
501 .exec(&mut db)
502 .await?;
503 Ok(())
504}
505
506#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
507pub async fn associate_new_user_with_todo_on_update_query_via_creation(
508 test: &mut Test,
509) -> Result<()> {
510 let mut db = setup(test).await;
511
512 let u1 = User::create()
514 .name("User 1")
515 .todo(Todo::create().title("a todo"))
516 .exec(&mut db)
517 .await?;
518
519 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
521 assert_eq!(1, todos.len());
522 let todo = todos.into_iter().next().unwrap();
523
524 Todo::filter_by_id(todo.id)
525 .update()
526 .user(User::create().name("User 2"))
527 .exec(&mut db)
528 .await?;
529 Ok(())
530}
531
532#[driver_test(id(ID))]
533#[should_panic]
534pub async fn update_user_with_null_todo_is_err(test: &mut Test) -> Result<()> {
535 #[derive(Debug, toasty::Model)]
536 struct User {
537 #[key]
538 #[auto]
539 id: ID,
540
541 #[has_many]
542 todos: toasty::HasMany<Todo>,
543 }
544
545 #[derive(Debug, toasty::Model)]
546 struct Todo {
547 #[key]
548 #[auto]
549 id: ID,
550
551 #[index]
552 user_id: ID,
553
554 #[belongs_to(key = user_id, references = id)]
555 user: toasty::BelongsTo<User>,
556 }
557
558 use toasty::stmt::{self, IntoExpr};
559
560 let mut db = test.setup_db(models!(User, Todo)).await;
561
562 let u1 = User::create().todo(Todo::create()).exec(&mut db).await?;
564
565 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
567 assert_eq!(1, todos.len());
568 let todo = todos.into_iter().next().unwrap();
569
570 let mut stmt: stmt::Update<Todo> =
572 stmt::Update::new(stmt::Query::from_expr((&todo).into_expr()));
573 stmt.set(2, toasty_core::stmt::Value::Null);
574 stmt.exec(&mut db).await?;
575
576 let u1_reloaded = User::get_by_id(&mut db, &u1.id).await?;
578 assert_eq!(u1_reloaded.id, u1.id);
579 Ok(())
580}
581
582#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
583pub async fn assign_todo_that_already_has_user_on_create(test: &mut Test) -> Result<()> {
584 let mut db = setup(test).await;
585
586 let todo = Todo::create()
587 .title("a todo")
588 .user(User::create().name("User 1"))
589 .exec(&mut db)
590 .await?;
591
592 let u1 = todo.user().exec(&mut db).await?;
593
594 let u2 = User::create()
595 .name("User 2")
596 .todo(&todo)
597 .exec(&mut db)
598 .await?;
599
600 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
601
602 assert_eq!(u2.id, todo_reload.user_id);
603
604 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
606 assert_eq!(0, todos.len());
607
608 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
610 assert_eq!(1, todos.len());
611 assert_eq!(todo.id, todos[0].id);
612 Ok(())
613}
614
615#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
616pub async fn assign_todo_that_already_has_user_on_update(test: &mut Test) -> Result<()> {
617 let mut db = setup(test).await;
618
619 let todo = Todo::create()
620 .title("a todo")
621 .user(User::create().name("User 1"))
622 .exec(&mut db)
623 .await?;
624
625 let u1 = todo.user().exec(&mut db).await?;
626
627 let mut u2 = User::create().name("User 2").exec(&mut db).await?;
628
629 u2.update()
631 .todos(toasty::stmt::insert(&todo))
632 .exec(&mut db)
633 .await?;
634
635 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
636
637 assert_eq!(u2.id, todo_reload.user_id);
638
639 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
641 assert_eq!(0, todos.len());
642
643 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
645 assert_eq!(1, todos.len());
646 assert_eq!(todo.id, todos[0].id);
647 Ok(())
648}
649
650#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
651pub async fn assign_existing_user_to_todo(test: &mut Test) -> Result<()> {
652 let mut db = setup(test).await;
653
654 let mut todo = Todo::create()
655 .title("hello")
656 .user(User::create().name("User 1"))
657 .exec(&mut db)
658 .await?;
659
660 let u1 = todo.user().exec(&mut db).await?;
661
662 let u2 = User::create().name("User 2").exec(&mut db).await?;
663
664 todo.update().user(&u2).exec(&mut db).await?;
666
667 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
668
669 assert_eq!(u2.id, todo_reload.user_id);
670
671 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
673 assert_eq!(0, todos.len());
674
675 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
677 assert_eq!(1, todos.len());
678 assert_eq!(todo.id, todos[0].id);
679 Ok(())
680}
681
682#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
683pub async fn assign_todo_to_user_on_update_query(test: &mut Test) -> Result<()> {
684 let mut db = setup(test).await;
685
686 let user = User::create().name("User 1").exec(&mut db).await?;
687
688 User::filter_by_id(user.id)
689 .update()
690 .todos(toasty::stmt::insert(Todo::create().title("hello")))
691 .exec(&mut db)
692 .await?;
693
694 let todos: Vec<_> = user.todos().exec(&mut db).await?;
695 assert_eq!(1, todos.len());
696 assert_eq!("hello", todos[0].title);
697 Ok(())
698}
699
700#[driver_test(id(ID))]
701pub async fn has_many_when_fk_is_composite_with_snippets(test: &mut Test) -> Result<()> {
702 #[derive(Debug, toasty::Model)]
703 struct User {
704 #[key]
705 #[auto]
706 id: ID,
707
708 #[has_many]
709 todos: toasty::HasMany<Todo>,
710 }
711
712 #[derive(Debug, toasty::Model)]
713 #[key(partition = user_id, local = id)]
714 struct Todo {
715 #[auto]
716 id: uuid::Uuid,
717
718 user_id: ID,
719
720 #[belongs_to(key = user_id, references = id)]
721 user: toasty::BelongsTo<User>,
722
723 title: String,
724 }
725
726 let mut db = test.setup_db(models!(User, Todo)).await;
727
728 let user1 = User::create().exec(&mut db).await?;
730 let user2 = User::create().exec(&mut db).await?;
731
732 user1
734 .todos()
735 .create()
736 .title("hello world")
737 .exec(&mut db)
738 .await?;
739
740 let todo2 = user2
741 .todos()
742 .create()
743 .title("hello world")
744 .exec(&mut db)
745 .await?;
746
747 Todo::update_by_user_id(user1.id)
749 .title("Title 2")
750 .exec(&mut db)
751 .await?;
752
753 let todo = Todo::get_by_user_id(&mut db, user1.id).await?;
754 assert!(todo.title == "Title 2");
755
756 Todo::update_by_user_id_and_id(user2.id, todo2.id)
757 .title("Title 3")
758 .exec(&mut db)
759 .await?;
760
761 let todo = Todo::get_by_user_id_and_id(&mut db, user2.id, todo2.id).await?;
762 assert!(todo.title == "Title 3");
763
764 Todo::delete_by_user_id(&mut db, user1.id).await?;
766 assert_err!(Todo::get_by_user_id(&mut db, user1.id).await);
767
768 Todo::delete_by_user_id_and_id(&mut db, user2.id, todo2.id).await?;
769 assert_err!(Todo::get_by_user_id_and_id(&mut db, user2.id, todo2.id).await);
770
771 Ok(())
772}