toasty_core/driver/operation/transaction.rs
1use super::Operation;
2
3/// SQL transaction isolation levels.
4///
5/// Not all backends support all levels. The driver returns an error if an
6/// unsupported level is requested.
7///
8/// # Examples
9///
10/// ```
11/// use toasty_core::driver::operation::IsolationLevel;
12///
13/// let level = IsolationLevel::Serializable;
14/// assert_eq!(level, IsolationLevel::Serializable);
15/// ```
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum IsolationLevel {
18 /// Transactions can see uncommitted changes from other transactions.
19 ReadUncommitted,
20 /// Transactions only see changes committed before each statement.
21 ReadCommitted,
22 /// Transactions see a consistent snapshot from the start of the transaction.
23 RepeatableRead,
24 /// Full serializability; transactions behave as if executed one at a time.
25 Serializable,
26}
27
28/// How a transaction acquires write locks.
29///
30/// Orthogonal to [`IsolationLevel`]: an isolation level describes *what
31/// anomalies* a transaction can observe; a mode describes *when* the
32/// transaction acquires its locks.
33///
34/// Only SQLite (and SQLite-compatible engines) currently expose this
35/// dimension to clients:
36///
37/// * [`Default`](Self::Default) → whatever the driver picks. For SQLite
38/// that is `BEGIN` (DEFERRED) today; for a future driver it may not
39/// be — e.g. Turso under MVCC plans to default to `BEGIN CONCURRENT`.
40/// * [`Deferred`](Self::Deferred) → `BEGIN` (DEFERRED): explicit
41/// deferred locking. Identical to `Default` on plain SQLite; on a
42/// driver whose default is *not* deferred (Turso MVCC), this is how
43/// the caller opts out of that default.
44/// * [`Immediate`](Self::Immediate) → `BEGIN IMMEDIATE`: write lock
45/// acquired up front, so a later write inside the transaction cannot
46/// fail with `SQLITE_BUSY`.
47/// * [`Exclusive`](Self::Exclusive) → `BEGIN EXCLUSIVE`: exclusive lock
48/// held for the lifetime of the transaction; no other connection —
49/// reader or writer — can make progress against the database file.
50///
51/// Drivers that do not implement a given mode return
52/// [`Error::unsupported_feature`](crate::Error::unsupported_feature) when
53/// the transaction starts. Future drivers may extend this enum (e.g. a
54/// Turso `Concurrent` variant for `BEGIN CONCURRENT` under MVCC).
55#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
56pub enum TransactionMode {
57 /// The driver's natural default. May differ from
58 /// [`Deferred`](Self::Deferred) on drivers that prefer a different
59 /// locking strategy (e.g. Turso MVCC → `BEGIN CONCURRENT`).
60 #[default]
61 Default,
62 /// Explicit deferred locking. SQLite → `BEGIN` (DEFERRED). Use this
63 /// to override a driver whose `Default` is not deferred.
64 Deferred,
65 /// Acquire a write lock when the transaction begins. SQLite →
66 /// `BEGIN IMMEDIATE`. Rejected by drivers without an equivalent.
67 Immediate,
68 /// Hold an exclusive lock for the entire transaction. SQLite →
69 /// `BEGIN EXCLUSIVE`. Rejected by drivers without an equivalent.
70 Exclusive,
71}
72
73/// A transaction lifecycle operation.
74///
75/// Covers the full transaction lifecycle: begin, commit, rollback, and
76/// savepoint management. Convert to [`Operation`] with `.into()`.
77///
78/// # Examples
79///
80/// ```
81/// use toasty_core::driver::operation::{Transaction, Operation};
82///
83/// // Start a default transaction
84/// let op: Operation = Transaction::start().into();
85///
86/// // Commit
87/// let op: Operation = Transaction::Commit.into();
88/// assert!(op.is_transaction_commit());
89/// ```
90#[derive(Debug, Clone)]
91pub enum Transaction {
92 /// Start a transaction with optional configuration.
93 ///
94 /// When `isolation` is `None`, `read_only` is `false`, and `mode` is
95 /// [`TransactionMode::Default`], the database's natural defaults are
96 /// used.
97 Start {
98 /// Optional isolation level. `None` uses the database default.
99 isolation: Option<IsolationLevel>,
100 /// When `true`, the transaction is read-only.
101 read_only: bool,
102 /// Lock-acquisition mode. See [`TransactionMode`].
103 mode: TransactionMode,
104 },
105
106 /// Commit a transaction
107 Commit,
108
109 /// Rollback a transaction
110 Rollback,
111
112 /// Create a savepoint with the given identifier
113 Savepoint(String),
114
115 /// Release (commit) a savepoint
116 ReleaseSavepoint(String),
117
118 /// Rollback to a savepoint, undoing work since it was created
119 RollbackToSavepoint(String),
120}
121
122impl Transaction {
123 /// Start a transaction with database defaults.
124 pub fn start() -> Self {
125 Self::Start {
126 isolation: None,
127 read_only: false,
128 mode: TransactionMode::Default,
129 }
130 }
131}
132
133impl Operation {
134 /// Returns `true` if this is a [`Transaction::Commit`] operation.
135 pub fn is_transaction_commit(&self) -> bool {
136 matches!(self, Operation::Transaction(Transaction::Commit))
137 }
138}
139
140impl From<Transaction> for Operation {
141 fn from(value: Transaction) -> Self {
142 Self::Transaction(value)
143 }
144}