toasty_driver_integration_suite/tests/
has_many_link_unlink.rs

1//! Test linking and unlinking has_many associations
2
3use crate::prelude::*;
4
5#[driver_test(id(ID))]
6pub async fn remove_add_single_relation_option_belongs_to(test: &mut Test) -> Result<()> {
7    #[derive(Debug, toasty::Model)]
8    struct User {
9        #[key]
10        #[auto]
11        id: ID,
12
13        #[has_many]
14        todos: toasty::HasMany<Todo>,
15    }
16
17    #[derive(Debug, toasty::Model)]
18    struct Todo {
19        #[key]
20        #[auto]
21        id: ID,
22
23        #[index]
24        user_id: Option<ID>,
25
26        #[belongs_to(key = user_id, references = id)]
27        user: toasty::BelongsTo<Option<User>>,
28    }
29
30    let mut db = test.setup_db(models!(User, Todo)).await;
31
32    // Create a user with some todos
33    let user = User::create()
34        .todo(Todo::create())
35        .todo(Todo::create())
36        .exec(&mut db)
37        .await?;
38
39    let todos: Vec<_> = user.todos().exec(&mut db).await?;
40    assert_eq!(2, todos.len());
41
42    // Remove a todo from the list.
43    user.todos().remove(&mut db, &todos[0]).await?;
44
45    let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
46    assert_eq!(1, todos_reloaded.len());
47    assert_eq!(todos[1].id, todos_reloaded[0].id);
48
49    // Can't find the TODO via a scoped query either
50    assert_err!(user.todos().get_by_id(&mut db, &todos[0].id).await);
51
52    // The todo is not deleted, but user is now None
53    let todo = Todo::get_by_id(&mut db, todos[0].id).await?;
54    assert_none!(todo.user_id);
55
56    // Create a second user w/ a TODO. We will ensure that unlinking *only*
57    // unlinks records currently associated with the base model.
58    let u2 = User::create().todo(Todo::create()).exec(&mut db).await?;
59    let u2_todos = u2.todos().exec(&mut db).await?;
60
61    // Try unlinking u2's todo via user. This should fail
62    assert_err!(user.todos().remove(&mut db, &u2_todos[0]).await);
63
64    // Reload u2's todo
65    let u2_todo = Todo::get_by_id(&mut db, u2_todos[0].id).await?;
66    assert_eq!(*u2_todo.user_id.as_ref().unwrap(), u2.id);
67
68    // Link the TODO back up
69    user.todos().insert(&mut db, &todos[0]).await?;
70
71    // The TODO is in the association again
72    let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
73    assert!(todos_reloaded.iter().any(|t| t.id == todos[0].id));
74    assert_ok!(user.todos().get_by_id(&mut db, todos[0].id).await);
75    Ok(())
76}
77
78#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
79pub async fn add_remove_single_relation_required_belongs_to(test: &mut Test) -> Result<()> {
80    let mut db = setup(test).await;
81
82    // Create a user with no todos
83    let user = User::create().name("User 1").exec(&mut db).await?;
84
85    // Create some TODOs
86    let t1 = user.todos().create().title("todo 1").exec(&mut db).await?;
87    let t2 = user.todos().create().title("todo 2").exec(&mut db).await?;
88    let t3 = user.todos().create().title("todo 3").exec(&mut db).await?;
89
90    let ids = vec![t1.id, t2.id, t3.id];
91
92    let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
93    assert_eq!(todos_reloaded.len(), 3);
94
95    for id in ids {
96        assert!(todos_reloaded.iter().any(|t| t.id == id));
97    }
98
99    // Unlinking a todo deletes it
100    user.todos().remove(&mut db, &todos_reloaded[0]).await?;
101
102    // The TODO no longer exists
103    assert_err!(Todo::get_by_id(&mut db, todos_reloaded[0].id).await);
104
105    // Rest of the todos exist
106    let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
107    assert_eq!(todos_reloaded.len(), 2);
108    Ok(())
109}
110
111#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
112pub async fn reassign_relation_required_belongs_to(test: &mut Test) -> Result<()> {
113    let mut db = setup(test).await;
114
115    // Create users with no todos
116    let u1 = User::create().name("User 1").exec(&mut db).await?;
117    let u2 = User::create().name("User 2").exec(&mut db).await?;
118
119    // Create a TODO associated with user 1
120    let t1 = u1.todos().create().title("a todo").exec(&mut db).await?;
121
122    // Associate the todo with user 2
123    u2.todos().insert(&mut db, &t1).await?;
124
125    // The TODO is no longer associated with user 1
126    assert!(u1.todos().exec(&mut db).await?.is_empty());
127
128    // The TODO is assiated with user 2
129    let todos = u2.todos().exec(&mut db).await?;
130    assert_eq!(1, todos.len());
131    assert_eq!(t1.id, todos[0].id);
132    Ok(())
133}
134
135#[driver_test(id(ID))]
136pub async fn add_remove_multiple_relation_option_belongs_to(test: &mut Test) -> Result<()> {
137    #[derive(Debug, toasty::Model)]
138    struct User {
139        #[key]
140        #[auto]
141        id: ID,
142
143        #[has_many]
144        todos: toasty::HasMany<Todo>,
145    }
146
147    #[derive(Debug, toasty::Model)]
148    struct Todo {
149        #[key]
150        #[auto]
151        id: ID,
152
153        #[index]
154        user_id: Option<ID>,
155
156        #[belongs_to(key = user_id, references = id)]
157        user: toasty::BelongsTo<Option<User>>,
158    }
159
160    let mut db = test.setup_db(models!(User, Todo)).await;
161
162    // Create a user with no todos
163    let user = User::create().exec(&mut db).await?;
164
165    // Create some TODOs
166    let t1 = Todo::create().exec(&mut db).await?;
167    let t2 = Todo::create().exec(&mut db).await?;
168    let t3 = Todo::create().exec(&mut db).await?;
169
170    let ids = vec![t1.id, t2.id, t3.id];
171
172    // Associate the todos with the user
173    user.todos().insert(&mut db, &[t1, t2, t3]).await?;
174
175    let todos_reloaded: Vec<_> = user.todos().exec(&mut db).await?;
176    assert_eq!(todos_reloaded.len(), 3);
177
178    for id in ids {
179        assert!(todos_reloaded.iter().any(|t| t.id == id));
180    }
181    Ok(())
182}