db.rs

 1mod kvp;
 2mod migrations;
 3
 4use std::path::Path;
 5use std::sync::Arc;
 6
 7use anyhow::Result;
 8use log::error;
 9use parking_lot::Mutex;
10use rusqlite::Connection;
11
12use migrations::MIGRATIONS;
13
14pub enum Db {
15    Real {
16        connection: Mutex<Connection>,
17        in_memory: bool,
18    },
19    Null,
20}
21
22// To make a migration:
23// Add to the migrations directory, a file with the name:
24//  <NUMBER>_<DESCRIPTION>.sql. Migrations are executed in order of number
25
26impl Db {
27    /// Open or create a database at the given file path. Falls back to in memory database if the
28    /// database at the given path is corrupted
29    pub fn open(path: &Path) -> Arc<Self> {
30        Connection::open(path)
31            .map_err(Into::into)
32            .and_then(|connection| Self::initialize(connection, false))
33            .unwrap_or_else(|e| {
34                error!(
35                    "Connecting to db failed. Falling back to in memory db. {}",
36                    e
37                );
38                Self::open_in_memory()
39            })
40    }
41
42    /// Open a in memory database for testing and as a fallback.
43    pub fn open_in_memory() -> Arc<Self> {
44        Connection::open_in_memory()
45            .map_err(Into::into)
46            .and_then(|connection| Self::initialize(connection, true))
47            .unwrap_or_else(|e| {
48                error!("Connecting to in memory db failed. Reverting to null db. {}");
49                Arc::new(Self::Null)
50            })
51    }
52
53    fn initialize(mut conn: Connection, in_memory: bool) -> Result<Arc<Self>> {
54        MIGRATIONS.to_latest(&mut conn)?;
55
56        Ok(Arc::new(Self::Real {
57            connection: Mutex::new(conn),
58            in_memory,
59        }))
60    }
61
62    fn persisting(&self) -> bool {
63        match self {
64            Db::Real { in_memory, .. } => *in_memory,
65            _ => false,
66        }
67    }
68}