db.rs

 1mod kvp;
 2mod migrations;
 3
 4use anyhow::Result;
 5use migrations::MIGRATIONS;
 6use parking_lot::Mutex;
 7use rusqlite::Connection;
 8use std::path::Path;
 9use std::sync::Arc;
10
11pub use kvp::*;
12
13pub struct Db {
14    connecion: Connection,
15    in_memory: bool,
16}
17
18// To make a migration:
19// Add to the migrations directory, a file with the name:
20//  <NUMBER>_<DESCRIPTION>.sql. Migrations are executed in order of number
21
22impl Db {
23    /// Open or create a database at the given file path. Falls back to in memory database if the
24    /// database at the given path is corrupted
25    pub fn open(path: &Path) -> Result<Arc<Mutex<Self>>> {
26        let conn = Connection::open(path)?;
27
28        Self::initialize(conn, false).or_else(|_| Self::open_in_memory())
29    }
30
31    /// Open a in memory database for testing and as a fallback.
32    pub fn open_in_memory() -> Result<Arc<Mutex<Self>>> {
33        let conn = Connection::open_in_memory()?;
34
35        Self::initialize(conn, true)
36    }
37
38    fn initialize(mut conn: Connection, in_memory: bool) -> Result<Arc<Mutex<Self>>> {
39        MIGRATIONS.to_latest(&mut conn)?;
40
41        Ok(Arc::new(Mutex::new(Self {
42            connecion: conn,
43            in_memory,
44        })))
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use tempdir::TempDir;
52
53    #[gpui::test]
54    fn test_db() {
55        let dir = TempDir::new("db-test").unwrap();
56        let fake_db = Db::open_in_memory().unwrap();
57        let real_db = Db::open(&dir.path().join("test.db")).unwrap();
58
59        for db in [&real_db, &fake_db] {
60            assert_eq!(
61                db.read(["key-1", "key-2", "key-3"]).unwrap(),
62                &[None, None, None]
63            );
64
65            db.write([("key-1", "one"), ("key-3", "three")]).unwrap();
66            assert_eq!(
67                db.read(["key-1", "key-2", "key-3"]).unwrap(),
68                &[
69                    Some("one".as_bytes().to_vec()),
70                    None,
71                    Some("three".as_bytes().to_vec())
72                ]
73            );
74
75            db.delete(["key-3", "key-4"]).unwrap();
76            assert_eq!(
77                db.read(["key-1", "key-2", "key-3"]).unwrap(),
78                &[Some("one".as_bytes().to_vec()), None, None,]
79            );
80        }
81
82        drop(real_db);
83
84        let real_db = Db::open(&dir.path().join("test.db")).unwrap();
85        assert_eq!(
86            real_db.read(["key-1", "key-2", "key-3"]).unwrap(),
87            &[Some("one".as_bytes().to_vec()), None, None,]
88        );
89    }
90}