2020-10-24 13:46:06 +00:00
|
|
|
use crate::db::errors::{DataError, MigrationError};
|
|
|
|
use crate::db::migrations::{get_migration_version, Migrations};
|
2020-10-24 13:08:23 +00:00
|
|
|
use crate::db::variables::Variables;
|
2020-10-24 13:46:06 +00:00
|
|
|
use log::info;
|
2020-11-03 20:14:15 +00:00
|
|
|
use sled::{Config, Db};
|
2020-10-23 20:19:04 +00:00
|
|
|
use std::path::Path;
|
2020-10-15 16:52:08 +00:00
|
|
|
|
2020-10-24 13:46:06 +00:00
|
|
|
pub mod data_migrations;
|
2020-10-24 13:08:23 +00:00
|
|
|
pub mod errors;
|
2020-10-24 13:46:06 +00:00
|
|
|
pub mod migrations;
|
2020-10-24 13:08:23 +00:00
|
|
|
pub mod schema;
|
|
|
|
pub mod variables;
|
2020-10-20 20:54:20 +00:00
|
|
|
|
2020-10-15 16:52:08 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Database {
|
|
|
|
db: Db,
|
2020-10-24 13:08:23 +00:00
|
|
|
pub(crate) variables: Variables,
|
2020-10-24 13:46:06 +00:00
|
|
|
pub(crate) migrations: Migrations,
|
2020-10-20 20:54:20 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 16:52:08 +00:00
|
|
|
impl Database {
|
2020-11-03 20:14:15 +00:00
|
|
|
fn new_db(db: sled::Db) -> Result<Database, DataError> {
|
2020-10-24 13:46:06 +00:00
|
|
|
let migrations = db.open_tree("migrations")?;
|
2020-10-18 15:13:34 +00:00
|
|
|
|
|
|
|
Ok(Database {
|
|
|
|
db: db.clone(),
|
2020-11-03 20:14:15 +00:00
|
|
|
variables: Variables::new(&db)?,
|
2020-10-24 13:46:06 +00:00
|
|
|
migrations: Migrations(migrations),
|
2020-10-18 15:13:34 +00:00
|
|
|
})
|
2020-10-15 16:52:08 +00:00
|
|
|
}
|
2020-10-24 13:46:06 +00:00
|
|
|
|
2020-11-03 20:14:15 +00:00
|
|
|
pub fn new<P: AsRef<Path>>(path: P) -> Result<Database, DataError> {
|
|
|
|
let db = sled::open(path)?;
|
|
|
|
Self::new_db(db)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_temp() -> Result<Database, DataError> {
|
|
|
|
let config = Config::new().temporary(true);
|
|
|
|
let db = config.open()?;
|
|
|
|
Self::new_db(db)
|
|
|
|
}
|
|
|
|
|
2020-10-24 13:46:06 +00:00
|
|
|
pub fn migrate(&self, to_version: u32) -> Result<(), DataError> {
|
|
|
|
//get version from db
|
|
|
|
let db_version = get_migration_version(&self)?;
|
|
|
|
|
|
|
|
if db_version < to_version {
|
|
|
|
info!(
|
|
|
|
"Migrating database from version {} to version {}",
|
|
|
|
db_version, to_version
|
|
|
|
);
|
|
|
|
//if db version < to_version, proceed
|
|
|
|
//produce range of db_version+1 .. to_version (inclusive)
|
|
|
|
let versions_to_run: Vec<u32> = ((db_version + 1)..=to_version).collect();
|
|
|
|
let migrations = data_migrations::get_migrations(&versions_to_run)?;
|
|
|
|
|
|
|
|
//execute each closure.
|
2020-10-30 21:48:52 +00:00
|
|
|
for (version, migration) in versions_to_run.iter().zip(migrations) {
|
|
|
|
let (migration_func, name) = migration;
|
2020-10-24 13:46:06 +00:00
|
|
|
//This needs to be transactional on migrations
|
|
|
|
//keyspace. abort on migration func error.
|
|
|
|
|
2020-10-30 21:48:52 +00:00
|
|
|
info!("Applying migration {} :: {}", version, name);
|
2020-10-24 13:46:06 +00:00
|
|
|
match migration_func(&self) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}?;
|
|
|
|
|
|
|
|
self.migrations.set_migration_version(*version)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("Done applying migrations.");
|
|
|
|
Ok(())
|
|
|
|
} else if db_version > to_version {
|
|
|
|
//if db version > to_version, cannot downgrade error
|
|
|
|
Err(MigrationError::CannotDowngrade.into())
|
|
|
|
} else {
|
|
|
|
//if db version == to_version, do nothing
|
|
|
|
info!("No database migrations needed.");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2020-10-15 16:52:08 +00:00
|
|
|
}
|