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