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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID), 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(id(ID))]
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: ID,
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: ID,
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(id(ID), 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(&mut db, &todos[0]).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(&mut db, &todos[0]).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(id(ID), 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().remove(&mut db, &todos_reloaded[0]).await?;
621
622 assert_err!(Todo::get_by_user_id_and_id(&mut db, &user.id, &todos_reloaded[0].id).await);
623
624 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
625 assert_eq!(todos_reloaded.len(), 2);
626 Ok(())
627}
628
629#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
630pub async fn composite_reassign_relation_required_belongs_to(test: &mut Test) -> Result<()> {
631 let mut db = setup(test).await;
632
633 let u1 = User::create()
634 .revision(1)
635 .name("User 1")
636 .exec(&mut db)
637 .await?;
638 let u2 = User::create()
639 .revision(1)
640 .name("User 2")
641 .exec(&mut db)
642 .await?;
643
644 let t1 = u1.todos().create().title("a todo").exec(&mut db).await?;
645
646 u2.todos().insert(&mut db, &t1).await?;
647
648 assert!(u1.todos().exec(&mut db).await?.is_empty());
649
650 let todos = u2.todos().exec(&mut db).await?;
651 assert_eq!(1, todos.len());
652 assert_eq!(t1.id, todos[0].id);
653 Ok(())
654}
655
656#[driver_test(id(ID), scenario(crate::scenarios::has_many_nullable_fk))]
657pub async fn composite_add_remove_multiple_relation_option_belongs_to(
658 test: &mut Test,
659) -> Result<()> {
660 let mut db = setup(test).await;
661
662 let user = User::create().exec(&mut db).await?;
663
664 let t1 = Todo::create().title("dummy").exec(&mut db).await?;
665 let t2 = Todo::create().title("dummy").exec(&mut db).await?;
666 let t3 = Todo::create().title("dummy").exec(&mut db).await?;
667
668 let ids = vec![t1.id, t2.id, t3.id];
669
670 user.todos().insert(&mut db, &t1).await?;
671 user.todos().insert(&mut db, &t2).await?;
672 user.todos().insert(&mut db, &t3).await?;
673
674 let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
675 assert_eq!(todos_reloaded.len(), 3);
676
677 for id in ids {
678 assert!(todos_reloaded.iter().any(|t| t.id == id));
679 }
680 Ok(())
681}
682
683#[driver_test(id(ID), scenario(crate::scenarios::composite_has_many_belongs_to))]
689pub async fn composite_basic_has_many_and_belongs_to_preload(test: &mut Test) -> Result<()> {
690 let mut db = setup(test).await;
691
692 let user = User::create()
693 .name("Alice")
694 .todos([Todo::create().title("todo 1")])
695 .todos([Todo::create().title("todo 2")])
696 .todos([Todo::create().title("todo 3")])
697 .exec(&mut db)
698 .await?;
699
700 let user = User::filter_by_id(user.id)
701 .include(User::fields().todos())
702 .get(&mut db)
703 .await?;
704
705 assert_eq!(3, user.todos.get().len());
706
707 let id = user.todos.get()[0].id;
708 let user_id = user.todos.get()[0].user_id;
709
710 let todo = Todo::filter_by_user_id_and_id(user_id, id)
711 .include(Todo::fields().user())
712 .get(&mut db)
713 .await?;
714
715 assert_eq!(user.id, todo.user.get().id);
716 assert_eq!(user.id, todo.user_id);
717 Ok(())
718}
719
720#[driver_test(scenario(crate::scenarios::composite_fk_has_many_belongs_to))]
725pub async fn composite_fk_belongs_to_preload(test: &mut Test) -> Result<()> {
726 let mut db = setup(test).await;
727
728 let u1 = toasty::create!(User {
729 revision: 1,
730 name: "User 1"
731 })
732 .exec(&mut db)
733 .await?;
734 let u2 = toasty::create!(User {
735 revision: 1,
736 name: "User 2"
737 })
738 .exec(&mut db)
739 .await?;
740
741 for user in [&u1, &u2] {
742 let todo = toasty::create!(in user.todos() { title: "a todo" })
743 .exec(&mut db)
744 .await?;
745
746 let todo = Todo::filter_by_id(todo.id)
747 .include(Todo::fields().user())
748 .get(&mut db)
749 .await?;
750
751 assert_struct!(todo.user.get(), _ { id: == user.id, name: == user.name, .. });
752 }
753 Ok(())
754}
755
756#[driver_test(id(ID), scenario(crate::scenarios::composite_has_many_belongs_to))]
757pub async fn composite_preload_on_empty_query(test: &mut Test) -> Result<()> {
758 let mut db = setup(test).await;
759
760 User::create().name("Alice").exec(&mut db).await?;
761
762 let users: Vec<_> = User::filter(User::fields().name().eq("Nope"))
763 .include(User::fields().todos())
764 .exec(&mut db)
765 .await?;
766 assert!(users.is_empty());
767 Ok(())
768}
769
770#[driver_test(id(ID), scenario(crate::scenarios::has_many_nullable_fk))]
771pub async fn composite_preload_has_many_with_optional_belongs_to(test: &mut Test) -> Result<()> {
772 let mut db = setup(test).await;
773
774 let user = User::create()
775 .todos([Todo::create().title("alpha")])
776 .todos([Todo::create().title("beta")])
777 .exec(&mut db)
778 .await?;
779
780 let user = User::filter_by_id(user.id)
781 .include(User::fields().todos())
782 .get(&mut db)
783 .await?;
784
785 assert_eq!(2, user.todos.get().len());
786 Ok(())
787}
788
789#[driver_test(id(ID), scenario(crate::scenarios::composite_has_many_belongs_to))]
790pub async fn composite_nested_has_many_then_belongs_to_required(test: &mut Test) -> Result<()> {
791 let mut db = setup(test).await;
792
793 let user = User::create()
794 .name("Alice")
795 .todos([Todo::create().title("alpha")])
796 .todos([Todo::create().title("beta")])
797 .exec(&mut db)
798 .await?;
799
800 let user = User::filter_by_id(user.id)
801 .include(User::fields().todos().user())
802 .get(&mut db)
803 .await?;
804
805 let todos = user.todos.get();
806 assert_eq!(2, todos.len());
807 for todo in todos {
808 assert_eq!(user.id, todo.user.get().id);
809 assert_eq!("Alice", todo.user.get().name);
810 }
811 Ok(())
812}
813
814#[driver_test(id(ID))]
819pub async fn composite_crud_has_one_required(test: &mut Test) -> Result<()> {
820 #[derive(Debug, toasty::Model)]
824 struct User {
825 #[key]
826 #[auto]
827 id: ID,
828
829 #[has_one]
830 profile: toasty::Deferred<Option<Profile>>,
831 }
832
833 #[derive(Debug, toasty::Model)]
834 #[key(partition = user_id, local = id)]
835 struct Profile {
836 #[auto]
837 id: uuid::Uuid,
838
839 user_id: ID,
840
841 #[belongs_to(key = user_id, references = id)]
842 user: toasty::Deferred<User>,
843
844 bio: String,
845 }
846
847 let mut db = test.setup_db(models!(User, Profile)).await;
848
849 let user = User::create()
850 .profile(Profile::create().bio("an apple a day"))
851 .exec(&mut db)
852 .await?;
853
854 let profile = user.profile().exec(&mut db).await?.unwrap();
855 assert_eq!(profile.bio, "an apple a day");
856
857 assert_eq!(user.id, profile.user().exec(&mut db).await?.id);
858
859 user.delete().exec(&mut db).await?;
861 assert_err!(Profile::get_by_user_id_and_id(&mut db, &profile.user_id, &profile.id).await);
862 Ok(())
863}
864
865#[driver_test(id(ID), requires(sql))]
870pub async fn composite_filter_by_belongs_to_field(test: &mut Test) -> Result<()> {
871 #[derive(Debug, toasty::Model)]
872 struct User {
873 #[key]
874 #[auto]
875 id: ID,
876
877 name: String,
878 }
879
880 #[derive(Debug, toasty::Model)]
881 #[key(partition = user_id, local = id)]
882 struct Profile {
883 #[auto]
884 id: uuid::Uuid,
885
886 user_id: ID,
887
888 #[belongs_to(key = user_id, references = id)]
889 user: toasty::Deferred<User>,
890
891 bio: String,
892 }
893
894 let mut db = test.setup_db(models!(User, Profile)).await;
895
896 let alice = User::create().name("alice").exec(&mut db).await?;
897 let bob = User::create().name("bob").exec(&mut db).await?;
898
899 Profile::create()
900 .user(&alice)
901 .bio("alice's bio")
902 .exec(&mut db)
903 .await?;
904 Profile::create()
905 .user(&bob)
906 .bio("bob's bio")
907 .exec(&mut db)
908 .await?;
909
910 let profiles: Vec<Profile> = Profile::filter(Profile::fields().user().name().eq("alice"))
911 .exec(&mut db)
912 .await?;
913 assert_eq!(profiles.len(), 1);
914 assert_eq!(profiles[0].bio, "alice's bio");
915 Ok(())
916}
917
918#[driver_test(
919 id(ID),
920 requires(scan),
921 scenario(crate::scenarios::composite_has_many_belongs_to)
922)]
923pub async fn composite_filter_parent_by_child_field(test: &mut Test) -> Result<()> {
924 let mut db = setup(test).await;
925
926 let alice = User::create().name("Alice").exec(&mut db).await?;
927 let bob = User::create().name("Bob").exec(&mut db).await?;
928 let carol = User::create().name("Carol").exec(&mut db).await?;
929
930 alice.todos().create().title("urgent").exec(&mut db).await?;
931 bob.todos().create().title("later").exec(&mut db).await?;
932 carol.todos().create().title("urgent").exec(&mut db).await?;
933 carol.todos().create().title("later").exec(&mut db).await?;
934
935 let users: Vec<_> = User::filter(
936 User::fields()
937 .todos()
938 .any(Todo::fields().title().eq("urgent")),
939 )
940 .exec(&mut db)
941 .await?;
942
943 assert_eq_unordered!(users.iter().map(|u| &u.name[..]), ["Alice", "Carol"]);
944 Ok(())
945}
946
947#[driver_test(id(ID), requires(scan))]
948pub async fn composite_select_belongs_to_basic(test: &mut Test) -> Result<()> {
949 #[derive(Debug, toasty::Model)]
950 struct User {
951 #[key]
952 #[auto]
953 id: ID,
954 name: String,
955 }
956
957 #[derive(Debug, toasty::Model)]
958 #[key(partition = user_id, local = id)]
959 struct Post {
960 #[auto]
961 id: uuid::Uuid,
962 title: String,
963
964 user_id: ID,
965
966 #[belongs_to(key = user_id, references = id)]
967 author: toasty::Deferred<User>,
968 }
969
970 let mut db = test.setup_db(models!(User, Post)).await;
971
972 let alice = User::create().name("Alice").exec(&mut db).await?;
973 Post::create()
974 .title("Hello")
975 .author(&alice)
976 .exec(&mut db)
977 .await?;
978
979 let users: Vec<User> = Post::all()
980 .select(Post::fields().author())
981 .exec(&mut db)
982 .await?;
983
984 assert_eq!(users.len(), 1);
985 assert_eq!(users[0].name, "Alice");
986 Ok(())
987}