use crate::errors::{AkitaError, Result};
use akita_core::Params;
pub struct SavepointGuard<'a, E: SavepointExecutor> {
executor: &'a mut E,
name: String,
released: bool,
}
impl<'a, E: SavepointExecutor> SavepointGuard<'a, E> {
pub fn new(executor: &'a mut E, name: &str) -> Result<Self> {
executor.create_savepoint(name)?;
Ok(Self {
executor,
name: name.to_string(),
released: false,
})
}
pub fn release(mut self) -> Result<()> {
self.executor.release_savepoint(&self.name)?;
self.released = true;
Ok(())
}
pub fn rollback(mut self) -> Result<()> {
self.executor.rollback_to_savepoint(&self.name)?;
self.released = true;
Ok(())
}
pub fn name(&self) -> &str {
&self.name
}
}
impl<'a, E: SavepointExecutor> Drop for SavepointGuard<'a, E> {
fn drop(&mut self) {
if !self.released {
let _ = self.executor.rollback_to_savepoint(&self.name);
}
}
}
pub trait SavepointExecutor {
fn create_savepoint(&mut self, name: &str) -> Result<()>;
fn release_savepoint(&mut self, name: &str) -> Result<()>;
fn rollback_to_savepoint(&mut self, name: &str) -> Result<()>;
}
pub mod sql {
pub fn create_savepoint(name: &str) -> String {
format!("SAVEPOINT {}", sanitize_name(name))
}
pub fn release_savepoint(name: &str) -> String {
format!("RELEASE SAVEPOINT {}", sanitize_name(name))
}
pub fn rollback_to_savepoint(name: &str) -> String {
format!("ROLLBACK TO SAVEPOINT {}", sanitize_name(name))
}
fn sanitize_name(name: &str) -> String {
let sanitized: String = name
.chars()
.filter(|c| c.is_alphanumeric() || *c == '_')
.collect();
if sanitized.is_empty() {
"sp_default".to_string()
} else {
sanitized
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_savepoint_sql() {
assert_eq!(create_savepoint("sp1"), "SAVEPOINT sp1");
assert_eq!(create_savepoint("my_savepoint"), "SAVEPOINT my_savepoint");
}
#[test]
fn test_release_savepoint_sql() {
assert_eq!(release_savepoint("sp1"), "RELEASE SAVEPOINT sp1");
}
#[test]
fn test_rollback_to_savepoint_sql() {
assert_eq!(rollback_to_savepoint("sp1"), "ROLLBACK TO SAVEPOINT sp1");
}
#[test]
fn test_sanitize_name() {
assert_eq!(sanitize_name("sp1"), "sp1");
assert_eq!(sanitize_name("my_savepoint"), "my_savepoint");
assert_eq!(sanitize_name("sp; DROP TABLE"), "spDROPTABLE");
assert_eq!(sanitize_name(""), "sp_default");
}
}
}