toasty_driver_integration_suite/tests/
batch_rollback.rs1use crate::prelude::*;
2
3use toasty_core::driver::{operation::Transaction, Operation};
4
5#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
9pub async fn batch_two_creates_rolls_back_on_second_failure(t: &mut Test) -> Result<()> {
10 let mut db = setup(t).await;
11
12 User::create()
14 .email("taken@example.com")
15 .exec(&mut db)
16 .await?;
17
18 t.log().clear();
19 assert_err!(
20 toasty::batch((
21 User::create().email("new@example.com"),
22 User::create().email("taken@example.com"),
23 ))
24 .exec(&mut db)
25 .await
26 );
27
28 assert_struct!(
30 t.log().pop_op(),
31 Operation::Transaction(Transaction::Start {
32 isolation: None,
33 read_only: false
34 })
35 );
36 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
38 t.log().pop_op(),
39 Operation::Transaction(Transaction::Rollback)
40 );
41 assert!(t.log().is_empty());
42
43 let users: Vec<User> = User::all().exec(&mut db).await?;
45 assert_eq!(1, users.len());
46 assert_eq!(users[0].email, "taken@example.com");
47
48 Ok(())
49}
50
51#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
54pub async fn batch_create_and_update_rolls_back_on_update_failure(t: &mut Test) -> Result<()> {
55 let mut db = setup(t).await;
56
57 User::create()
58 .email("alice@example.com")
59 .exec(&mut db)
60 .await?;
61 User::create()
62 .email("taken@example.com")
63 .exec(&mut db)
64 .await?;
65
66 t.log().clear();
67 assert_err!(
68 toasty::batch((
69 User::create().email("bob@example.com"),
70 User::filter_by_email("alice@example.com")
71 .update()
72 .email("taken@example.com"), ))
74 .exec(&mut db)
75 .await
76 );
77
78 assert_struct!(
80 t.log().pop_op(),
81 Operation::Transaction(Transaction::Start {
82 isolation: None,
83 read_only: false
84 })
85 );
86 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
88 t.log().pop_op(),
89 Operation::Transaction(Transaction::Rollback)
90 );
91 assert!(t.log().is_empty());
92
93 let all: Vec<User> = User::all().exec(&mut db).await?;
95 assert_eq!(2, all.len());
96 let emails: std::collections::HashSet<_> = all.iter().map(|u| u.email.as_str()).collect();
97 assert!(emails.contains("alice@example.com"));
98 assert!(emails.contains("taken@example.com"));
99
100 Ok(())
101}
102
103#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
106pub async fn batch_update_and_create_rolls_back_on_create_failure(t: &mut Test) -> Result<()> {
107 let mut db = setup(t).await;
108
109 User::create()
110 .email("alice@example.com")
111 .exec(&mut db)
112 .await?;
113 User::create()
114 .email("taken@example.com")
115 .exec(&mut db)
116 .await?;
117
118 t.log().clear();
119 assert_err!(
120 toasty::batch((
121 User::filter_by_email("alice@example.com")
122 .update()
123 .email("alice2@example.com"),
124 User::create().email("taken@example.com"), ))
126 .exec(&mut db)
127 .await
128 );
129
130 assert_struct!(
132 t.log().pop_op(),
133 Operation::Transaction(Transaction::Start {
134 isolation: None,
135 read_only: false
136 })
137 );
138 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
140 t.log().pop_op(),
141 Operation::Transaction(Transaction::Rollback)
142 );
143 assert!(t.log().is_empty());
144
145 let alice: Vec<User> = User::filter_by_email("alice@example.com")
147 .exec(&mut db)
148 .await?;
149 assert_eq!(1, alice.len());
150
151 let alice2: Vec<User> = User::filter_by_email("alice2@example.com")
153 .exec(&mut db)
154 .await?;
155 assert!(alice2.is_empty());
156
157 Ok(())
158}
159
160#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
163pub async fn batch_array_creates_rolls_back_on_failure(t: &mut Test) -> Result<()> {
164 let mut db = setup(t).await;
165
166 User::create()
168 .email("taken@example.com")
169 .exec(&mut db)
170 .await?;
171
172 t.log().clear();
173 assert_err!(
174 toasty::batch([
175 User::create().email("first@example.com"),
176 User::create().email("second@example.com"),
177 User::create().email("taken@example.com"), ])
179 .exec(&mut db)
180 .await
181 );
182
183 assert_struct!(
185 t.log().pop_op(),
186 Operation::Transaction(Transaction::Start {
187 isolation: None,
188 read_only: false
189 })
190 );
191 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
194 t.log().pop_op(),
195 Operation::Transaction(Transaction::Rollback)
196 );
197 assert!(t.log().is_empty());
198
199 let users: Vec<User> = User::all().exec(&mut db).await?;
201 assert_eq!(1, users.len());
202 assert_eq!(users[0].email, "taken@example.com");
203
204 Ok(())
205}
206
207#[driver_test(id(ID), requires(sql))]
210pub async fn batch_different_models_rolls_back_on_failure(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 #[derive(Debug, toasty::Model)]
220 struct Post {
221 #[key]
222 #[auto]
223 id: ID,
224
225 #[unique]
226 title: String,
227 }
228
229 let mut db = t.setup_db(models!(User, Post)).await;
230
231 Post::create().title("taken").exec(&mut db).await?;
233
234 t.log().clear();
235 assert_err!(
236 toasty::batch((
237 User::create().name("alice"),
238 Post::create().title("taken"), ))
240 .exec(&mut db)
241 .await
242 );
243
244 assert_struct!(
246 t.log().pop_op(),
247 Operation::Transaction(Transaction::Start {
248 isolation: None,
249 read_only: false
250 })
251 );
252 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
254 t.log().pop_op(),
255 Operation::Transaction(Transaction::Rollback)
256 );
257 assert!(t.log().is_empty());
258
259 let users: Vec<User> = User::all().exec(&mut db).await?;
261 assert!(users.is_empty());
262
263 let posts: Vec<Post> = Post::all().exec(&mut db).await?;
265 assert_eq!(1, posts.len());
266
267 Ok(())
268}