toasty_driver_integration_suite/tests/
field_version.rs1use crate::prelude::*;
2
3#[driver_test(scenario(crate::scenarios::versioned_item))]
5pub async fn create_initializes_version(test: &mut Test) -> Result<()> {
6 let mut db = setup(test).await;
7
8 let item = toasty::create!(Item { name: "hello" })
9 .exec(&mut db)
10 .await?;
11 assert_eq!(item.version, 1);
12
13 Ok(())
14}
15
16#[driver_test(scenario(crate::scenarios::versioned_item))]
18pub async fn update_increments_version(test: &mut Test) -> Result<()> {
19 let mut db = setup(test).await;
20
21 let mut item = toasty::create!(Item { name: "hello" })
22 .exec(&mut db)
23 .await?;
24 assert_eq!(item.version, 1);
25
26 item.update().name("world").exec(&mut db).await?;
27 assert_eq!(item.version, 2);
28
29 item.update().name("again").exec(&mut db).await?;
30 assert_eq!(item.version, 3);
31
32 Ok(())
33}
34
35#[driver_test(scenario(crate::scenarios::versioned_counter))]
42pub async fn relative_update_increments_value_and_version(test: &mut Test) -> Result<()> {
43 let mut db = setup(test).await;
44
45 let mut counter = toasty::create!(Counter { value: 10 }).exec(&mut db).await?;
46 assert_struct!(counter, _ { value: 10, version: 1, .. });
47
48 counter
49 .update()
50 .value(toasty::stmt::increment())
51 .exec(&mut db)
52 .await?;
53
54 assert_struct!(counter, _ { value: 11, version: 2, .. });
57
58 let reloaded = Counter::filter_by_id(counter.id).get(&mut db).await?;
60 assert_struct!(reloaded, _ { value: 11, version: 2, .. });
61
62 Ok(())
63}
64
65#[driver_test(scenario(crate::scenarios::versioned_item))]
68pub async fn stale_update_fails(test: &mut Test) -> Result<()> {
69 let mut db = setup(test).await;
70
71 let mut item = toasty::create!(Item { name: "hello" })
72 .exec(&mut db)
73 .await?;
74 assert_eq!(item.version, 1);
75
76 let mut stale = Item::filter_by_id(item.id).get(&mut db).await?;
78 assert_eq!(stale.version, 1);
79
80 item.update().name("updated").exec(&mut db).await?;
82 assert_eq!(item.version, 2);
83
84 let result: Result<()> = stale.update().name("should fail").exec(&mut db).await;
86 assert!(
87 result.is_err(),
88 "expected stale update to fail, but it succeeded"
89 );
90
91 Ok(())
92}
93
94#[driver_test(scenario(crate::scenarios::versioned_item))]
98pub async fn duplicate_create_fails(test: &mut Test) -> Result<()> {
99 let mut db = setup(test).await;
100
101 let item = toasty::create!(Item { name: "original" })
102 .exec(&mut db)
103 .await?;
104
105 let result = toasty::create!(Item {
106 id: item.id,
107 name: "duplicate"
108 })
109 .exec(&mut db)
110 .await;
111
112 assert!(
113 result.is_err(),
114 "expected duplicate create to fail, but it succeeded"
115 );
116
117 Ok(())
118}
119
120#[driver_test(scenario(crate::scenarios::versioned_item))]
123pub async fn batch_insert_checks_version(test: &mut Test) -> Result<()> {
124 let mut db = setup(test).await;
125
126 let items = toasty::create!(Item::[
128 { name: "first" },
129 { name: "second" },
130 ])
131 .exec(&mut db)
132 .await?;
133
134 assert_eq!(items.len(), 2);
135 assert!(items.iter().all(|i| i.version == 1));
136
137 let existing_id = items[0].id;
139 let result = toasty::create!(Item::[
140 { id: existing_id, name: "duplicate" },
141 { name: "new" },
142 ])
143 .exec(&mut db)
144 .await;
145
146 assert!(
147 result.is_err(),
148 "expected batch create with duplicate to fail"
149 );
150
151 Ok(())
152}
153
154#[driver_test(scenario(crate::scenarios::versioned_item))]
161pub async fn query_update_increments_version(test: &mut Test) -> Result<()> {
162 let mut db = setup(test).await;
163
164 let item = toasty::create!(Item { name: "hello" })
165 .exec(&mut db)
166 .await?;
167 assert_eq!(item.version, 1);
168
169 Item::filter_by_id(item.id)
170 .update()
171 .name("world")
172 .exec(&mut db)
173 .await?;
174
175 let reloaded = Item::filter_by_id(item.id).get(&mut db).await?;
176 assert_eq!(reloaded.name, "world");
177 assert_eq!(reloaded.version, 2);
178
179 Ok(())
180}
181
182#[driver_test(scenario(crate::scenarios::versioned_item))]
186pub async fn query_update_invalidates_stale_instance(test: &mut Test) -> Result<()> {
187 let mut db = setup(test).await;
188
189 let item = toasty::create!(Item { name: "hello" })
190 .exec(&mut db)
191 .await?;
192 assert_eq!(item.version, 1);
193
194 let mut stale = Item::filter_by_id(item.id).get(&mut db).await?;
196 assert_eq!(stale.version, 1);
197
198 Item::filter_by_id(item.id)
200 .update()
201 .name("query-updated")
202 .exec(&mut db)
203 .await?;
204
205 let result: Result<()> = stale.update().name("clobber").exec(&mut db).await;
207 assert!(
208 result.is_err(),
209 "expected stale instance update to fail after a concurrent query update"
210 );
211
212 let reloaded = Item::filter_by_id(item.id).get(&mut db).await?;
214 assert_eq!(reloaded.name, "query-updated");
215 assert_eq!(reloaded.version, 2);
216
217 Ok(())
218}
219
220#[driver_test(scenario(crate::scenarios::tagged_item))]
228pub async fn query_update_multi_key_works(test: &mut Test) -> Result<()> {
229 let mut db = setup(test).await;
230
231 let items = toasty::create!(Item::[
233 { tag: "batch", status: "active", name: "alpha" },
234 { tag: "batch", status: "active", name: "beta" },
235 ])
236 .exec(&mut db)
237 .await?;
238 assert!(items.iter().all(|i| i.version == 1));
239
240 Item::filter_by_tag("batch")
242 .update()
243 .name("updated")
244 .exec(&mut db)
245 .await?;
246
247 let a2 = Item::filter_by_id(items[0].id).get(&mut db).await?;
248 let b2 = Item::filter_by_id(items[1].id).get(&mut db).await?;
249 assert_eq!(a2.name, "updated");
250 assert_eq!(a2.version, 2);
251 assert_eq!(b2.name, "updated");
252 assert_eq!(b2.version, 2);
253
254 Ok(())
255}
256
257#[driver_test(scenario(crate::scenarios::versioned_user_unique_email))]
261pub async fn query_update_unique_index_increments_version(test: &mut Test) -> Result<()> {
262 let mut db = setup(test).await;
263
264 let user = toasty::create!(User {
265 email: "carol@example.com"
266 })
267 .exec(&mut db)
268 .await?;
269 assert_eq!(user.version, 1);
270
271 User::filter_by_id(user.id)
272 .update()
273 .email("carol2@example.com")
274 .exec(&mut db)
275 .await?;
276
277 let reloaded = User::filter_by_id(user.id).get(&mut db).await?;
278 assert_eq!(reloaded.email, "carol2@example.com");
279 assert_eq!(reloaded.version, 2);
280
281 Ok(())
282}
283
284#[driver_test(scenario(crate::scenarios::versioned_user_unique_email))]
287pub async fn unique_index_update_increments_version(test: &mut Test) -> Result<()> {
288 let mut db = setup(test).await;
289
290 let mut user = toasty::create!(User {
291 email: "alice@example.com"
292 })
293 .exec(&mut db)
294 .await?;
295 assert_eq!(user.version, 1);
296
297 user.update()
298 .email("alice2@example.com")
299 .exec(&mut db)
300 .await?;
301 assert_eq!(user.version, 2);
302
303 user.update()
304 .email("alice3@example.com")
305 .exec(&mut db)
306 .await?;
307 assert_eq!(user.version, 3);
308
309 Ok(())
310}
311
312#[driver_test(scenario(crate::scenarios::versioned_user_unique_email))]
315pub async fn unique_index_stale_update_fails(test: &mut Test) -> Result<()> {
316 let mut db = setup(test).await;
317
318 let mut user = toasty::create!(User {
319 email: "bob@example.com"
320 })
321 .exec(&mut db)
322 .await?;
323 assert_eq!(user.version, 1);
324
325 let mut stale = User::filter_by_email("bob@example.com")
326 .get(&mut db)
327 .await?;
328 assert_eq!(stale.version, 1);
329
330 user.update()
332 .email("bob2@example.com")
333 .exec(&mut db)
334 .await?;
335 assert_eq!(user.version, 2);
336
337 let result: Result<()> = stale.update().email("bob3@example.com").exec(&mut db).await;
339 assert!(
340 result.is_err(),
341 "expected stale unique-index update to fail"
342 );
343
344 Ok(())
345}
346
347#[driver_test(scenario(crate::scenarios::versioned_counter))]
356pub async fn query_relative_update_increments_value_and_version(test: &mut Test) -> Result<()> {
357 let mut db = setup(test).await;
358
359 let counter = toasty::create!(Counter { value: 10 }).exec(&mut db).await?;
360 assert_struct!(counter, _ { value: 10, version: 1, .. });
361
362 Counter::filter_by_id(counter.id)
363 .update()
364 .value(toasty::stmt::increment())
365 .exec(&mut db)
366 .await?;
367
368 let reloaded = Counter::filter_by_id(counter.id).get(&mut db).await?;
369 assert_struct!(reloaded, _ { value: 11, version: 2, .. });
370
371 Ok(())
372}
373
374#[driver_test(scenario(crate::scenarios::versioned_item))]
376pub async fn delete_checks_version(test: &mut Test) -> Result<()> {
377 let mut db = setup(test).await;
378
379 let item = toasty::create!(Item { name: "hello" })
380 .exec(&mut db)
381 .await?;
382 assert_eq!(item.version, 1);
383 let id = item.id;
384
385 item.delete().exec(&mut db).await?;
386
387 let after_delete = Item::filter_by_id(id).get(&mut db).await;
389 assert!(after_delete.is_err(), "item should have been deleted");
390
391 Ok(())
392}
393
394#[driver_test(scenario(crate::scenarios::versioned_item))]
397pub async fn update_after_delete_fails(test: &mut Test) -> Result<()> {
398 let mut db = setup(test).await;
399
400 let mut item = toasty::create!(Item { name: "hello" })
401 .exec(&mut db)
402 .await?;
403
404 Item::filter_by_id(item.id).delete().exec(&mut db).await?;
406
407 let result: Result<()> = item.update().name("stale").exec(&mut db).await;
408 let err = assert_err!(result);
409 if test.capability().sql {
410 assert!(
411 err.is_record_not_found(),
412 "expected record_not_found, got {err:?}"
413 );
414 }
415
416 Ok(())
417}
418
419#[driver_test(scenario(crate::scenarios::versioned_counter))]
424pub async fn relative_update_after_delete_fails(test: &mut Test) -> Result<()> {
425 let mut db = setup(test).await;
426
427 let mut counter = toasty::create!(Counter { value: 10 }).exec(&mut db).await?;
428
429 Counter::filter_by_id(counter.id)
430 .delete()
431 .exec(&mut db)
432 .await?;
433
434 let result: Result<()> = counter
435 .update()
436 .value(toasty::stmt::increment())
437 .exec(&mut db)
438 .await;
439 let err = assert_err!(result);
440 if test.capability().sql {
441 assert!(
442 err.is_record_not_found(),
443 "expected record_not_found, got {err:?}"
444 );
445 }
446
447 Ok(())
448}
449
450#[driver_test]
455pub async fn update_with_float_field_works(test: &mut Test) -> Result<()> {
456 #[derive(Debug, toasty::Model)]
457 struct Gauge {
458 #[key]
459 #[auto]
460 id: uuid::Uuid,
461
462 value: f64,
463
464 #[version]
465 version: u64,
466 }
467
468 let mut db = test.setup_db(models!(Gauge)).await;
469
470 let mut gauge = toasty::create!(Gauge { value: 1.5 }).exec(&mut db).await?;
471
472 gauge.update().value(2.5).exec(&mut db).await?;
473 assert_struct!(gauge, _ { value: 2.5, version: 2, .. });
474
475 let reloaded = Gauge::filter_by_id(gauge.id).get(&mut db).await?;
476 assert_struct!(reloaded, _ { value: 2.5, version: 2, .. });
477
478 Ok(())
479}
480
481#[driver_test(scenario(crate::scenarios::versioned_item))]
483pub async fn stale_delete_fails(test: &mut Test) -> Result<()> {
484 let mut db = setup(test).await;
485
486 let mut item = toasty::create!(Item { name: "hello" })
487 .exec(&mut db)
488 .await?;
489 assert_eq!(item.version, 1);
490
491 let stale = Item::filter_by_id(item.id).get(&mut db).await?;
493 item.update().name("updated").exec(&mut db).await?;
494 assert_eq!(item.version, 2);
495
496 let result: Result<()> = stale.delete().exec(&mut db).await;
498 assert!(result.is_err(), "expected stale delete to fail");
499
500 let _ = Item::filter_by_id(item.id)
502 .get(&mut db)
503 .await
504 .expect("item should still exist");
505
506 Ok(())
507}