#[macro_use] extern crate anyhow; use anyhow::Result; use blake2::{Blake2b, Digest}; use rusqlite::{params, Connection}; use std::io; use std::path::Path; /// Return a hex-encoded string representing the contents of `hash`. fn hexlify(hash: &[u8]) -> String { hash.iter() .map(|b| format!("{:x}", b)) .collect::>() .join("") } #[derive(Debug)] struct TagBase { conn: Connection, } impl TagBase { /// Instantiate a new `TagBase` whose backing database is at `path`. fn new(path: &str) -> Result { let conn = Connection::open(path)?; conn.execute( "CREATE TABLE IF NOT EXISTS images ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, blake2 TEXT NOT NULL, filename TEXT NOT NULL, orig_dir TEXT NOT NULL )", params![], )?; conn.execute( "CREATE TABLE IF NOT EXISTS tags ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL )", params![], )?; conn.execute( "CREATE TABLE IF NOT EXISTS mapping ( image INTEGER NOT NULL, tag INTEGER NOT NULL )", params![], )?; Ok(TagBase { conn }) } /// Insert the image at `path` into the data. fn import_image(&self, path: &Path) -> Result { if path.is_dir() { bail!("`path` does not name a file."); } let mut file = std::fs::File::open(path)?; let mut hasher = Blake2b::new(); let _ = io::copy(&mut file, &mut hasher)?; let hash = base64::encode(&hasher.result()); let file_name = path .file_name() .and_then(|os| os.to_str()) .ok_or(anyhow!("Couldn't parse file name."))?; let path = path.to_str().ok_or(anyhow!("Couldn't parse path."))?; let split_index = path.len() - file_name.len(); let parent_directory = &path[0..split_index]; let id = self .conn .prepare("INSERT INTO images (blake2, filename, orig_dir) VALUES(?,?,?)")? .insert(params![hash, file_name, parent_directory])?; Ok(id) } /// Insert `tag` into the database, if it does not already exist. fn add_tag(&self, tag: &str) -> Result<()> { let exists = self .conn .prepare("SELECT * FROM tags WHERE name = ?")? .exists(params![tag]); if let Err(_) = exists { self.conn .execute("INSERT INTO tags (name) VALUES(?)", params![tag])?; } Ok(()) } } fn main() { let tb = TagBase::new("/tmp/test.db").unwrap(); tb.import_image(Path::new("/home/jakob/Sync/06fc9ae71549eb4d.jpeg")) .unwrap(); println!("{:?}", tb); }