upend/src/database.rs

123 lines
3.5 KiB
Rust

use crate::models::NewFile;
use actix::prelude::*;
use actix_derive::Message;
use anyhow::Result;
use diesel::prelude::*;
use diesel::r2d2::{self, ConnectionManager};
use diesel::sqlite::SqliteConnection;
use log::debug;
use std::error::Error;
use std::path::Path;
use std::time::Duration;
pub type DbPool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
pub struct DbExecutor(pub DbPool);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
#[derive(Message)]
#[rtype(result = "Result<usize>")]
pub struct InsertFile {
pub file: NewFile,
}
#[derive(Message)]
#[rtype(result = "Result<Option<String>>")]
pub struct RetrieveByHash {
pub hash: String,
}
impl Handler<InsertFile> for DbExecutor {
type Result = Result<usize>;
fn handle(&mut self, msg: InsertFile, _: &mut Self::Context) -> Self::Result {
use crate::schema::files;
let connection = &self.0.get()?;
debug!("Inserting {:?}...", msg.file);
Ok(diesel::insert_into(files::table)
.values(msg.file)
.execute(connection)?)
}
}
impl Handler<RetrieveByHash> for DbExecutor {
type Result = Result<Option<String>>;
fn handle(&mut self, msg: RetrieveByHash, _: &mut Self::Context) -> Self::Result {
use crate::models::File;
use crate::schema::files::dsl::*;
let connection = &self.0.get()?;
let matches = files.filter(hash.eq(msg.hash)).load::<File>(connection)?;
Ok(matches.get(0).map(|f| f.path.clone()))
}
}
#[derive(Debug)]
pub struct ConnectionOptions {
pub enable_foreign_keys: bool,
pub busy_timeout: Option<Duration>,
}
impl ConnectionOptions {
pub fn apply(&self, conn: &SqliteConnection) -> QueryResult<()> {
if self.enable_foreign_keys {
conn.execute("PRAGMA foreign_keys = ON;")?;
}
if let Some(duration) = self.busy_timeout {
conn.execute(&format!("PRAGMA busy_timeout = {};", duration.as_millis()))?;
}
Ok(())
}
}
impl diesel::r2d2::CustomizeConnection<SqliteConnection, diesel::r2d2::Error>
for ConnectionOptions
{
fn on_acquire(&self, conn: &mut SqliteConnection) -> Result<(), diesel::r2d2::Error> {
self.apply(conn).map_err(diesel::r2d2::Error::QueryError)
}
}
pub fn open_upend<P: AsRef<Path>>(dirpath: P) -> Result<DbPool, Box<dyn Error>> {
embed_migrations!("./migrations/upend/");
let database_path = dirpath.as_ref().join("upend.sqlite3");
let manager = ConnectionManager::<SqliteConnection>::new(database_path.to_str().unwrap());
let pool = r2d2::Pool::builder()
.connection_customizer(Box::new(ConnectionOptions {
enable_foreign_keys: true,
busy_timeout: Some(Duration::from_secs(3)),
}))
.build(manager)
.expect("Failed to create pool.");
embedded_migrations::run_with_output(&pool.get().unwrap(), &mut std::io::stdout())?;
Ok(pool)
}
// extern crate xdg;
// pub fn open_config() -> Result<SqliteConnection, Box<dyn Error>> {
// embed_migrations!("./migrations/config/");
// let dirpath = xdg::BaseDirectories::with_prefix("upend")
// .unwrap()
// .place_config_file("config.sqlite3")
// .expect("Could not create config file?!");
// let database_url = dirpath.join("base.sqlite3");
// let connection = SqliteConnection::establish(database_url.to_str().unwrap())?;
// embedded_migrations::run_with_output(&connection, &mut std::io::stdout())?;
// Ok(connection)
// }