aboutsummaryrefslogtreecommitdiff
path: root/src/database.rs
blob: de77f950e09ea92f8a20b2f470ab1168dc9a88d1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use anyhow::Result;
use rusqlite::{Connection, Transaction, config::DbConfig};

pub const DB_NAME: &str = "database.sqlite";
const DB_VERSION: i64 = 0;

pub struct Database {
    conn: Connection,
}

impl Database {
    pub fn new(db_file: &str) -> Result<Self> {
        let mut init = false;
        if !std::fs::exists(db_file)? {
            init = true;
        }

        let mut db = Database {
            conn: Connection::open(db_file)?,
        };
        if init {
            db.initialize()?;
        }

        db.conn.db_config(DbConfig::SQLITE_DBCONFIG_ENABLE_FKEY)?;

        Ok(db)
    }

    fn initialize(&mut self) -> Result<()> {
        let tx = self.conn.transaction()?;
        let mut q = "CREATE TABLE version (
            version INTEGER NOT NULL,
            UNIQUE (version))";
        tx.execute(q, ())?;

        q = "INSERT INTO version VALUES (?)";
        tx.execute(q, [&DB_VERSION])?;

        q = "CREATE TABLE user (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT,
            email TEXT NOT NULL,
            UNIQUE (email))";
        tx.execute(q, ())?;

        q = "CREATE TABLE list (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            description TEXT,
            UNIQUE (name))";
        tx.execute(q, ())?;

        q = "CREATE TABLE subscription (
            user_id INTEGER REFERENCES user (id),
            list_id INTEGER REFERENCES list (id),
            UNIQUE (user_id, list_id))";
        tx.execute(q, ())?;

        tx.commit()?;
        Ok(())
    }

    pub fn execute<Ex>(&mut self, q: Ex) -> Result<QueryResult<Ex::T>>
    where
        Ex: DBExecutable,
    {
        let tx = self.conn.transaction()?;
        let ris = q.execute(&tx)?;
        tx.commit()?;
        Ok(ris)
    }
}

pub trait DBExecutable {
    type T;
    fn execute(&self, tx: &Transaction) -> Result<QueryResult<Self::T>>;
}

#[derive(Debug)]
pub enum QueryResult<T> {
    Empty,
    Vec(Vec<T>),
}
XMR address: 854DmXNrxULU3ZFJVs4Wc8PFhbq29RhqHhY8W6cdWrtFN3qmooKyyeYPcDzZTNRxphhJ5UzASQfAdEMwSteVqymk28aLhqj