toasty_driver_integration_suite/tests/
batch_associations.rs1use crate::prelude::*;
5
6#[driver_test(
8 id(ID),
9 requires(scan),
10 scenario(crate::scenarios::has_many_belongs_to)
11)]
12pub async fn batch_two_scoped_creates_same_relation(t: &mut Test) -> Result<()> {
13 let mut db = setup(t).await;
14 let user = User::create().name("Alice").exec(&mut db).await?;
15
16 let (t1, t2): (Todo, Todo) = toasty::batch((
17 user.todos().create().title("first"),
18 user.todos().create().title("second"),
19 ))
20 .exec(&mut db)
21 .await?;
22
23 assert_eq!(t1.title, "first");
24 assert_eq!(t2.title, "second");
25 assert_eq!(t1.user_id, user.id);
26 assert_eq!(t2.user_id, user.id);
27
28 let all: Vec<Todo> = user.todos().exec(&mut db).await?;
29 assert_eq!(all.len(), 2);
30
31 Ok(())
32}
33
34#[driver_test(
36 id(ID),
37 requires(scan),
38 scenario(crate::scenarios::has_many_belongs_to)
39)]
40pub async fn batch_two_scoped_queries_same_relation(t: &mut Test) -> Result<()> {
41 let mut db = setup(t).await;
42
43 let u1 = User::create().name("u1").exec(&mut db).await?;
44 let u2 = User::create().name("u2").exec(&mut db).await?;
45 u1.todos().create().title("u1 todo").exec(&mut db).await?;
46 u2.todos().create().title("u2 todo").exec(&mut db).await?;
47
48 let (u1_todos, u2_todos): (Vec<Todo>, Vec<Todo>) = toasty::batch((u1.todos(), u2.todos()))
49 .exec(&mut db)
50 .await?;
51
52 assert_struct!(u1_todos, [{ title: "u1 todo" }]);
53 assert_struct!(u2_todos, [{ title: "u2 todo" }]);
54
55 Ok(())
56}
57
58#[driver_test(
60 id(ID),
61 requires(scan),
62 scenario(crate::scenarios::has_many_belongs_to)
63)]
64pub async fn batch_scoped_update_and_delete_same_relation(t: &mut Test) -> Result<()> {
65 let mut db = setup(t).await;
66 let user = User::create().name("Alice").exec(&mut db).await?;
67 let todo_keep = user.todos().create().title("keep").exec(&mut db).await?;
68 let todo_drop = user.todos().create().title("drop").exec(&mut db).await?;
69
70 let ((), ()): ((), ()) = toasty::batch((
71 user.todos()
72 .filter_by_id(todo_keep.id)
73 .update()
74 .title("kept"),
75 user.todos().filter_by_id(todo_drop.id).delete(),
76 ))
77 .exec(&mut db)
78 .await?;
79
80 let remaining: Vec<Todo> = user.todos().exec(&mut db).await?;
81 assert_eq!(remaining.len(), 1);
82 assert_eq!(remaining[0].title, "kept");
83
84 Ok(())
85}
86
87#[driver_test(
89 id(ID),
90 requires(scan),
91 scenario(crate::scenarios::has_many_belongs_to)
92)]
93pub async fn batch_scoped_all_four_crud(t: &mut Test) -> Result<()> {
94 let mut db = setup(t).await;
95 let user = User::create().name("Alice").exec(&mut db).await?;
96 let existing = user
97 .todos()
98 .create()
99 .title("existing")
100 .exec(&mut db)
101 .await?;
102 let doomed = user.todos().create().title("doomed").exec(&mut db).await?;
103
104 let (queried, created, (), ()): (Vec<Todo>, Todo, (), ()) = toasty::batch((
105 user.todos(),
106 user.todos().create().title("new"),
107 user.todos()
108 .filter_by_id(existing.id)
109 .update()
110 .title("updated"),
111 user.todos().filter_by_id(doomed.id).delete(),
112 ))
113 .exec(&mut db)
114 .await?;
115
116 assert_eq!(queried.len(), 2);
118 assert_eq!(created.title, "new");
119
120 let final_todos: Vec<Todo> = user.todos().exec(&mut db).await?;
122 assert_eq!(final_todos.len(), 2); let titles: Vec<&str> = final_todos.iter().map(|t| t.title.as_str()).collect();
125 assert!(titles.contains(&"updated"));
126 assert!(titles.contains(&"new"));
127
128 Ok(())
129}
130
131#[driver_test(
133 id(ID),
134 requires(scan),
135 scenario(crate::scenarios::has_many_belongs_to)
136)]
137pub async fn batch_scoped_with_root_statements(t: &mut Test) -> Result<()> {
138 let mut db = setup(t).await;
139 let user = User::create().name("Alice").exec(&mut db).await?;
140
141 let (users, todo, new_user): (Vec<User>, Todo, User) = toasty::batch((
143 User::filter_by_name("Alice"),
144 user.todos().create().title("from batch"),
145 User::create().name("Bob"),
146 ))
147 .exec(&mut db)
148 .await?;
149
150 assert_struct!(users, [{ name: "Alice" }]);
151 assert_eq!(todo.title, "from batch");
152 assert_eq!(todo.user_id, user.id);
153 assert_eq!(new_user.name, "Bob");
154
155 Ok(())
156}
157
158#[driver_test(id(ID), requires(scan))]
160pub async fn batch_scoped_across_relations(t: &mut Test) -> Result<()> {
161 #[derive(Debug, toasty::Model)]
162 struct User {
163 #[key]
164 #[auto]
165 id: ID,
166 #[has_many]
167 todos: toasty::HasMany<Todo>,
168 #[has_many]
169 posts: toasty::HasMany<Post>,
170 }
171
172 #[derive(Debug, toasty::Model)]
173 struct Todo {
174 #[key]
175 #[auto]
176 id: ID,
177 #[index]
178 user_id: ID,
179 #[belongs_to(key = user_id, references = id)]
180 user: toasty::BelongsTo<User>,
181 title: String,
182 }
183
184 #[derive(Debug, toasty::Model)]
185 struct Post {
186 #[key]
187 #[auto]
188 id: ID,
189 #[index]
190 user_id: ID,
191 #[belongs_to(key = user_id, references = id)]
192 user: toasty::BelongsTo<User>,
193 body: String,
194 }
195
196 let mut db = t.setup_db(models!(User, Todo, Post)).await;
197 let user = User::create().exec(&mut db).await?;
198
199 let (todo, post): (Todo, Post) = toasty::batch((
201 user.todos().create().title("my todo"),
202 user.posts().create().body("my post"),
203 ))
204 .exec(&mut db)
205 .await?;
206
207 assert_eq!(todo.title, "my todo");
208 assert_eq!(todo.user_id, user.id);
209 assert_eq!(post.body, "my post");
210 assert_eq!(post.user_id, user.id);
211
212 Ok(())
213}
214
215#[driver_test(id(ID), requires(scan))]
217pub async fn batch_query_across_relations(t: &mut Test) -> Result<()> {
218 #[derive(Debug, toasty::Model)]
219 struct User {
220 #[key]
221 #[auto]
222 id: ID,
223 #[has_many]
224 todos: toasty::HasMany<Todo>,
225 #[has_many]
226 posts: toasty::HasMany<Post>,
227 }
228
229 #[derive(Debug, toasty::Model)]
230 struct Todo {
231 #[key]
232 #[auto]
233 id: ID,
234 #[index]
235 user_id: ID,
236 #[belongs_to(key = user_id, references = id)]
237 user: toasty::BelongsTo<User>,
238 title: String,
239 }
240
241 #[derive(Debug, toasty::Model)]
242 struct Post {
243 #[key]
244 #[auto]
245 id: ID,
246 #[index]
247 user_id: ID,
248 #[belongs_to(key = user_id, references = id)]
249 user: toasty::BelongsTo<User>,
250 body: String,
251 }
252
253 let mut db = t.setup_db(models!(User, Todo, Post)).await;
254 let user = User::create().exec(&mut db).await?;
255 user.todos().create().title("t1").exec(&mut db).await?;
256 user.todos().create().title("t2").exec(&mut db).await?;
257 user.posts().create().body("p1").exec(&mut db).await?;
258
259 let (todos, posts): (Vec<Todo>, Vec<Post>) = toasty::batch((user.todos(), user.posts()))
260 .exec(&mut db)
261 .await?;
262
263 assert_eq!(todos.len(), 2);
264 assert_eq!(posts.len(), 1);
265 assert_eq!(posts[0].body, "p1");
266
267 Ok(())
268}
269
270#[driver_test(
272 id(ID),
273 requires(scan),
274 scenario(crate::scenarios::has_many_belongs_to)
275)]
276pub async fn batch_scoped_different_parents(t: &mut Test) -> Result<()> {
277 let mut db = setup(t).await;
278 let alice = User::create().name("Alice").exec(&mut db).await?;
279 let bob = User::create().name("Bob").exec(&mut db).await?;
280
281 let (alice_todo, bob_todo): (Todo, Todo) = toasty::batch((
283 alice.todos().create().title("alice task"),
284 bob.todos().create().title("bob task"),
285 ))
286 .exec(&mut db)
287 .await?;
288
289 assert_eq!(alice_todo.user_id, alice.id);
290 assert_eq!(bob_todo.user_id, bob.id);
291
292 let (alice_todos, bob_todos): (Vec<Todo>, Vec<Todo>) =
294 toasty::batch((alice.todos(), bob.todos()))
295 .exec(&mut db)
296 .await?;
297
298 assert_struct!(alice_todos, [{ title: "alice task" }]);
299 assert_struct!(bob_todos, [{ title: "bob task" }]);
300
301 Ok(())
302}
303
304#[driver_test(
306 id(ID),
307 requires(scan),
308 scenario(crate::scenarios::has_many_belongs_to)
309)]
310pub async fn batch_scoped_delete_with_root_update(t: &mut Test) -> Result<()> {
311 let mut db = setup(t).await;
312 let user = User::create().name("Alice").exec(&mut db).await?;
313 let todo = user.todos().create().title("done").exec(&mut db).await?;
314
315 let ((), ()): ((), ()) = toasty::batch((
316 user.todos().filter_by_id(todo.id).delete(),
317 User::filter_by_name("Alice").update().name("Alice2"),
318 ))
319 .exec(&mut db)
320 .await?;
321
322 let remaining: Vec<Todo> = user.todos().exec(&mut db).await?;
324 assert!(remaining.is_empty());
325
326 let updated: Vec<User> = User::filter_by_name("Alice2").exec(&mut db).await?;
328 assert_eq!(updated.len(), 1);
329
330 Ok(())
331}