toasty_driver_integration_suite/tests/
tx_interactive.rs1use crate::prelude::*;
2
3use toasty::Executor;
4use toasty_core::driver::{operation::Transaction, Operation};
5
6#[driver_test(id(ID), requires(sql))]
10pub async fn commit_persists_data(t: &mut Test) -> Result<()> {
11 #[derive(Debug, toasty::Model)]
12 struct User {
13 #[key]
14 #[auto]
15 id: ID,
16 name: String,
17 }
18
19 let mut db = t.setup_db(models!(User)).await;
20
21 let mut tx = db.transaction().await?;
22 User::create().name("Alice").exec(&mut tx).await?;
23 tx.commit().await?;
24
25 let users = User::all().exec(&mut db).await?;
26 assert_eq!(users.len(), 1);
27 assert_eq!(users[0].name, "Alice");
28
29 Ok(())
30}
31
32#[driver_test(id(ID), requires(sql))]
34pub async fn rollback_discards_data(t: &mut Test) -> Result<()> {
35 #[derive(Debug, toasty::Model)]
36 struct User {
37 #[key]
38 #[auto]
39 id: ID,
40 name: String,
41 }
42
43 let mut db = t.setup_db(models!(User)).await;
44
45 let mut tx = db.transaction().await?;
46 User::create().name("Ghost").exec(&mut tx).await?;
47 tx.rollback().await?;
48
49 let users = User::all().exec(&mut db).await?;
50 assert!(users.is_empty());
51
52 Ok(())
53}
54
55#[driver_test(id(ID), requires(sql))]
57pub async fn drop_without_finalize_rolls_back(t: &mut Test) -> Result<()> {
58 #[derive(Debug, toasty::Model)]
59 struct User {
60 #[key]
61 #[auto]
62 id: ID,
63 name: String,
64 }
65
66 let mut db = t.setup_db(models!(User)).await;
67
68 {
69 let mut tx = db.transaction().await?;
70 User::create().name("Ghost").exec(&mut tx).await?;
71 }
73
74 let users = User::all().exec(&mut db).await?;
75 assert!(users.is_empty());
76
77 Ok(())
78}
79
80#[driver_test(id(ID), requires(sql))]
82pub async fn multiple_ops_in_transaction(t: &mut Test) -> Result<()> {
83 #[derive(Debug, toasty::Model)]
84 struct User {
85 #[key]
86 #[auto]
87 id: ID,
88 name: String,
89 }
90
91 let mut db = t.setup_db(models!(User)).await;
92
93 let mut tx = db.transaction().await?;
94 User::create().name("Alice").exec(&mut tx).await?;
95 User::create().name("Bob").exec(&mut tx).await?;
96 User::create().name("Carol").exec(&mut tx).await?;
97 tx.commit().await?;
98
99 let users = User::all().exec(&mut db).await?;
100 assert_eq!(users.len(), 3);
101
102 Ok(())
103}
104
105#[driver_test(id(ID), requires(sql))]
108pub async fn read_your_writes(t: &mut Test) -> Result<()> {
109 #[derive(Debug, toasty::Model)]
110 struct User {
111 #[key]
112 #[auto]
113 id: ID,
114 name: String,
115 }
116
117 let mut db = t.setup_db(models!(User)).await;
118
119 let mut tx = db.transaction().await?;
120 User::create().name("Alice").exec(&mut tx).await?;
121
122 let users = User::all().exec(&mut tx).await?;
123 assert_eq!(users.len(), 1);
124 assert_eq!(users[0].name, "Alice");
125
126 tx.commit().await?;
127
128 Ok(())
129}
130
131#[driver_test(id(ID), requires(sql))]
133pub async fn update_inside_transaction(t: &mut Test) -> Result<()> {
134 #[derive(Debug, toasty::Model)]
135 struct User {
136 #[key]
137 #[auto]
138 id: ID,
139 name: String,
140 }
141
142 let mut db = t.setup_db(models!(User)).await;
143
144 let mut user = User::create().name("Alice").exec(&mut db).await?;
145
146 let mut tx = db.transaction().await?;
147 user.update().name("Bob").exec(&mut tx).await?;
148 tx.commit().await?;
149
150 let reloaded = User::get_by_id(&mut db, user.id).await?;
151 assert_eq!(reloaded.name, "Bob");
152
153 Ok(())
154}
155
156#[driver_test(id(ID), requires(sql))]
158pub async fn update_rolled_back(t: &mut Test) -> Result<()> {
159 #[derive(Debug, toasty::Model)]
160 struct User {
161 #[key]
162 #[auto]
163 id: ID,
164 name: String,
165 }
166
167 let mut db = t.setup_db(models!(User)).await;
168
169 let mut user = User::create().name("Alice").exec(&mut db).await?;
170
171 let mut tx = db.transaction().await?;
172 user.update().name("Bob").exec(&mut tx).await?;
173 tx.rollback().await?;
174
175 let reloaded = User::get_by_id(&mut db, user.id).await?;
176 assert_eq!(reloaded.name, "Alice");
177
178 Ok(())
179}
180
181#[driver_test(id(ID), requires(sql))]
183pub async fn delete_rolled_back(t: &mut Test) -> Result<()> {
184 #[derive(Debug, toasty::Model)]
185 struct User {
186 #[key]
187 #[auto]
188 id: ID,
189 name: String,
190 }
191
192 let mut db = t.setup_db(models!(User)).await;
193
194 let user = User::create().name("Alice").exec(&mut db).await?;
195
196 let mut tx = db.transaction().await?;
197 User::filter_by_id(user.id).delete().exec(&mut tx).await?;
198 tx.rollback().await?;
199
200 let reloaded = User::get_by_id(&mut db, user.id).await?;
201 assert_eq!(reloaded.name, "Alice");
202
203 Ok(())
204}
205
206#[driver_test(id(ID), requires(sql))]
210pub async fn driver_sees_begin_commit(t: &mut Test) -> Result<()> {
211 #[derive(Debug, toasty::Model)]
212 struct User {
213 #[key]
214 #[auto]
215 id: ID,
216 name: String,
217 }
218
219 let mut db = t.setup_db(models!(User)).await;
220
221 t.log().clear();
222
223 let mut tx = db.transaction().await?;
224 User::create().name("Alice").exec(&mut tx).await?;
225 tx.commit().await?;
226
227 assert_struct!(
228 t.log().pop_op(),
229 Operation::Transaction(Transaction::Start {
230 isolation: None,
231 read_only: false
232 })
233 );
234 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
236 t.log().pop_op(),
237 Operation::Transaction(Transaction::Commit)
238 );
239 assert!(t.log().is_empty());
240
241 Ok(())
242}
243
244#[driver_test(id(ID), requires(sql))]
246pub async fn driver_sees_begin_rollback(t: &mut Test) -> Result<()> {
247 #[derive(Debug, toasty::Model)]
248 struct User {
249 #[key]
250 #[auto]
251 id: ID,
252 name: String,
253 }
254
255 let mut db = t.setup_db(models!(User)).await;
256
257 t.log().clear();
258
259 let mut tx = db.transaction().await?;
260 User::create().name("Alice").exec(&mut tx).await?;
261 tx.rollback().await?;
262
263 assert_struct!(
264 t.log().pop_op(),
265 Operation::Transaction(Transaction::Start {
266 isolation: None,
267 read_only: false
268 })
269 );
270 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
272 t.log().pop_op(),
273 Operation::Transaction(Transaction::Rollback)
274 );
275 assert!(t.log().is_empty());
276
277 Ok(())
278}
279
280#[driver_test(id(ID), requires(sql))]
285pub async fn nested_commit_both(t: &mut Test) -> Result<()> {
286 #[derive(Debug, toasty::Model)]
287 struct User {
288 #[key]
289 #[auto]
290 id: ID,
291 name: String,
292 }
293
294 let mut db = t.setup_db(models!(User)).await;
295
296 let mut tx = db.transaction().await?;
297 User::create().name("Alice").exec(&mut tx).await?;
298
299 {
300 let mut nested = tx.transaction().await?;
301 User::create().name("Bob").exec(&mut nested).await?;
302 nested.commit().await?;
303 }
304
305 tx.commit().await?;
306
307 let users = User::all().exec(&mut db).await?;
308 assert_eq!(users.len(), 2);
309
310 Ok(())
311}
312
313#[driver_test(id(ID), requires(sql))]
316pub async fn nested_rollback_inner(t: &mut Test) -> Result<()> {
317 #[derive(Debug, toasty::Model)]
318 struct User {
319 #[key]
320 #[auto]
321 id: ID,
322 name: String,
323 }
324
325 let mut db = t.setup_db(models!(User)).await;
326
327 let mut tx = db.transaction().await?;
328 User::create().name("Alice").exec(&mut tx).await?;
329
330 {
331 let mut nested = tx.transaction().await?;
332 User::create().name("Ghost").exec(&mut nested).await?;
333 nested.rollback().await?;
334 }
335
336 tx.commit().await?;
337
338 let users = User::all().exec(&mut db).await?;
339 assert_eq!(users.len(), 1);
340 assert_eq!(users[0].name, "Alice");
341
342 Ok(())
343}
344
345#[driver_test(id(ID), requires(sql))]
348pub async fn nested_rollback_outer(t: &mut Test) -> Result<()> {
349 #[derive(Debug, toasty::Model)]
350 struct User {
351 #[key]
352 #[auto]
353 id: ID,
354 name: String,
355 }
356
357 let mut db = t.setup_db(models!(User)).await;
358
359 let mut tx = db.transaction().await?;
360 User::create().name("Alice").exec(&mut tx).await?;
361
362 {
363 let mut nested = tx.transaction().await?;
364 User::create().name("Bob").exec(&mut nested).await?;
365 nested.commit().await?;
366 }
367
368 tx.rollback().await?;
369
370 let users = User::all().exec(&mut db).await?;
371 assert!(users.is_empty());
372
373 Ok(())
374}
375
376#[driver_test(id(ID), requires(sql))]
379pub async fn nested_drop_rolls_back_savepoint(t: &mut Test) -> Result<()> {
380 #[derive(Debug, toasty::Model)]
381 struct User {
382 #[key]
383 #[auto]
384 id: ID,
385 name: String,
386 }
387
388 let mut db = t.setup_db(models!(User)).await;
389
390 let mut tx = db.transaction().await?;
391 User::create().name("Alice").exec(&mut tx).await?;
392
393 {
394 let mut nested = tx.transaction().await?;
395 User::create().name("Ghost").exec(&mut nested).await?;
396 }
398
399 tx.commit().await?;
400
401 let users = User::all().exec(&mut db).await?;
402 assert_eq!(users.len(), 1);
403 assert_eq!(users[0].name, "Alice");
404
405 Ok(())
406}
407
408#[driver_test(id(ID), requires(sql))]
411pub async fn nested_driver_sees_savepoint_ops(t: &mut Test) -> Result<()> {
412 #[derive(Debug, toasty::Model)]
413 struct User {
414 #[key]
415 #[auto]
416 id: ID,
417 name: String,
418 }
419
420 let mut db = t.setup_db(models!(User)).await;
421
422 t.log().clear();
423
424 let mut tx = db.transaction().await?;
425 User::create().name("Alice").exec(&mut tx).await?;
426
427 let mut nested = tx.transaction().await?;
428 User::create().name("Bob").exec(&mut nested).await?;
429 nested.commit().await?;
430
431 tx.commit().await?;
432
433 assert_struct!(
435 t.log().pop_op(),
436 Operation::Transaction(Transaction::Start {
437 isolation: None,
438 read_only: false
439 })
440 );
441 assert_struct!(t.log().pop_op(), Operation::QuerySql(_));
443 assert_struct!(
445 t.log().pop_op(),
446 Operation::Transaction(Transaction::Savepoint(_))
447 );
448 assert_struct!(t.log().pop_op(), Operation::QuerySql(_));
450 assert_struct!(
452 t.log().pop_op(),
453 Operation::Transaction(Transaction::ReleaseSavepoint(_))
454 );
455 assert_struct!(
457 t.log().pop_op(),
458 Operation::Transaction(Transaction::Commit)
459 );
460 assert!(t.log().is_empty());
461
462 Ok(())
463}
464
465#[driver_test(id(ID), requires(sql))]
468pub async fn nested_driver_sees_rollback_to_savepoint(t: &mut Test) -> Result<()> {
469 #[derive(Debug, toasty::Model)]
470 struct User {
471 #[key]
472 #[auto]
473 id: ID,
474 name: String,
475 }
476
477 let mut db = t.setup_db(models!(User)).await;
478
479 t.log().clear();
480
481 let mut tx = db.transaction().await?;
482
483 let mut nested = tx.transaction().await?;
484 User::create().name("Ghost").exec(&mut nested).await?;
485 nested.rollback().await?;
486
487 tx.commit().await?;
488
489 assert_struct!(
491 t.log().pop_op(),
492 Operation::Transaction(Transaction::Start {
493 isolation: None,
494 read_only: false
495 })
496 );
497 assert_struct!(
499 t.log().pop_op(),
500 Operation::Transaction(Transaction::Savepoint(_))
501 );
502 assert_struct!(t.log().pop_op(), Operation::QuerySql(_));
504 assert_struct!(
506 t.log().pop_op(),
507 Operation::Transaction(Transaction::RollbackToSavepoint(_))
508 );
509 assert_struct!(
511 t.log().pop_op(),
512 Operation::Transaction(Transaction::Commit)
513 );
514 assert!(t.log().is_empty());
515
516 Ok(())
517}
518
519#[driver_test(id(ID), requires(sql))]
522pub async fn two_sequential_nested_transactions(t: &mut Test) -> Result<()> {
523 #[derive(Debug, toasty::Model)]
524 struct User {
525 #[key]
526 #[auto]
527 id: ID,
528 name: String,
529 }
530
531 let mut db = t.setup_db(models!(User)).await;
532
533 let mut tx = db.transaction().await?;
534
535 {
536 let mut nested1 = tx.transaction().await?;
537 User::create().name("Alice").exec(&mut nested1).await?;
538 nested1.commit().await?;
539 }
540
541 {
542 let mut nested2 = tx.transaction().await?;
543 User::create().name("Ghost").exec(&mut nested2).await?;
544 nested2.rollback().await?;
545 }
546
547 tx.commit().await?;
548
549 let users = User::all().exec(&mut db).await?;
550 assert_eq!(users.len(), 1);
551 assert_eq!(users[0].name, "Alice");
552
553 Ok(())
554}
555
556#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::has_many_belongs_to))]
562pub async fn multi_op_inside_tx_uses_savepoints(t: &mut Test) -> Result<()> {
563 let mut db = setup(t).await;
564
565 t.log().clear();
566
567 let mut tx = db.transaction().await?;
568 let user = User::create()
569 .name("Alice")
570 .todo(Todo::create().title("task"))
571 .exec(&mut tx)
572 .await?;
573 tx.commit().await?;
574
575 assert_struct!(
577 t.log().pop_op(),
578 Operation::Transaction(Transaction::Start {
579 isolation: None,
580 read_only: false
581 })
582 );
583 assert_struct!(
585 t.log().pop_op(),
586 Operation::Transaction(Transaction::Savepoint(_))
587 );
588 assert_struct!(t.log().pop_op(), Operation::QuerySql(_));
590 assert_struct!(t.log().pop_op(), Operation::QuerySql(_));
592 assert_struct!(
594 t.log().pop_op(),
595 Operation::Transaction(Transaction::ReleaseSavepoint(_))
596 );
597 assert_struct!(
599 t.log().pop_op(),
600 Operation::Transaction(Transaction::Commit)
601 );
602 assert!(t.log().is_empty());
603
604 let todos = user.todos().exec(&mut db).await?;
606 assert_eq!(todos.len(), 1);
607 assert_eq!(todos[0].title, "task");
608
609 Ok(())
610}