cratefield_testing/
batch.rs1use cratefield_core::{Database, Statement};
7
8pub async fn assert_batch_is_atomic(db: &dyn Database) {
21 db.execute(&Statement::new(
22 "CREATE TABLE IF NOT EXISTS batch_atomicity_probe \
23 (id TEXT PRIMARY KEY, marker TEXT NOT NULL)",
24 ))
25 .await
26 .expect("probe table");
27
28 db.execute(&Statement::new("DELETE FROM batch_atomicity_probe"))
29 .await
30 .expect("clear probe");
31
32 let commits = vec![
33 Statement::with_values(
34 "INSERT INTO batch_atomicity_probe (id, marker) VALUES (?, ?)",
35 vec!["committed-1".into(), "batch".into()],
36 ),
37 Statement::with_values(
38 "INSERT INTO batch_atomicity_probe (id, marker) VALUES (?, ?)",
39 vec!["committed-2".into(), "batch".into()],
40 ),
41 ];
42 db.batch_atomic(&commits)
43 .await
44 .expect("a valid batch commits");
45 let rows = db
46 .query(&Statement::new(
47 "SELECT id FROM batch_atomicity_probe ORDER BY id",
48 ))
49 .await
50 .expect("read back");
51 assert_eq!(
52 rows.len(),
53 2,
54 "a committed batch leaves every statement visible"
55 );
56
57 let mid_batch = vec![
58 Statement::with_values(
59 "INSERT INTO batch_atomicity_probe (id, marker) VALUES (?, ?)",
60 vec!["doomed".into(), "must not survive".into()],
61 ),
62 Statement::new("THIS IS NOT SQL"),
63 ];
64 assert!(
65 db.batch_atomic(&mid_batch).await.is_err(),
66 "a batch with a failing statement must fail"
67 );
68 let survivors = db
69 .query(&Statement::with_values(
70 "SELECT id FROM batch_atomicity_probe WHERE id = ?",
71 vec!["doomed".into()],
72 ))
73 .await
74 .expect("read back");
75 assert!(
76 survivors.is_empty(),
77 "nothing from a failed batch is visible afterwards"
78 );
79
80 db.execute(&Statement::new("DELETE FROM batch_atomicity_probe"))
81 .await
82 .expect("clean probe");
83}