#[macro_use]
extern crate diesel;
mod models;
mod reader;
mod schema;
mod serialization;
mod writer;
use std::{
fmt::{Debug, Formatter},
fs::create_dir_all,
path::Path,
sync::{Arc, Mutex},
};
use diesel::{Connection, RunQueryDsl, SqliteConnection, sql_query};
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};
use tari_ootle_wallet_sdk::storage::{ReadableWalletStore, WalletStorageError, WriteableWalletStore};
use crate::{reader::ReadTransaction, writer::WriteTransaction};
#[derive(Clone)]
pub struct SqliteWalletStore {
connection: Arc<Mutex<SqliteConnection>>,
}
impl SqliteWalletStore {
pub fn try_open<P: AsRef<Path>>(path: P) -> Result<Self, WalletStorageError> {
create_dir_all(path.as_ref().parent().unwrap()).expect("Failed to create DB path");
let database_url = path.as_ref().to_str().expect("database_url utf-8 error").to_string();
let mut connection =
SqliteConnection::establish(&database_url).map_err(|e| WalletStorageError::general("connect", e))?;
sql_query("PRAGMA foreign_keys = ON;")
.execute(&mut connection)
.map_err(|source| WalletStorageError::general("set pragma", source))?;
Ok(Self {
connection: Arc::new(Mutex::new(connection)),
})
}
pub fn run_migrations(&self) -> Result<(), WalletStorageError> {
let mut conn = self.connection.lock().unwrap();
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations");
conn.run_pending_migrations(MIGRATIONS)
.map_err(|source| WalletStorageError::general("migrate", source))?;
Ok(())
}
}
impl ReadableWalletStore for SqliteWalletStore {
type ReadTransaction<'a> = ReadTransaction<'a>;
fn create_read_tx(&self) -> Result<Self::ReadTransaction<'_>, WalletStorageError> {
let mut lock = self.connection.lock().unwrap();
sql_query("BEGIN")
.execute(&mut *lock)
.map_err(|e| WalletStorageError::general("BEGIN transaction", e))?;
Ok(ReadTransaction::new(lock))
}
}
impl WriteableWalletStore for SqliteWalletStore {
type WriteTransaction<'a> = WriteTransaction<'a>;
fn create_write_tx(&self) -> Result<Self::WriteTransaction<'_>, WalletStorageError> {
let mut lock = self.connection.lock().unwrap();
sql_query("BEGIN")
.execute(&mut *lock)
.map_err(|e| WalletStorageError::general("BEGIN transaction", e))?;
Ok(WriteTransaction::new(lock))
}
}
impl Debug for SqliteWalletStore {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SqliteWalletStore")
.field("connection", &"SqliteConnection")
.finish()
}
}