-
Notifications
You must be signed in to change notification settings - Fork 101
/
Copy pathmod.rs
123 lines (106 loc) · 2.87 KB
/
mod.rs
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use anyhow::*;
use diesel::r2d2::{self, ConnectionManager, PooledConnection};
use diesel::sqlite::SqliteConnection;
use diesel::RunQueryDsl;
use diesel_migrations;
use std::path::{Path, PathBuf};
mod schema;
pub use self::schema::*;
#[allow(dead_code)]
const DB_MIGRATIONS_PATH: &str = "migrations";
embed_migrations!("migrations");
#[derive(Clone)]
pub struct DB {
pool: r2d2::Pool<ConnectionManager<SqliteConnection>>,
location: PathBuf,
}
#[derive(Debug)]
struct ConnectionCustomizer {}
impl diesel::r2d2::CustomizeConnection<SqliteConnection, diesel::r2d2::Error>
for ConnectionCustomizer
{
fn on_acquire(&self, connection: &mut SqliteConnection) -> Result<(), diesel::r2d2::Error> {
let query = diesel::sql_query(
r#"
PRAGMA busy_timeout = 60000;
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;
"#,
);
query
.execute(connection)
.map_err(|e| diesel::r2d2::Error::QueryError(e))?;
Ok(())
}
}
impl DB {
pub fn new(path: &Path) -> Result<DB> {
let manager = ConnectionManager::<SqliteConnection>::new(path.to_string_lossy());
let pool = diesel::r2d2::Pool::builder()
.connection_customizer(Box::new(ConnectionCustomizer {}))
.build(manager)?;
let db = DB {
pool: pool,
location: path.to_owned(),
};
db.migrate_up()?;
Ok(db)
}
pub fn location(&self) -> &Path {
&self.location
}
pub fn connect(&self) -> Result<PooledConnection<ConnectionManager<SqliteConnection>>> {
self.pool.get().map_err(Error::new)
}
#[allow(dead_code)]
fn migrate_down(&self) -> Result<()> {
let connection = self.connect().unwrap();
loop {
match diesel_migrations::revert_latest_migration_in_directory(
&connection,
Path::new(DB_MIGRATIONS_PATH),
) {
Ok(_) => (),
Err(diesel_migrations::RunMigrationsError::MigrationError(
diesel_migrations::MigrationError::NoMigrationRun,
)) => break,
Err(e) => bail!(e),
}
}
Ok(())
}
fn migrate_up(&self) -> Result<()> {
let connection = self.connect().unwrap();
embedded_migrations::run(&connection)?;
Ok(())
}
}
#[cfg(test)]
pub fn get_test_db(name: &str) -> DB {
use crate::app::{config, user};
let config_path = Path::new("test-data/config.toml");
let config = config::Config::from_path(&config_path).unwrap();
let mut db_path = std::path::PathBuf::new();
db_path.push("test-output");
std::fs::create_dir_all(&db_path).unwrap();
db_path.push(name);
if db_path.exists() {
std::fs::remove_file(&db_path).unwrap();
}
let db = DB::new(&db_path).unwrap();
let user_manager = user::Manager::new(db.clone());
let config_manager = config::Manager::new(db.clone(), user_manager);
config_manager.amend(&config).unwrap();
db
}
#[test]
fn test_migrations_up() {
get_test_db("migrations_up.sqlite");
}
#[test]
fn test_migrations_down() {
let db = get_test_db("migrations_down.sqlite");
db.migrate_down().unwrap();
db.migrate_up().unwrap();
}