use std::path::PathBuf;
use rusqlite::{Connection, Row};
use crate::catalog::CatalogVersion;
use crate::content::Content;
use crate::fromdb::FromDb;
use crate::lrobject::{LrId, LrObject};
#[derive(Clone)]
pub struct Folder {
id: LrId,
uuid: String,
pub path_from_root: PathBuf,
pub root_folder: LrId,
pub content: Option<Content>,
}
impl LrObject for Folder {
fn id(&self) -> LrId {
self.id
}
fn uuid(&self) -> &str {
&self.uuid
}
}
impl FromDb for Folder {
fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
Ok(Folder {
id: row.get(0)?,
uuid: row.get(1)?,
path_from_root: PathBuf::from(row.get::<_, String>(2)?),
root_folder: row.get(3)?,
content: None,
})
}
fn read_db_tables(_version: CatalogVersion) -> &'static str {
"AgLibraryFolder"
}
fn read_db_columns(_version: CatalogVersion) -> &'static str {
"id_local,id_global,pathFromRoot,rootFolder"
}
}
impl Folder {
pub fn new(id: LrId, uuid: &str) -> Folder {
Folder {
id,
uuid: String::from(uuid),
path_from_root: PathBuf::from(""),
root_folder: 0,
content: None,
}
}
pub fn read_content(&self, conn: &Connection) -> Content {
Content::from_db(conn, "AgFolderContent", "containingFolder", self.id)
}
}
#[derive(Clone)]
pub struct RootFolder {
id: LrId,
uuid: String,
pub absolute_path: PathBuf,
pub name: String,
pub relative_path_from_catalog: Option<PathBuf>,
}
impl LrObject for RootFolder {
fn id(&self) -> LrId {
self.id
}
fn uuid(&self) -> &str {
&self.uuid
}
}
impl RootFolder {
pub fn new(id: LrId, uuid: &str) -> RootFolder {
RootFolder {
id,
uuid: String::from(uuid),
absolute_path: PathBuf::from(""),
name: String::from(""),
relative_path_from_catalog: None,
}
}
}
impl FromDb for RootFolder {
fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
Ok(RootFolder {
id: row.get(0)?,
uuid: row.get(1)?,
absolute_path: PathBuf::from(row.get::<_, String>(2)?),
name: row.get(3)?,
relative_path_from_catalog: row.get::<_, String>(4).map(PathBuf::from).ok(),
})
}
fn read_db_tables(_version: CatalogVersion) -> &'static str {
"AgLibraryRootFolder"
}
fn read_db_columns(_version: CatalogVersion) -> &'static str {
"id_local,id_global,absolutePath,name,relativePathFromCatalog"
}
}
#[derive(Clone, Default)]
pub struct Folders {
pub roots: Vec<RootFolder>,
pub folders: Vec<Folder>,
}
impl Folders {
pub fn new() -> Folders {
Folders::default()
}
pub fn is_empty(&self) -> bool {
self.roots.is_empty() && self.folders.is_empty()
}
pub fn add_folder(&mut self, folder: Folder) {
self.folders.push(folder);
}
pub fn add_root_folder(&mut self, root_folder: RootFolder) {
self.roots.push(root_folder);
}
pub fn append_folders(&mut self, mut folders: Vec<Folder>) {
self.folders.append(&mut folders);
}
pub fn append_root_folders(&mut self, mut root_folders: Vec<RootFolder>) {
self.roots.append(&mut root_folders);
}
pub fn find_root_folder(&self, id: LrId) -> Option<&RootFolder> {
self.roots.iter().find(|&root| root.id() == id)
}
pub fn resolve_folder_path(&self, folder: &Folder) -> Option<PathBuf> {
let root_folder = self.find_root_folder(folder.root_folder)?;
let mut root_path = root_folder.absolute_path.clone();
root_path.push(&folder.path_from_root);
Some(root_path)
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::{Folder, Folders, RootFolder};
#[test]
fn test_resolve_folder_path() {
let mut folders = Folders::new();
let mut rfolder = RootFolder::new(24, "toplevel");
rfolder.absolute_path = PathBuf::from("/home/hub/Pictures/");
rfolder.name = String::from("Pictures");
folders.add_root_folder(rfolder);
let mut folder = Folder::new(42, "foobar");
folder.root_folder = 24;
folder.path_from_root = PathBuf::from("2017/10/");
folders.add_folder(folder);
let resolved = folders.resolve_folder_path(&folders.folders[0]);
assert!(resolved.is_some());
let resolved = resolved.unwrap();
assert_eq!(resolved, PathBuf::from("/home/hub/Pictures/2017/10/"));
}
}