use crate::{
alias::AliasList,
error::{WHError, WHResult},
};
use sqlite::{Connection, State};
pub struct Database {
connection: Connection,
}
impl Database {
pub fn new(path: &str) -> WHResult<Database> {
let connection = Connection::open(path);
match connection {
Ok(connection) => Ok(Database { connection }),
Err(_) => Err(WHError::DatabaseConnectionError(path.to_string())),
}
}
pub fn init(&self) {
self.connection
.execute(
"create table if not exists aliases (
id integer primary key,
alias text not null,
path text not null,
unique(alias)
)",
)
.unwrap();
}
fn run_statement<T: sqlite::Bindable>(&self, query: &str, bind: T) -> sqlite::Statement {
let mut statement = self.connection.prepare(query).unwrap();
statement.bind::<T>(bind).unwrap();
statement
}
fn run_querry(&self, query: &str) -> sqlite::Statement {
self.connection.prepare(query).unwrap()
}
pub fn add_alias(&self, alias: &str, path: &str) -> WHResult<()> {
let mut statement = self.run_statement::<&[(&str, &str)]>(
"insert into aliases (alias, path) values (:alias, :path)",
&[(":alias", alias), (":path", path)],
);
match statement.next() {
Ok(_) => Ok(()),
Err(_) => Err(WHError::AliasAlreadyExists(alias.to_string())),
}
}
pub fn edit_alias(&self, alias: &str, paths: &str) -> WHResult<()> {
self.get_alias(alias)?; let mut statement = self.run_statement::<&[(&str, &str)]>(
"update aliases set path = :path where alias = :alias",
&[(":alias", alias), (":path", paths)],
);
statement.next().unwrap();
Ok(())
}
pub fn rename_alias(&self, old_alias: &str, new_alias: &str) -> WHResult<()> {
self.get_alias(old_alias)?; let mut statement = self.run_statement::<&[(&str, &str)]>(
"update aliases set alias = :new_alias where alias = :old_alias",
&[(":old_alias", old_alias), (":new_alias", new_alias)],
);
match statement.next() {
Ok(_) => Ok(()),
Err(_) => Err(WHError::AliasAlreadyExists(new_alias.to_string())),
}
}
pub fn remove_alias(&self, alias: &str) -> WHResult<()> {
let mut statement = self.run_statement::<(&str, &str)>("delete from aliases where alias = :alias", (":alias", alias));
statement.next().unwrap();
Ok(())
}
pub fn get_all_aliases(&self) -> WHResult<AliasList> {
let mut statement = self.run_querry("select alias, path from aliases order by alias");
let mut aliases = AliasList::new();
while let Ok(State::Row) = statement.next() {
aliases.add(
(
statement.read::<String, _>("alias").unwrap(),
statement.read::<String, _>("path").unwrap(),
)
.into(),
);
}
Ok(aliases)
}
pub fn get_alias(&self, alias: &str) -> WHResult<String> {
let mut statement = self.run_statement::<(&str, &str)>("select path from aliases where alias = :alias", (":alias", alias));
if let Ok(State::Row) = statement.next() {
Ok(statement.read::<String, _>("path").unwrap())
} else {
Err(WHError::AliasNotFound(alias.to_string()))
}
}
pub fn get_aliases_matching(&self, pattern: &str) -> WHResult<AliasList> {
let mut statement = self.run_statement::<(&str, &str)>(
"select alias, path from aliases where path like :pattern order by alias",
(":pattern", pattern),
);
let mut aliases = AliasList::new();
if let Ok(State::Done) = statement.next() {
return Err(WHError::PatternNotMatch(pattern.to_string()));
}
let _ = statement.reset();
while let Ok(State::Row) = statement.next() {
aliases.add(
(
statement.read::<String, _>("alias").unwrap(),
statement.read::<String, _>("path").unwrap(),
)
.into(),
);
}
Ok(aliases)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::remove_file;
#[test]
fn test_database() {
let path = ".db_test.db";
if std::path::Path::new(path).exists() {
remove_file(path).unwrap();
}
let database = Database::new(path).unwrap();
database.init();
database.add_alias("alias", "path").unwrap();
assert_eq!(database.get_alias("alias").unwrap(), "path");
database.edit_alias("alias", "new_path").unwrap();
assert_eq!(database.get_alias("alias").unwrap(), "new_path");
database.rename_alias("alias", "new_alias").unwrap();
assert_eq!(database.get_alias("new_alias").unwrap(), "new_path");
database.add_alias("alias2", "path2").unwrap();
let aliases = database.get_all_aliases().unwrap();
assert_eq!(format!("{}", aliases), "alias2 -> path2\nnew_alias -> new_path\n");
let aliases = database.get_aliases_matching("new%").unwrap();
assert_eq!(format!("{}", aliases), "new_alias -> new_path\n");
database.remove_alias("new_alias").unwrap();
assert!(database.get_alias("new_alias").is_err());
}
}