use std::path::Path;
use super::archive::Archive;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TransactionBehavior {
Deferred,
Immediate,
Exclusive,
}
impl TransactionBehavior {
fn inner(self) -> rusqlite::TransactionBehavior {
match self {
TransactionBehavior::Deferred => rusqlite::TransactionBehavior::Deferred,
TransactionBehavior::Immediate => rusqlite::TransactionBehavior::Immediate,
TransactionBehavior::Exclusive => rusqlite::TransactionBehavior::Exclusive,
}
}
}
#[derive(Debug)]
pub struct Connection {
conn: rusqlite::Connection,
}
impl Connection {
pub(super) fn new(conn: rusqlite::Connection) -> Self {
Self { conn }
}
pub fn open<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
use rusqlite::OpenFlags;
let flags = OpenFlags::SQLITE_OPEN_NO_MUTEX | OpenFlags::SQLITE_OPEN_READ_WRITE;
let mut conn = Connection::new(rusqlite::Connection::open_with_flags(path, flags)?);
conn.exec(|archive| archive.init(false))?;
Ok(conn)
}
pub fn create<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
use rusqlite::OpenFlags;
let flags = OpenFlags::SQLITE_OPEN_NO_MUTEX
| OpenFlags::SQLITE_OPEN_READ_WRITE
| OpenFlags::SQLITE_OPEN_CREATE;
let mut conn = Connection::new(rusqlite::Connection::open_with_flags(path, flags)?);
conn.exec(|archive| archive.init(false))?;
Ok(conn)
}
pub fn create_new<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
use rusqlite::OpenFlags;
let flags = OpenFlags::SQLITE_OPEN_NO_MUTEX
| OpenFlags::SQLITE_OPEN_READ_WRITE
| OpenFlags::SQLITE_OPEN_CREATE;
let mut conn = Connection::new(rusqlite::Connection::open_with_flags(path, flags)?);
conn.exec(|archive| archive.init(true))?;
Ok(conn)
}
pub fn open_readonly<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
use rusqlite::OpenFlags;
let flags = OpenFlags::SQLITE_OPEN_NO_MUTEX | OpenFlags::SQLITE_OPEN_READ_ONLY;
let mut conn = Connection::new(rusqlite::Connection::open_with_flags(path, flags)?);
conn.exec(|archive| archive.init(false))?;
Ok(conn)
}
pub fn open_in_memory() -> crate::Result<Self> {
let mut conn = Self::new(rusqlite::Connection::open_in_memory()?);
conn.exec(|archive| archive.init(true))?;
Ok(conn)
}
pub fn transaction(&mut self) -> crate::Result<Transaction> {
Ok(Transaction::new(self.conn.transaction()?))
}
pub fn transaction_with(
&mut self,
behavior: TransactionBehavior,
) -> crate::Result<Transaction> {
Ok(Transaction::new(
self.conn.transaction_with_behavior(behavior.inner())?,
))
}
pub fn exec<T, E, F>(&mut self, f: F) -> Result<T, E>
where
F: FnOnce(&mut Archive) -> Result<T, E>,
E: From<crate::Error>,
{
self.transaction()?.exec(f)
}
pub fn exec_with<T, E, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T, E>
where
F: FnOnce(&mut Archive) -> Result<T, E>,
E: From<crate::Error>,
{
self.transaction_with(behavior)?.exec(f)
}
}
#[derive(Debug)]
pub struct Transaction<'conn> {
archive: Archive<'conn>,
}
impl<'conn> Transaction<'conn> {
pub(super) fn new(tx: rusqlite::Transaction<'conn>) -> Self {
Self {
archive: Archive::new(tx),
}
}
pub fn exec<T, E, F>(mut self, f: F) -> Result<T, E>
where
F: FnOnce(&mut Archive) -> Result<T, E>,
E: From<crate::Error>,
{
let result = f(&mut self.archive)?;
self.archive
.into_tx()
.commit()
.map_err(crate::Error::from)?;
Ok(result)
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn archive(&self) -> &Archive<'conn> {
&self.archive
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn archive_mut(&mut self) -> &mut Archive<'conn> {
&mut self.archive
}
pub fn rollback(self) -> crate::Result<()> {
Ok(self.archive.into_tx().rollback()?)
}
pub fn commit(self) -> crate::Result<()> {
Ok(self.archive.into_tx().commit()?)
}
}