toasty_driver_integration_suite/tests/
batch_rollback.rs1use crate::prelude::*;
2
3use toasty_core::driver::{Operation, operation::Transaction};
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 );
37 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
39 t.log().pop_op(),
40 Operation::Transaction(Transaction::Rollback)
41 );
42 assert!(t.log().is_empty());
43
44 let users: Vec<User> = User::all().exec(&mut db).await?;
46 assert_eq!(1, users.len());
47 assert_eq!(users[0].email, "taken@example.com");
48
49 Ok(())
50}
51
52#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
55pub async fn batch_create_and_update_rolls_back_on_update_failure(t: &mut Test) -> Result<()> {
56 let mut db = setup(t).await;
57
58 User::create()
59 .email("alice@example.com")
60 .exec(&mut db)
61 .await?;
62 User::create()
63 .email("taken@example.com")
64 .exec(&mut db)
65 .await?;
66
67 t.log().clear();
68 assert_err!(
69 toasty::batch((
70 User::create().email("bob@example.com"),
71 User::filter_by_email("alice@example.com")
72 .update()
73 .email("taken@example.com"), ))
75 .exec(&mut db)
76 .await
77 );
78
79 assert_struct!(
81 t.log().pop_op(),
82 Operation::Transaction(Transaction::Start {
83 isolation: None,
84 read_only: false,
85 ..
86 })
87 );
88 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
90 t.log().pop_op(),
91 Operation::Transaction(Transaction::Rollback)
92 );
93 assert!(t.log().is_empty());
94
95 let all: Vec<User> = User::all().exec(&mut db).await?;
97 assert_eq!(2, all.len());
98 let emails: hashbrown::HashSet<_> = all.iter().map(|u| u.email.as_str()).collect();
99 assert!(emails.contains("alice@example.com"));
100 assert!(emails.contains("taken@example.com"));
101
102 Ok(())
103}
104
105#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
108pub async fn batch_update_and_create_rolls_back_on_create_failure(t: &mut Test) -> Result<()> {
109 let mut db = setup(t).await;
110
111 User::create()
112 .email("alice@example.com")
113 .exec(&mut db)
114 .await?;
115 User::create()
116 .email("taken@example.com")
117 .exec(&mut db)
118 .await?;
119
120 t.log().clear();
121 assert_err!(
122 toasty::batch((
123 User::filter_by_email("alice@example.com")
124 .update()
125 .email("alice2@example.com"),
126 User::create().email("taken@example.com"), ))
128 .exec(&mut db)
129 .await
130 );
131
132 assert_struct!(
134 t.log().pop_op(),
135 Operation::Transaction(Transaction::Start {
136 isolation: None,
137 read_only: false,
138 ..
139 })
140 );
141 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
143 t.log().pop_op(),
144 Operation::Transaction(Transaction::Rollback)
145 );
146 assert!(t.log().is_empty());
147
148 let alice: Vec<User> = User::filter_by_email("alice@example.com")
150 .exec(&mut db)
151 .await?;
152 assert_eq!(1, alice.len());
153
154 let alice2: Vec<User> = User::filter_by_email("alice2@example.com")
156 .exec(&mut db)
157 .await?;
158 assert!(alice2.is_empty());
159
160 Ok(())
161}
162
163#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::user_unique_email))]
166pub async fn batch_array_creates_rolls_back_on_failure(t: &mut Test) -> Result<()> {
167 let mut db = setup(t).await;
168
169 User::create()
171 .email("taken@example.com")
172 .exec(&mut db)
173 .await?;
174
175 t.log().clear();
176 assert_err!(
177 toasty::batch([
178 User::create().email("first@example.com"),
179 User::create().email("second@example.com"),
180 User::create().email("taken@example.com"), ])
182 .exec(&mut db)
183 .await
184 );
185
186 assert_struct!(
188 t.log().pop_op(),
189 Operation::Transaction(Transaction::Start {
190 isolation: None,
191 read_only: false,
192 ..
193 })
194 );
195 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
198 t.log().pop_op(),
199 Operation::Transaction(Transaction::Rollback)
200 );
201 assert!(t.log().is_empty());
202
203 let users: Vec<User> = User::all().exec(&mut db).await?;
205 assert_eq!(1, users.len());
206 assert_eq!(users[0].email, "taken@example.com");
207
208 Ok(())
209}
210
211#[driver_test(id(ID), requires(sql))]
214pub async fn batch_different_models_rolls_back_on_failure(t: &mut Test) -> Result<()> {
215 #[derive(Debug, toasty::Model)]
216 struct User {
217 #[key]
218 #[auto]
219 id: ID,
220 name: String,
221 }
222
223 #[derive(Debug, toasty::Model)]
224 struct Post {
225 #[key]
226 #[auto]
227 id: ID,
228
229 #[unique]
230 title: String,
231 }
232
233 let mut db = t.setup_db(models!(User, Post)).await;
234
235 Post::create().title("taken").exec(&mut db).await?;
237
238 t.log().clear();
239 assert_err!(
240 toasty::batch((
241 User::create().name("alice"),
242 Post::create().title("taken"), ))
244 .exec(&mut db)
245 .await
246 );
247
248 assert_struct!(
250 t.log().pop_op(),
251 Operation::Transaction(Transaction::Start {
252 isolation: None,
253 read_only: false,
254 ..
255 })
256 );
257 assert_struct!(t.log().pop_op(), Operation::QuerySql(_)); assert_struct!(
259 t.log().pop_op(),
260 Operation::Transaction(Transaction::Rollback)
261 );
262 assert!(t.log().is_empty());
263
264 let users: Vec<User> = User::all().exec(&mut db).await?;
266 assert!(users.is_empty());
267
268 let posts: Vec<Post> = Post::all().exec(&mut db).await?;
270 assert_eq!(1, posts.len());
271
272 Ok(())
273}