toasty_driver_integration_suite/tests/
relation_many_to_many.rs1use crate::prelude::*;
5
6#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
10pub async fn query_from_both_sides(test: &mut Test) -> Result<()> {
11 let mut db = setup(test).await;
12 let fixture = seed(&mut db).await?;
13
14 let groups = fixture
15 .alice
16 .groups()
17 .order_by(Group::fields().name().asc())
18 .exec(&mut db)
19 .await?;
20 assert_eq!(
21 groups
22 .iter()
23 .map(|group| &group.name[..])
24 .collect::<Vec<_>>(),
25 ["Databases", "Rust"]
26 );
27
28 let users = fixture
29 .rust
30 .users()
31 .order_by(User::fields().name().asc())
32 .exec(&mut db)
33 .await?;
34 assert_eq!(
35 users.iter().map(|user| &user.name[..]).collect::<Vec<_>>(),
36 ["Alice", "Bob"]
37 );
38
39 assert!(fixture.carol.groups().exec(&mut db).await?.is_empty());
40 assert!(fixture.empty.users().exec(&mut db).await?.is_empty());
41
42 Ok(())
43}
44
45#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
49pub async fn filter_through_join_model(test: &mut Test) -> Result<()> {
50 let mut db = setup(test).await;
51 seed(&mut db).await?;
52
53 let users: Vec<User> = User::filter(
54 User::fields()
55 .memberships()
56 .any(Membership::fields().group().name().eq("Rust")),
57 )
58 .exec(&mut db)
59 .await?;
60 assert_eq_unordered!(users.iter().map(|user| &user.name[..]), ["Alice", "Bob"]);
61
62 let groups: Vec<Group> = Group::filter(
63 Group::fields()
64 .memberships()
65 .any(Membership::fields().user().name().eq("Alice")),
66 )
67 .exec(&mut db)
68 .await?;
69 assert_eq_unordered!(
70 groups.iter().map(|group| &group.name[..]),
71 ["Rust", "Databases"]
72 );
73
74 let owners: Vec<User> = User::filter(
75 User::fields()
76 .memberships()
77 .any(Membership::fields().role().eq("owner")),
78 )
79 .exec(&mut db)
80 .await?;
81 assert_eq!(owners.len(), 1);
82 assert_eq!(owners[0].name, "Alice");
83
84 Ok(())
85}
86
87#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
90pub async fn filter_through_via_from_both_sides(test: &mut Test) -> Result<()> {
91 let mut db = setup(test).await;
92 seed(&mut db).await?;
93
94 let users: Vec<User> = User::filter(
95 User::fields()
96 .groups()
97 .any(Group::fields().name().eq("Rust")),
98 )
99 .exec(&mut db)
100 .await?;
101 assert_eq_unordered!(users.iter().map(|user| &user.name[..]), ["Alice", "Bob"]);
102
103 let groups: Vec<Group> = Group::filter(
104 Group::fields()
105 .users()
106 .any(User::fields().name().eq("Alice")),
107 )
108 .exec(&mut db)
109 .await?;
110 assert_eq_unordered!(
111 groups.iter().map(|group| &group.name[..]),
112 ["Rust", "Databases"]
113 );
114
115 Ok(())
116}
117
118#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
121pub async fn include_from_both_sides(test: &mut Test) -> Result<()> {
122 let mut db = setup(test).await;
123 seed(&mut db).await?;
124
125 let users: Vec<User> = User::all()
126 .include(User::fields().groups())
127 .exec(&mut db)
128 .await?;
129 for user in &users {
130 let groups = user.groups.get().iter().map(|group| &group.name[..]);
131 match &user.name[..] {
132 "Alice" => {
133 assert_eq_unordered!(groups, ["Rust", "Databases"]);
134 }
135 "Bob" => {
136 assert_eq_unordered!(groups, ["Rust"]);
137 }
138 "Carol" => {
139 assert_eq!(groups.count(), 0);
140 }
141 name => panic!("unexpected user {name}"),
142 }
143 }
144
145 let groups: Vec<Group> = Group::all()
146 .include(Group::fields().users())
147 .exec(&mut db)
148 .await?;
149 for group in &groups {
150 let users = group.users.get().iter().map(|user| &user.name[..]);
151 match &group.name[..] {
152 "Rust" => {
153 assert_eq_unordered!(users, ["Alice", "Bob"]);
154 }
155 "Databases" => {
156 assert_eq_unordered!(users, ["Alice"]);
157 }
158 "Empty" => {
159 assert_eq!(users.count(), 0);
160 }
161 name => panic!("unexpected group {name}"),
162 }
163 }
164
165 Ok(())
166}
167
168#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
172pub async fn mutate_link_through_join_model(test: &mut Test) -> Result<()> {
173 let mut db = setup(test).await;
174
175 let user = toasty::create!(User { name: "Alice" })
176 .exec(&mut db)
177 .await?;
178 let group = toasty::create!(Group { name: "Rust" })
179 .exec(&mut db)
180 .await?;
181
182 let mut membership = toasty::create!(Membership {
183 user: &user,
184 group: &group,
185 role: "member"
186 })
187 .exec(&mut db)
188 .await?;
189
190 assert_eq!(user.groups().get(&mut db).await?.id, group.id);
191 assert_eq!(group.users().get(&mut db).await?.id, user.id);
192
193 membership.update().role("owner").exec(&mut db).await?;
194 assert_eq!(membership.role, "owner");
195
196 membership.delete().exec(&mut db).await?;
197 assert!(user.groups().exec(&mut db).await?.is_empty());
198 assert!(group.users().exec(&mut db).await?.is_empty());
199
200 assert_eq!(User::get_by_id(&mut db, user.id).await?.name, "Alice");
201 assert_eq!(Group::get_by_id(&mut db, group.id).await?.name, "Rust");
202
203 Ok(())
204}
205
206#[driver_test(requires(sql), scenario(crate::scenarios::user_group_membership))]
209pub async fn composite_join_key_prevents_duplicate_links(test: &mut Test) -> Result<()> {
210 let mut db = setup(test).await;
211
212 let users = toasty::create!(User::[{ name: "Alice" }, { name: "Bob" }])
213 .exec(&mut db)
214 .await?;
215 let groups = toasty::create!(Group::[{ name: "Rust" }, { name: "Databases" }])
216 .exec(&mut db)
217 .await?;
218
219 toasty::create!(Membership {
220 user: &users[0],
221 group: &groups[0],
222 role: "member"
223 })
224 .exec(&mut db)
225 .await?;
226
227 assert_err!(
228 toasty::create!(Membership {
229 user: &users[0],
230 group: &groups[0],
231 role: "owner"
232 })
233 .exec(&mut db)
234 .await
235 );
236
237 toasty::create!(Membership::[
238 { user: &users[0], group: &groups[1], role: "member" },
239 { user: &users[1], group: &groups[0], role: "member" },
240 ])
241 .exec(&mut db)
242 .await?;
243
244 Ok(())
245}
246
247#[driver_test(requires(sql))]
251pub async fn self_referential_followers_and_following(test: &mut Test) -> Result<()> {
252 #[derive(Debug, toasty::Model)]
253 struct User {
254 #[key]
255 #[auto]
256 id: uuid::Uuid,
257
258 name: String,
259
260 #[has_many(pair = follower)]
261 outgoing_follows: toasty::Deferred<Vec<Follow>>,
262
263 #[has_many(pair = followed)]
264 incoming_follows: toasty::Deferred<Vec<Follow>>,
265
266 #[has_many(via = outgoing_follows.followed)]
267 following: toasty::Deferred<Vec<User>>,
268
269 #[has_many(via = incoming_follows.follower)]
270 followers: toasty::Deferred<Vec<User>>,
271 }
272
273 #[derive(Debug, toasty::Model)]
274 #[key(follower_id, followed_id)]
275 struct Follow {
276 #[index]
277 follower_id: uuid::Uuid,
278
279 #[belongs_to(key = follower_id, references = id)]
280 follower: toasty::Deferred<User>,
281
282 #[index]
283 followed_id: uuid::Uuid,
284
285 #[belongs_to(key = followed_id, references = id)]
286 followed: toasty::Deferred<User>,
287 }
288
289 let mut db = test.setup_db(models!(User, Follow)).await;
290
291 let users = toasty::create!(User::[
292 { name: "Alice" },
293 { name: "Bob" },
294 { name: "Carol" },
295 ])
296 .exec(&mut db)
297 .await?;
298 let (alice, bob, carol) = (&users[0], &users[1], &users[2]);
299
300 toasty::create!(Follow::[
301 { follower: alice, followed: bob },
302 { follower: alice, followed: carol },
303 { follower: carol, followed: bob },
304 ])
305 .exec(&mut db)
306 .await?;
307
308 let following = alice.following().exec(&mut db).await?;
309 assert_eq_unordered!(
310 following.iter().map(|user| &user.name[..]),
311 ["Bob", "Carol"]
312 );
313
314 let followers = bob.followers().exec(&mut db).await?;
315 assert_eq_unordered!(
316 followers.iter().map(|user| &user.name[..]),
317 ["Alice", "Carol"]
318 );
319
320 assert!(bob.following().exec(&mut db).await?.is_empty());
321
322 Ok(())
323}