Skip to main content

sqlx_cloudflare_do/
transaction.rs

1use std::future::{self, Future};
2
3use sqlx_core::error::Error;
4use sqlx_core::sql_str::SqlStr;
5use sqlx_core::transaction::TransactionManager;
6
7use crate::error::unsupported;
8use crate::{Do, DoConnection};
9
10const NO_TRANSACTIONS: &str = "Durable Object storage has no interactive transactions; \
11     send the statements together with `DoConnection::execute_batch`, \
12     which runs them atomically";
13
14/// Refuses every transaction.
15///
16/// `sql.exec` rejects `BEGIN` and `SAVEPOINT` outright: the only transactions
17/// Durable Object storage offers wrap a callback, and sqlx's `begin` and
18/// `commit` are two separate calls with the caller's code in between.
19/// Buffering writes until `commit` would look like a transaction and not be
20/// one -- reads inside it would see the database as it was before -- which is
21/// worse than an error. So `conn.begin()` compiles and fails at runtime, and
22/// the atomic multi-statement case goes through `DoConnection::execute_batch`.
23#[derive(Debug)]
24pub struct DoTransactionManager;
25
26impl TransactionManager for DoTransactionManager {
27    type Database = Do;
28
29    fn begin(
30        _conn: &mut DoConnection,
31        _statement: Option<SqlStr>,
32    ) -> impl Future<Output = Result<(), Error>> + Send + '_ {
33        future::ready(Err(unsupported(NO_TRANSACTIONS)))
34    }
35
36    // Unreachable in practice: `begin` never succeeds, so there is never a
37    // transaction to end. They still answer rather than panic.
38    fn commit(_conn: &mut DoConnection) -> impl Future<Output = Result<(), Error>> + Send + '_ {
39        future::ready(Err(unsupported(NO_TRANSACTIONS)))
40    }
41
42    fn rollback(_conn: &mut DoConnection) -> impl Future<Output = Result<(), Error>> + Send + '_ {
43        future::ready(Err(unsupported(NO_TRANSACTIONS)))
44    }
45
46    // `Transaction` calls this from `Drop` when `begin` failed -- it cannot
47    // tell a failed begin from an abandoned transaction -- so it must be a
48    // quiet no-op, not an error.
49    fn start_rollback(_conn: &mut DoConnection) {}
50
51    fn get_transaction_depth(_conn: &DoConnection) -> usize {
52        0
53    }
54}