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}