#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum IsolationLevel {
ReadUncommitted,
#[default]
ReadCommitted,
RepeatableRead,
Serializable,
Snapshot,
}
impl IsolationLevel {
#[must_use]
pub fn as_sql(&self) -> &'static str {
match self {
Self::ReadUncommitted => "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED",
Self::ReadCommitted => "SET TRANSACTION ISOLATION LEVEL READ COMMITTED",
Self::RepeatableRead => "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ",
Self::Serializable => "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE",
Self::Snapshot => "SET TRANSACTION ISOLATION LEVEL SNAPSHOT",
}
}
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::ReadUncommitted => "READ UNCOMMITTED",
Self::ReadCommitted => "READ COMMITTED",
Self::RepeatableRead => "REPEATABLE READ",
Self::Serializable => "SERIALIZABLE",
Self::Snapshot => "SNAPSHOT",
}
}
}
#[derive(Debug, Clone)]
#[must_use = "a savepoint should be used to rollback or it has no effect"]
pub struct SavePoint {
pub(crate) name: String,
}
impl SavePoint {
pub(crate) fn new(name: String) -> Self {
Self { name }
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
}
#[must_use = "a transaction must be committed or rolled back"]
pub struct Transaction<'a> {
isolation_level: IsolationLevel,
_marker: std::marker::PhantomData<&'a ()>,
}
impl Transaction<'_> {
#[allow(dead_code)] pub(crate) fn new() -> Self {
Self {
isolation_level: IsolationLevel::default(),
_marker: std::marker::PhantomData,
}
}
#[allow(dead_code)] pub(crate) fn with_isolation_level(level: IsolationLevel) -> Self {
Self {
isolation_level: level,
_marker: std::marker::PhantomData,
}
}
#[must_use]
pub fn isolation_level(&self) -> IsolationLevel {
self.isolation_level
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_isolation_level_sql() {
assert_eq!(
IsolationLevel::ReadCommitted.as_sql(),
"SET TRANSACTION ISOLATION LEVEL READ COMMITTED"
);
assert_eq!(
IsolationLevel::Snapshot.as_sql(),
"SET TRANSACTION ISOLATION LEVEL SNAPSHOT"
);
}
#[test]
fn test_isolation_level_name() {
assert_eq!(IsolationLevel::ReadCommitted.name(), "READ COMMITTED");
assert_eq!(IsolationLevel::Serializable.name(), "SERIALIZABLE");
}
#[test]
fn test_savepoint_name() {
let sp = SavePoint::new("my_savepoint".to_string());
assert_eq!(sp.name(), "my_savepoint");
assert_eq!(sp.name, "my_savepoint");
}
#[test]
fn test_default_isolation_level() {
let level = IsolationLevel::default();
assert_eq!(level, IsolationLevel::ReadCommitted);
}
}