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
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
// imports

// [[file:~/Workspace/Programming/gosh-rs/database/database.note::*imports][imports:1]]
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate diesel_migrations;

use std::sync::{Arc, Mutex, MutexGuard};

use diesel::prelude::*;
// imports:1 ends here

// mods

// [[file:~/Workspace/Programming/gosh-rs/database/database.note::*mods][mods:1]]
mod checkpoint;
mod collection;
mod core;

pub mod prelude {
    pub use crate::checkpoint::*;
    pub use crate::collection::*;
}

pub(crate) mod schema;
// mods:1 ends here

// base

// [[file:~/Workspace/Programming/gosh-rs/database/database.note::*base][base:1]]
use gosh_core::*;

use gut::prelude::*;

embed_migrations!();

#[derive(Clone)]
pub struct DbConnection {
    database_url: String,
    connection: Arc<Mutex<SqliteConnection>>,
}

impl DbConnection {
    /// Eastablish connection to database specified using env var
    /// `GOSH_DATABASE_URL`.
    pub fn establish() -> Result<DbConnection> {
        // read vars from .env file
        dotenv::dotenv().ok();

        let database_url = std::env::var("GOSH_DATABASE_URL")
            .with_context(|| format!("GOSH_DATABASE_URL var not set"))?;
        debug!("Database: {}", database_url);

        Self::connect(&database_url)
    }

    /// Connect to database specified using `database_url`.
    pub fn connect(database_url: &str) -> Result<DbConnection> {
        // diesel accept &str, not Path
        let conn = SqliteConnection::establish(database_url)?;

        // see: https://sqlite.org/faq.html#q19
        //
        // With synchronous OFF, SQLite continues without syncing as soon as
        // it has handed data off to the operating system. If the application
        // running SQLite crashes, the data will be safe, but the database might
        // become corrupted if the operating system crashes or the computer
        // loses power before that data has been written to the disk surface. On
        // the other hand, commits can be orders of magnitude faster with
        // synchronous OFF.
        conn.execute("PRAGMA synchronous = OFF")?;

        let conn = Arc::new(Mutex::new(conn));

        let db = DbConnection {
            database_url: database_url.into(),
            connection: conn.clone(),
        };

        db.migrate()?;

        Ok(db)
    }

    /// Show database url.
    pub fn database_url(&self) -> &str {
        &self.database_url
    }

    pub(crate) fn get(&self) -> MutexGuard<'_, SqliteConnection> {
        self.connection.lock().expect("cannot lock db connection!")
    }

    // for schema migrations, sql tables initialization
    fn migrate(&self) -> Result<()> {
        let conn = self.get();

        // This will run the necessary migrations.
        embedded_migrations::run(&*conn)?;

        Ok(())
    }
}
// base:1 ends here