pub mod defaults;
pub mod utils;
use std::path::{Path, PathBuf};
use rusqlite::{Connection, OpenFlags};
use crate::result::{Error, Result};
use self::utils::APPLEBOOKS_VERSION;
#[derive(Debug, Clone, Copy)]
pub struct ABMacos;
impl ABMacos {
pub fn extract_books<T>(path: &Path) -> Result<Vec<T>>
where
T: ABQuery,
{
Self::query::<T>(path, ABDatabase::Books)
}
pub fn extract_annotations<T>(path: &Path) -> Result<Vec<T>>
where
T: ABQuery,
{
Self::query::<T>(path, ABDatabase::Annotations)
}
#[allow(clippy::missing_panics_doc)]
fn query<T>(path: &Path, database: ABDatabase) -> Result<Vec<T>>
where
T: ABQuery,
{
let path = Self::get_database(path, database)?;
let Ok(connection) = Connection::open_with_flags(&path, OpenFlags::SQLITE_OPEN_READ_ONLY)
else {
return Err(Error::DatabaseConnection {
name: database.to_string(),
path: path.display().to_string(),
});
};
let mut statement = match connection.prepare(T::QUERY) {
Ok(statement) => statement,
Err(error) => {
return Err(Error::UnsupportedMacosVersion {
error: error.to_string(),
version: APPLEBOOKS_VERSION.to_owned(),
});
}
};
let items = statement
.query_map([], |row| Ok(T::from_row(row)))
.unwrap()
.filter_map(std::result::Result::ok)
.collect();
Ok(items)
}
fn get_database(path: &Path, database: ABDatabase) -> Result<PathBuf> {
let path = path.join(database.to_string());
let pattern = format!("{database}*.sqlite");
let pattern = path.join(pattern);
let pattern = pattern.to_string_lossy();
let mut databases: Vec<PathBuf> = glob::glob(&pattern)
.unwrap()
.filter_map(std::result::Result::ok)
.collect();
match &databases[..] {
[_] => Ok(databases.pop().unwrap()),
_ => Err(Error::MissingDefaultDatabase),
}
}
}
pub trait ABQuery {
const QUERY: &'static str;
fn from_row(row: &rusqlite::Row<'_>) -> Self;
}
#[derive(Debug, Clone, Copy)]
pub enum ABDatabase {
Books,
Annotations,
}
impl std::fmt::Display for ABDatabase {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ABDatabase::Books => write!(f, "BKLibrary"),
ABDatabase::Annotations => write!(f, "AEAnnotation"),
}
}
}