1use crate::prelude::*;
20use hashbrown::HashMap;
21
22#[driver_test]
26pub async fn composite_belongs_to_missing_index_is_error(test: &mut Test) -> Result<()> {
27 #[derive(Debug, toasty::Model)]
28 #[key(id, revision)]
29 struct Parent {
30 id: String,
31 revision: i64,
32
33 #[has_many]
34 children: toasty::Deferred<Vec<Child>>,
35 }
36
37 #[derive(Debug, toasty::Model)]
38 struct Child {
39 #[key]
40 id: String,
41
42 #[index]
45 parent_id: String,
46 #[index]
47 parent_revision: i64,
48
49 #[belongs_to(key = [parent_id, parent_revision], references = [id, revision])]
50 parent: toasty::Deferred<Parent>,
51 }
52
53 let err = test
54 .try_setup_db(models!(Parent, Child))
55 .await
56 .expect_err("schema verification should reject this layout");
57
58 assert!(
59 err.is_invalid_schema(),
60 "expected invalid_schema error, got: {err}",
61 );
62
63 let msg = err.to_string();
64 assert!(
65 msg.contains("parent_id") && msg.contains("parent_revision"),
66 "error should mention the foreign-key fields, got: {msg}",
67 );
68 assert!(
69 msg.contains("#[index(parent_id, parent_revision)]"),
70 "error should suggest adding a composite index, got: {msg}",
71 );
72 assert!(
76 msg.contains("each foreign-key field already has its own `#[index]`"),
77 "error should call out the per-field `#[index]` annotations, got: {msg}",
78 );
79
80 Ok(())
81}
82
83#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
89pub async fn composite_crud_user_todos(test: &mut Test) -> Result<()> {
90 let mut db = setup(test).await;
91
92 let user = User::create().name("User 1").exec(&mut db).await?;
93
94 assert_eq!(0, user.todos().exec(&mut db).await?.len());
95
96 let todo = user
97 .todos()
98 .create()
99 .title("hello world")
100 .exec(&mut db)
101 .await?;
102
103 let list = Todo::filter_by_user_id_and_id(user.id, todo.id)
105 .exec(&mut db)
106 .await?;
107 assert_eq!(1, list.len());
108 assert_eq!(todo.id, list[0].id);
109
110 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
112 assert_eq!(1, list.len());
113 assert_eq!(todo.id, list[0].id);
114
115 let user_reload = User::get_by_id(&mut db, &todo.user_id).await?;
117 assert_eq!(user.id, user_reload.id);
118
119 let mut created = HashMap::new();
120 let mut ids = vec![todo.id];
121 created.insert(todo.id, todo);
122
123 for i in 0..5 {
124 let title = format!("hello world {i}");
125 let todo = if i.is_even() {
126 user.todos().create().title(title).exec(&mut db).await?
127 } else {
128 Todo::create()
129 .user(&user)
130 .title(title)
131 .exec(&mut db)
132 .await?
133 };
134 ids.push(todo.id);
135 assert_none!(created.insert(todo.id, todo));
136 }
137
138 let list = user.todos().exec(&mut db).await?;
139 assert_eq!(6, list.len());
140
141 let loaded: HashMap<_, _> = list.into_iter().map(|t| (t.id, t)).collect();
142 assert_eq!(6, loaded.len());
143 for (id, expect) in &created {
144 assert_eq!(expect.title, loaded[id].title);
145 }
146
147 let list = Todo::filter_by_user_id(user.id).exec(&mut db).await?;
148 assert_eq!(6, list.len());
149
150 let user2 = User::create().name("User 2").exec(&mut db).await?;
151 assert_eq!(0, user2.todos().exec(&mut db).await?.len());
152
153 let u2_todo = user2
154 .todos()
155 .create()
156 .title("user 2 todo")
157 .exec(&mut db)
158 .await?;
159
160 for todo in user.todos().exec(&mut db).await? {
161 assert_ne!(u2_todo.id, todo.id);
162 }
163
164 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await?;
166 todo.delete().exec(&mut db).await?;
167 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[0]).await);
168 assert_err!(user.todos().get_by_id(&mut db, &ids[0]).await);
169
170 user.todos()
172 .filter_by_id(ids[1])
173 .delete()
174 .exec(&mut db)
175 .await?;
176 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[1]).await);
177 assert_err!(user.todos().get_by_id(&mut db, &ids[1]).await);
178
179 user.todos()
181 .filter_by_id(ids[2])
182 .update()
183 .title("batch update 1")
184 .exec(&mut db)
185 .await?;
186 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
187 assert_eq!(todo.title, "batch update 1");
188
189 user2
191 .todos()
192 .filter_by_id(ids[2])
193 .update()
194 .title("batch update 2")
195 .exec(&mut db)
196 .await?;
197 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &ids[2]).await?;
198 assert_eq!(todo.title, "batch update 1");
199
200 let id = user.id;
202 user.delete().exec(&mut db).await?;
203 assert_err!(User::get_by_id(&mut db, &id).await);
204 assert_err!(Todo::get_by_user_id_and_id(&mut db, &id, &ids[2]).await);
205 Ok(())
206}
207
208#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
209pub async fn composite_has_many_insert_on_update(test: &mut Test) -> Result<()> {
210 let mut db = setup(test).await;
211
212 let mut user = User::create().name("Alice").exec(&mut db).await?;
213 assert!(user.todos().exec(&mut db).await?.is_empty());
214
215 user.update()
216 .name("Bob")
217 .todos(toasty::stmt::insert(Todo::create().title("change name")))
218 .exec(&mut db)
219 .await?;
220
221 assert_eq!("Bob", user.name);
222 let todos: Vec<_> = user.todos().exec(&mut db).await?;
223 assert_eq!(1, todos.len());
224 assert_eq!(todos[0].title, "change name");
225 Ok(())
226}
227
228#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
229pub async fn composite_scoped_find_by_id(test: &mut Test) -> Result<()> {
230 let mut db = setup(test).await;
231
232 let user1 = User::create().name("User 1").exec(&mut db).await?;
233 let user2 = User::create().name("User 2").exec(&mut db).await?;
234
235 let todo = user1
236 .todos()
237 .create()
238 .title("hello world")
239 .exec(&mut db)
240 .await?;
241
242 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
243 assert_eq!(reloaded.id, todo.id);
244 assert_eq!(reloaded.title, todo.title);
245
246 assert_none!(
248 user2
249 .todos()
250 .filter_by_id(todo.id)
251 .first()
252 .exec(&mut db)
253 .await?
254 );
255
256 let reloaded = User::filter_by_id(user1.id)
257 .todos()
258 .get_by_id(&mut db, &todo.id)
259 .await?;
260 assert_eq!(reloaded.id, todo.id);
261
262 user2
264 .todos()
265 .filter_by_id(todo.id)
266 .delete()
267 .exec(&mut db)
268 .await?;
269 let reloaded = user1.todos().get_by_id(&mut db, &todo.id).await?;
270 assert_eq!(reloaded.id, todo.id);
271 Ok(())
272}
273
274#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
275pub async fn composite_belongs_to_required(test: &mut Test) {
276 let mut db = setup(test).await;
277 assert_err!(Todo::create().title("orphan").exec(&mut db).await);
278}
279
280#[driver_test(scenario(crate::scenarios::has_many_nullable_fk))]
281pub async fn composite_delete_when_belongs_to_optional(test: &mut Test) -> Result<()> {
282 let mut db = setup(test).await;
283
284 let user = User::create().exec(&mut db).await?;
285 let mut ids = vec![];
286
287 for _ in 0..3 {
288 let todo = user.todos().create().title("dummy").exec(&mut db).await?;
289 ids.push(todo.id);
290 }
291
292 user.delete().exec(&mut db).await?;
293
294 for id in ids {
296 let todo = Todo::get_by_id(&mut db, id).await?;
297 assert_none!(todo.user_id);
298 }
299 Ok(())
300}
301
302#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
303pub async fn composite_associate_new_user_with_todo_on_update_via_creation(
304 test: &mut Test,
305) -> Result<()> {
306 let mut db = setup(test).await;
307
308 let u1 = User::create()
309 .revision(1)
310 .name("User 1")
311 .todos([Todo::create().title("hello world")])
312 .exec(&mut db)
313 .await?;
314
315 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
316 assert_eq!(1, todos.len());
317 let mut todo = todos.into_iter().next().unwrap();
318
319 todo.update()
320 .user(User::create().revision(1).name("User 2"))
321 .exec(&mut db)
322 .await?;
323 Ok(())
324}
325
326#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
327pub async fn composite_associate_new_user_with_todo_on_update_query_via_creation(
328 test: &mut Test,
329) -> Result<()> {
330 let mut db = setup(test).await;
331
332 let u1 = User::create()
333 .revision(1)
334 .name("User 1")
335 .todos([Todo::create().title("a todo")])
336 .exec(&mut db)
337 .await?;
338
339 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
340 assert_eq!(1, todos.len());
341 let todo = todos.into_iter().next().unwrap();
342
343 Todo::filter_by_id(todo.id)
344 .update()
345 .user(User::create().revision(1).name("User 2"))
346 .exec(&mut db)
347 .await?;
348 Ok(())
349}
350
351#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
352pub async fn composite_assign_todo_that_already_has_user_on_create(test: &mut Test) -> Result<()> {
353 let mut db = setup(test).await;
354
355 let todo = Todo::create()
356 .title("a todo")
357 .user(User::create().revision(1).name("User 1"))
358 .exec(&mut db)
359 .await?;
360
361 let u1 = todo.user().exec(&mut db).await?;
362
363 let u2 = User::create()
364 .revision(1)
365 .name("User 2")
366 .todos([&todo])
367 .exec(&mut db)
368 .await?;
369
370 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
371 assert_eq!(u2.id, todo_reload.user_id);
372 assert_eq!(u2.revision, todo_reload.user_revision);
373
374 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
375 assert_eq!(0, todos.len());
376
377 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
378 assert_eq!(1, todos.len());
379 assert_eq!(todo.id, todos[0].id);
380 Ok(())
381}
382
383#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
384pub async fn composite_assign_todo_that_already_has_user_on_update(test: &mut Test) -> Result<()> {
385 let mut db = setup(test).await;
386
387 let todo = Todo::create()
388 .title("a todo")
389 .user(User::create().revision(1).name("User 1"))
390 .exec(&mut db)
391 .await?;
392
393 let u1 = todo.user().exec(&mut db).await?;
394
395 let mut u2 = User::create()
396 .revision(1)
397 .name("User 2")
398 .exec(&mut db)
399 .await?;
400
401 u2.update()
402 .todos(toasty::stmt::insert(&todo))
403 .exec(&mut db)
404 .await?;
405
406 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
407 assert_eq!(u2.id, todo_reload.user_id);
408 assert_eq!(u2.revision, todo_reload.user_revision);
409
410 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
411 assert_eq!(0, todos.len());
412
413 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
414 assert_eq!(1, todos.len());
415 assert_eq!(todo.id, todos[0].id);
416 Ok(())
417}
418
419#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
420pub async fn composite_assign_existing_user_to_todo(test: &mut Test) -> Result<()> {
421 let mut db = setup(test).await;
422
423 let mut todo = Todo::create()
424 .title("hello")
425 .user(User::create().revision(1).name("User 1"))
426 .exec(&mut db)
427 .await?;
428
429 let u1 = todo.user().exec(&mut db).await?;
430 let u2 = User::create()
431 .revision(1)
432 .name("User 2")
433 .exec(&mut db)
434 .await?;
435
436 todo.update().user(&u2).exec(&mut db).await?;
437
438 let todo_reload = Todo::get_by_id(&mut db, &todo.id).await?;
439 assert_eq!(u2.id, todo_reload.user_id);
440 assert_eq!(u2.revision, todo_reload.user_revision);
441
442 let todos: Vec<_> = u1.todos().exec(&mut db).await?;
443 assert_eq!(0, todos.len());
444
445 let todos: Vec<_> = u2.todos().exec(&mut db).await?;
446 assert_eq!(1, todos.len());
447 assert_eq!(todo.id, todos[0].id);
448 Ok(())
449}
450
451#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
452pub async fn composite_assign_todo_to_user_on_update_query(test: &mut Test) -> Result<()> {
453 let mut db = setup(test).await;
454
455 let user = User::create().name("User 1").exec(&mut db).await?;
456
457 User::filter_by_id(user.id)
458 .update()
459 .todos(toasty::stmt::insert(Todo::create().title("hello")))
460 .exec(&mut db)
461 .await?;
462
463 let todos: Vec<_> = user.todos().exec(&mut db).await?;
464 assert_eq!(1, todos.len());
465 assert_eq!("hello", todos[0].title);
466 Ok(())
467}
468
469#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
475pub async fn composite_user_batch_create_todos_one_level(test: &mut Test) -> Result<()> {
476 let mut db = setup(test).await;
477
478 let user = User::create()
479 .name("Ann Chovey")
480 .todos([Todo::create().title("Make pizza")])
481 .exec(&mut db)
482 .await?;
483
484 assert_eq!(user.name, "Ann Chovey");
485
486 let todos: Vec<_> = user.todos().exec(&mut db).await?;
487 assert_eq!(1, todos.len());
488 assert_eq!("Make pizza", todos[0].title);
489
490 let todo = Todo::get_by_user_id_and_id(&mut db, &user.id, &todos[0].id).await?;
491 assert_eq!("Make pizza", todo.title);
492 Ok(())
493}
494
495#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
496pub async fn composite_user_batch_create_two_todos_simple(test: &mut Test) -> Result<()> {
497 let mut db = setup(test).await;
498
499 let user = User::create()
500 .name("Ann Chovey")
501 .todos([Todo::create().title("Make pizza")])
502 .todos([Todo::create().title("Sleep")])
503 .exec(&mut db)
504 .await?;
505
506 let todos: Vec<_> = user.todos().exec(&mut db).await?;
507 assert_eq!(2, todos.len());
508
509 let mut titles: Vec<_> = todos.iter().map(|t| &t.title[..]).collect();
510 titles.sort();
511 assert_eq!(titles, vec!["Make pizza", "Sleep"]);
512 Ok(())
513}
514
515#[driver_test]
516pub async fn composite_user_batch_create_todos_with_optional_field(test: &mut Test) -> Result<()> {
517 #[derive(Debug, toasty::Model)]
518 struct User {
519 #[key]
520 #[auto]
521 id: uuid::Uuid,
522
523 name: String,
524
525 #[has_many]
526 todos: toasty::Deferred<Vec<Todo>>,
527
528 #[allow(dead_code)]
531 moto: Option<String>,
532 }
533
534 #[derive(Debug, toasty::Model)]
535 #[key(partition = user_id, local = id)]
536 struct Todo {
537 #[auto]
538 id: uuid::Uuid,
539
540 user_id: uuid::Uuid,
541
542 #[belongs_to(key = user_id, references = id)]
543 user: toasty::Deferred<User>,
544
545 title: String,
546 }
547
548 let mut db = test.setup_db(models!(User, Todo)).await;
549
550 let user = User::create()
551 .name("Ann Chovey")
552 .todos([Todo::create().title("Make pizza")])
553 .todos([Todo::create().title("Sleep")])
554 .exec(&mut db)
555 .await?;
556
557 let todos: Vec<_> = user.todos().exec(&mut db).await?;
558 assert_eq!(2, todos.len());
559
560 let mut titles: Vec<_> = todos.iter().map(|t| &t.title[..]).collect();
561 titles.sort();
562 assert_eq!(titles, vec!["Make pizza", "Sleep"]);
563 Ok(())
564}
565
566#[driver_test(scenario(crate::scenarios::has_many_nullable_fk))]
567pub async fn composite_remove_add_single_relation_option_belongs_to(test: &mut Test) -> Result<()> {
568 let mut db = setup(test).await;
569
570 let user = User::create()
571 .todos([Todo::create().title("dummy")])
572 .todos([Todo::create().title("dummy")])
573 .exec(&mut db)
574 .await?;
575
576 let todos: Vec<_> = user.todos().exec(&mut db).await?;
577 assert_eq!(2, todos.len());
578
579 user.todos().remove(&todos[0]).exec(&mut db).await?;
580
581 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
582 assert_eq!(1, todos_reloaded.len());
583 assert_eq!(todos[1].id, todos_reloaded[0].id);
584
585 assert_err!(user.todos().get_by_id(&mut db, &todos[0].id).await);
586
587 let todo = Todo::get_by_id(&mut db, todos[0].id).await?;
588 assert_none!(todo.user_id);
589
590 user.todos().insert(&todos[0]).exec(&mut db).await?;
591
592 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
593 assert!(todos_reloaded.iter().any(|t| t.id == todos[0].id));
594 assert_ok!(user.todos().get_by_id(&mut db, todos[0].id).await);
595 Ok(())
596}
597
598#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
599pub async fn composite_add_remove_single_relation_required_belongs_to(
600 test: &mut Test,
601) -> Result<()> {
602 let mut db = setup(test).await;
603
604 let user = User::create().name("User 1").exec(&mut db).await?;
605
606 let t1 = user.todos().create().title("todo 1").exec(&mut db).await?;
607 let t2 = user.todos().create().title("todo 2").exec(&mut db).await?;
608 let t3 = user.todos().create().title("todo 3").exec(&mut db).await?;
609
610 let ids = vec![t1.id, t2.id, t3.id];
611
612 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
613 assert_eq!(todos_reloaded.len(), 3);
614
615 for id in ids {
616 assert!(todos_reloaded.iter().any(|t| t.id == id));
617 }
618
619 user.todos()
621 .remove(&todos_reloaded[0])
622 .exec(&mut db)
623 .await?;
624
625 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &todos_reloaded[0].id).await);
626
627 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
628 assert_eq!(todos_reloaded.len(), 2);
629 Ok(())
630}
631
632#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
633pub async fn composite_reassign_relation_required_belongs_to(test: &mut Test) -> Result<()> {
634 let mut db = setup(test).await;
635
636 let u1 = User::create()
637 .revision(1)
638 .name("User 1")
639 .exec(&mut db)
640 .await?;
641 let u2 = User::create()
642 .revision(1)
643 .name("User 2")
644 .exec(&mut db)
645 .await?;
646
647 let t1 = u1.todos().create().title("a todo").exec(&mut db).await?;
648
649 u2.todos().insert(&t1).exec(&mut db).await?;
650
651 assert!(u1.todos().exec(&mut db).await?.is_empty());
652
653 let todos = u2.todos().exec(&mut db).await?;
654 assert_eq!(1, todos.len());
655 assert_eq!(t1.id, todos[0].id);
656 Ok(())
657}
658
659#[driver_test(scenario(crate::scenarios::has_many_nullable_fk))]
660pub async fn composite_add_remove_multiple_relation_option_belongs_to(
661 test: &mut Test,
662) -> Result<()> {
663 let mut db = setup(test).await;
664
665 let user = User::create().exec(&mut db).await?;
666
667 let t1 = Todo::create().title("dummy").exec(&mut db).await?;
668 let t2 = Todo::create().title("dummy").exec(&mut db).await?;
669 let t3 = Todo::create().title("dummy").exec(&mut db).await?;
670
671 let ids = vec![t1.id, t2.id, t3.id];
672
673 user.todos().insert(&t1).exec(&mut db).await?;
674 user.todos().insert(&t2).exec(&mut db).await?;
675 user.todos().insert(&t3).exec(&mut db).await?;
676
677 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
678 assert_eq!(todos_reloaded.len(), 3);
679
680 for id in ids {
681 assert!(todos_reloaded.iter().any(|t| t.id == id));
682 }
683 Ok(())
684}
685
686#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
692pub async fn composite_basic_has_many_and_belongs_to_preload(test: &mut Test) -> Result<()> {
693 let mut db = setup(test).await;
694
695 let user = User::create()
696 .name("Alice")
697 .todos([Todo::create().title("todo 1")])
698 .todos([Todo::create().title("todo 2")])
699 .todos([Todo::create().title("todo 3")])
700 .exec(&mut db)
701 .await?;
702
703 let user = User::filter_by_id(user.id)
704 .include(User::fields().todos())
705 .get(&mut db)
706 .await?;
707
708 assert_eq!(3, user.todos.get().len());
709
710 let id = user.todos.get()[0].id;
711 let user_id = user.todos.get()[0].user_id;
712
713 let todo = Todo::filter_by_user_id_and_id(user_id, id)
714 .include(Todo::fields().user())
715 .get(&mut db)
716 .await?;
717
718 assert_eq!(user.id, todo.user.get().id);
719 assert_eq!(user.id, todo.user_id);
720 Ok(())
721}
722
723#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
728pub async fn composite_fk_belongs_to_preload(test: &mut Test) -> Result<()> {
729 let mut db = setup(test).await;
730
731 let u1 = toasty::create!(User {
732 revision: 1,
733 name: "User 1"
734 })
735 .exec(&mut db)
736 .await?;
737 let u2 = toasty::create!(User {
738 revision: 1,
739 name: "User 2"
740 })
741 .exec(&mut db)
742 .await?;
743
744 for user in [&u1, &u2] {
745 let todo = toasty::create!(in user.todos() { title: "a todo" })
746 .exec(&mut db)
747 .await?;
748
749 let todo = Todo::filter_by_id(todo.id)
750 .include(Todo::fields().user())
751 .get(&mut db)
752 .await?;
753
754 assert_struct!(todo.user.get(), { id: == user.id, name: == user.name });
755 }
756 Ok(())
757}
758
759#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
760pub async fn composite_preload_on_empty_query(test: &mut Test) -> Result<()> {
761 let mut db = setup(test).await;
762
763 User::create().name("Alice").exec(&mut db).await?;
764
765 let users: Vec<_> = User::filter(User::fields().name().eq("Nope"))
766 .include(User::fields().todos())
767 .exec(&mut db)
768 .await?;
769 assert!(users.is_empty());
770 Ok(())
771}
772
773#[driver_test(scenario(crate::scenarios::has_many_nullable_fk))]
774pub async fn composite_preload_has_many_with_optional_belongs_to(test: &mut Test) -> Result<()> {
775 let mut db = setup(test).await;
776
777 let user = User::create()
778 .todos([Todo::create().title("alpha")])
779 .todos([Todo::create().title("beta")])
780 .exec(&mut db)
781 .await?;
782
783 let user = User::filter_by_id(user.id)
784 .include(User::fields().todos())
785 .get(&mut db)
786 .await?;
787
788 assert_eq!(2, user.todos.get().len());
789 Ok(())
790}
791
792#[driver_test(scenario(crate::scenarios::composite_has_many_belongs_to))]
793pub async fn composite_nested_has_many_then_belongs_to_required(test: &mut Test) -> Result<()> {
794 let mut db = setup(test).await;
795
796 let user = User::create()
797 .name("Alice")
798 .todos([Todo::create().title("alpha")])
799 .todos([Todo::create().title("beta")])
800 .exec(&mut db)
801 .await?;
802
803 let user = User::filter_by_id(user.id)
804 .include(User::fields().todos().user())
805 .get(&mut db)
806 .await?;
807
808 let todos = user.todos.get();
809 assert_eq!(2, todos.len());
810 for todo in todos {
811 assert_eq!(user.id, todo.user.get().id);
812 assert_eq!("Alice", todo.user.get().name);
813 }
814 Ok(())
815}
816
817#[driver_test]
822pub async fn composite_crud_has_one_required(test: &mut Test) -> Result<()> {
823 #[derive(Debug, toasty::Model)]
827 struct User {
828 #[key]
829 #[auto]
830 id: uuid::Uuid,
831
832 #[has_one]
833 profile: toasty::Deferred<Option<Profile>>,
834 }
835
836 #[derive(Debug, toasty::Model)]
837 #[key(partition = user_id, local = id)]
838 struct Profile {
839 #[auto]
840 id: uuid::Uuid,
841
842 user_id: uuid::Uuid,
843
844 #[belongs_to(key = user_id, references = id)]
845 user: toasty::Deferred<User>,
846
847 bio: String,
848 }
849
850 let mut db = test.setup_db(models!(User, Profile)).await;
851
852 let user = User::create()
853 .profile(Profile::create().bio("an apple a day"))
854 .exec(&mut db)
855 .await?;
856
857 let profile = user.profile().exec(&mut db).await?.unwrap();
858 assert_eq!(profile.bio, "an apple a day");
859
860 assert_eq!(user.id, profile.user().exec(&mut db).await?.id);
861
862 user.delete().exec(&mut db).await?;
864 assert_err!(Profile::get_by_user_id_and_id(&mut db, &profile.user_id, &profile.id).await);
865 Ok(())
866}
867
868#[driver_test(requires(sql))]
873pub async fn composite_filter_by_belongs_to_field(test: &mut Test) -> Result<()> {
874 #[derive(Debug, toasty::Model)]
875 struct User {
876 #[key]
877 #[auto]
878 id: uuid::Uuid,
879
880 name: String,
881 }
882
883 #[derive(Debug, toasty::Model)]
884 #[key(partition = user_id, local = id)]
885 struct Profile {
886 #[auto]
887 id: uuid::Uuid,
888
889 user_id: uuid::Uuid,
890
891 #[belongs_to(key = user_id, references = id)]
892 user: toasty::Deferred<User>,
893
894 bio: String,
895 }
896
897 let mut db = test.setup_db(models!(User, Profile)).await;
898
899 let alice = User::create().name("alice").exec(&mut db).await?;
900 let bob = User::create().name("bob").exec(&mut db).await?;
901
902 Profile::create()
903 .user(&alice)
904 .bio("alice's bio")
905 .exec(&mut db)
906 .await?;
907 Profile::create()
908 .user(&bob)
909 .bio("bob's bio")
910 .exec(&mut db)
911 .await?;
912
913 let profiles: Vec<Profile> = Profile::filter(Profile::fields().user().name().eq("alice"))
914 .exec(&mut db)
915 .await?;
916 assert_eq!(profiles.len(), 1);
917 assert_eq!(profiles[0].bio, "alice's bio");
918 Ok(())
919}
920
921#[driver_test(
922 requires(scan),
923 scenario(crate::scenarios::composite_has_many_belongs_to)
924)]
925pub async fn composite_filter_parent_by_child_field(test: &mut Test) -> Result<()> {
926 let mut db = setup(test).await;
927
928 let alice = User::create().name("Alice").exec(&mut db).await?;
929 let bob = User::create().name("Bob").exec(&mut db).await?;
930 let carol = User::create().name("Carol").exec(&mut db).await?;
931
932 alice.todos().create().title("urgent").exec(&mut db).await?;
933 bob.todos().create().title("later").exec(&mut db).await?;
934 carol.todos().create().title("urgent").exec(&mut db).await?;
935 carol.todos().create().title("later").exec(&mut db).await?;
936
937 let users: Vec<_> = User::filter(
938 User::fields()
939 .todos()
940 .any(Todo::fields().title().eq("urgent")),
941 )
942 .exec(&mut db)
943 .await?;
944
945 assert_eq_unordered!(users.iter().map(|u| &u.name[..]), ["Alice", "Carol"]);
946 Ok(())
947}
948
949#[driver_test(requires(scan))]
950pub async fn composite_select_belongs_to_basic(test: &mut Test) -> Result<()> {
951 #[derive(Debug, toasty::Model)]
952 struct User {
953 #[key]
954 #[auto]
955 id: uuid::Uuid,
956 name: String,
957 }
958
959 #[derive(Debug, toasty::Model)]
960 #[key(partition = user_id, local = id)]
961 struct Post {
962 #[auto]
963 id: uuid::Uuid,
964 title: String,
965
966 user_id: uuid::Uuid,
967
968 #[belongs_to(key = user_id, references = id)]
969 author: toasty::Deferred<User>,
970 }
971
972 let mut db = test.setup_db(models!(User, Post)).await;
973
974 let alice = User::create().name("Alice").exec(&mut db).await?;
975 Post::create()
976 .title("Hello")
977 .author(&alice)
978 .exec(&mut db)
979 .await?;
980
981 let users: Vec<User> = Post::all()
982 .select(Post::fields().author())
983 .exec(&mut db)
984 .await?;
985
986 assert_eq!(users.len(), 1);
987 assert_eq!(users[0].name, "Alice");
988 Ok(())
989}