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}