1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#[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::<Vec<String>>()
.join("")
}
#[derive(Debug)]
struct TagBase {
conn: Connection,
}
impl TagBase {
/// Instantiate a new `TagBase` whose backing database is at `path`.
fn new(path: &str) -> Result<Self> {
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<i64> {
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);
}
|