/
germanubis
/
rust-postgres
Обзор
Документация
Войти
/
germanubis
/
rust-postgres
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tokio-postgres/src/transaction_builder.rs
140 строк
4 KB
Fredrik Enestad
expose sync rollback as a private api method
02 апр 2025, 15:46
02 апр 2025, 15:46
7d52522
Код
Авторство
О чём код?
use crate::{Client, Error, Transaction}; /// The isolation level of a database transaction. #[derive(Debug, Copy, Clone)] #[non_exhaustive] pub enum IsolationLevel { /// Equivalent to `ReadCommitted`. ReadUncommitted, /// An individual statement in the transaction will see rows committed before it began. ReadCommitted, /// All statements in the transaction will see the same view of rows committed before the first query in the /// transaction. RepeatableRead, /// The reads and writes in this transaction must be able to be committed as an atomic "unit" with respect to reads /// and writes of all other concurrent serializable transactions without interleaving. Serializable, } /// A builder for database transactions. pub struct TransactionBuilder<'a> { client: &'a mut Client, isolation_level: Option<IsolationLevel>, read_only: Option<bool>, deferrable: Option<bool>, } impl<'a> TransactionBuilder<'a> { pub(crate) fn new(client: &'a mut Client) -> TransactionBuilder<'a> { TransactionBuilder { client, isolation_level: None, read_only: None, deferrable: None, } } /// Sets the isolation level of the transaction. pub fn isolation_level(mut self, isolation_level: IsolationLevel) -> Self { self.isolation_level = Some(isolation_level); self } /// Sets the access mode of the transaction. pub fn read_only(mut self, read_only: bool) -> Self { self.read_only = Some(read_only); self } /// Sets the deferrability of the transaction. /// /// If the transaction is also serializable and read only, creation of the transaction may block, but when it /// completes the transaction is able to run with less overhead and a guarantee that it will not be aborted due to /// serialization failure. pub fn deferrable(mut self, deferrable: bool) -> Self { self.deferrable = Some(deferrable); self } /// Begins the transaction. /// /// The transaction will roll back by default - use the `commit` method to commit it. pub async fn start(self) -> Result<Transaction<'a>, Error> { let mut query = "START TRANSACTION".to_string(); let mut first = true; if let Some(level) = self.isolation_level { first = false; query.push_str(" ISOLATION LEVEL "); let level = match level { IsolationLevel::ReadUncommitted => "READ UNCOMMITTED", IsolationLevel::ReadCommitted => "READ COMMITTED", IsolationLevel::RepeatableRead => "REPEATABLE READ", IsolationLevel::Serializable => "SERIALIZABLE", }; query.push_str(level); } if let Some(read_only) = self.read_only { if !first { query.push(','); } first = false; let s = if read_only { " READ ONLY" } else { " READ WRITE" }; query.push_str(s); } if let Some(deferrable) = self.deferrable { if !first { query.push(','); } let s = if deferrable { " DEFERRABLE" } else { " NOT DEFERRABLE" }; query.push_str(s); } struct RollbackIfNotDone<'me> { client: &'me Client, done: bool, } impl Drop for RollbackIfNotDone<'_> { fn drop(&mut self) { if self.done { return; } self.client.__private_api_rollback(None); } } // This is done as `Future` created by this method can be dropped after // `RequestMessages` is synchronously send to the `Connection` by // `batch_execute()`, but before `Responses` is asynchronously polled to // completion. In that case `Transaction` won't be created and thus // won't be rolled back. { let mut cleaner = RollbackIfNotDone { client: self.client, done: false, }; self.client.batch_execute(&query).await?; cleaner.done = true; } Ok(Transaction::new(self.client)) } }