1use std::marker::PhantomData;
2use rusqlite::{Connection, params, ToSql, types::FromSql};
3use anyhow::Result;
4
5#[derive(Debug, Clone)]
6pub struct DBMap<K, V> {
7 path: String,
8 key_type: PhantomData<K>,
9 value_type: PhantomData<V>
10}
11
12impl<K, V> DBMap<K, V> {
13 pub fn new(db_path: &str) -> Result<Self> {
14 let conn = Connection::open(db_path)?;
15 conn.execute(
16 "CREATE TABLE IF NOT EXISTS Map (
17 key BLOB PRIMARY KEY,
18 value BLOB
19 )",
20 [],
21 )?;
22 Ok(DBMap {
23 path: db_path.to_string(),
24 key_type: PhantomData,
25 value_type: PhantomData
26 })
27 }
28}
29
30impl<K: ToSql, V: ToSql> DBMap<K, V> {
31 pub fn insert(&self, key: K, value: V) -> Result<()> {
32 let conn = Connection::open(&self.path)?;
33 conn.execute(
34 "INSERT OR REPLACE INTO Map (key, value)
35 VALUES (?1, ?2)",
36 params![key, value]
37 )?;
38 Ok(())
39 }
40}
41
42impl<K: ToSql, V: FromSql> DBMap<K, V> {
43 pub fn get(&self, key: K) -> Result<V> {
44 let conn = Connection::open(&self.path)?;
45 let mut stmt = conn
46 .prepare("SELECT value FROM Map WHERE key = ?1")
47 .unwrap();
48 let value = stmt
49 .query_row([key], |row| {
50 row.get::<usize, V>(0)
51 })?;
52 Ok(value)
53 }
54}
55
56impl<K: FromSql, V: ToSql> DBMap<K, V> {
57 pub fn get_keys(&self, value: V) -> Result<Vec<K>> {
58 let conn = Connection::open(&self.path)?;
59 let mut stmt = conn
60 .prepare("SELECT key FROM Map WHERE value = ?1")
61 .unwrap();
62 let values = stmt
63 .query_map([value], |row| {
64 row.get::<usize, K>(0)
65 })?
66 .collect::<Result<Vec<K>, rusqlite::Error>>()?;
67 Ok(values)
68 }
69}