Added forced migration option
ci/woodpecker/push/woodpecker Pipeline was successful Details

+ Useful when u h*ck up like me
main
Joey Hines 2022-01-06 19:26:14 -07:00
parent 51d6ffb7be
commit 99cb470e6e
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
10 changed files with 44 additions and 22 deletions

View File

@ -103,6 +103,7 @@ mod test {
use crate::commands::Command; use crate::commands::Command;
use crate::config::GeoffreyAPIConfig; use crate::config::GeoffreyAPIConfig;
use crate::context::Context; use crate::context::Context;
use crate::Args;
use geoffrey_models::models::item::ItemListing; use geoffrey_models::models::item::ItemListing;
use geoffrey_models::models::locations::shop::Shop; use geoffrey_models::models::locations::shop::Shop;
use geoffrey_models::models::locations::{LocationDataDb, LocationDb}; use geoffrey_models::models::locations::{LocationDataDb, LocationDb};
@ -118,7 +119,7 @@ mod test {
max_str_len: 64, max_str_len: 64,
}; };
let ctx = Context::new(config.clone()).unwrap(); let ctx = Context::new(config.clone(), Args::default()).unwrap();
let mut shop_data = Shop::default(); let mut shop_data = Shop::default();

View File

@ -1,5 +1,5 @@
use crate::config::GeoffreyAPIConfig; use crate::config::GeoffreyAPIConfig;
use crate::Result; use crate::{Args, Result};
use geoffrey_db::database::Database; use geoffrey_db::database::Database;
use std::sync::Arc; use std::sync::Arc;
@ -9,9 +9,9 @@ pub struct Context {
} }
impl Context { impl Context {
pub fn new(cfg: GeoffreyAPIConfig) -> Result<Arc<Self>> { pub fn new(cfg: GeoffreyAPIConfig, args: Args) -> Result<Arc<Self>> {
let ctx = Self { let ctx = Self {
db: Database::new(cfg.db_path.as_path()).unwrap(), db: Database::new(cfg.db_path.as_path(), args.force_migration).unwrap(),
cfg, cfg,
}; };

View File

@ -25,9 +25,9 @@ mod logging;
pub type Result<T> = std::result::Result<T, GeoffreyAPIError>; pub type Result<T> = std::result::Result<T, GeoffreyAPIError>;
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone, Default)]
#[structopt(name = "GeoffreyAPI", about = "Geoffrey Central API")] #[structopt(name = "GeoffreyAPI", about = "Geoffrey Central API")]
struct Args { pub struct Args {
#[structopt(env = "GEOFFREY_CONFIG", parse(from_os_str))] #[structopt(env = "GEOFFREY_CONFIG", parse(from_os_str))]
config: PathBuf, config: PathBuf,
#[structopt( #[structopt(
@ -39,18 +39,27 @@ struct Args {
)] )]
log_level: LogLevel, log_level: LogLevel,
#[structopt(short, long)]
force_migration: bool,
#[structopt(subcommand)] #[structopt(subcommand)]
command: GeoffreyApiCommand, command: GeoffreyApiCommand,
} }
#[derive(Debug, PartialEq, StructOpt, Clone)] #[derive(Debug, PartialEq, StructOpt, Clone)]
enum GeoffreyApiCommand { pub enum GeoffreyApiCommand {
Run, Run,
CreateAdminToken(CreateTokenCommand), CreateAdminToken(CreateTokenCommand),
} }
impl Default for GeoffreyApiCommand {
fn default() -> Self {
Self::Run
}
}
#[derive(Debug, StructOpt, PartialEq, Clone)] #[derive(Debug, StructOpt, PartialEq, Clone)]
struct CreateTokenCommand { pub struct CreateTokenCommand {
#[structopt(parse(try_from_str = Permissions::try_from))] #[structopt(parse(try_from_str = Permissions::try_from))]
pub permissions: Vec<Permissions>, pub permissions: Vec<Permissions>,
} }
@ -98,7 +107,7 @@ async fn main() {
} }
}; };
let ctx = Context::new(cfg).unwrap(); let ctx = Context::new(cfg, args.clone()).unwrap();
match args.command { match args.command {
GeoffreyApiCommand::Run => run_server(ctx).await, GeoffreyApiCommand::Run => run_server(ctx).await,

View File

@ -24,9 +24,14 @@ pub struct Database {
} }
impl Database { impl Database {
pub fn new(db_path: &Path) -> Result<Self> { pub fn new(db_path: &Path, force_migration: bool) -> Result<Self> {
let db = sled::open(db_path)?; let db = sled::open(db_path)?;
let db = Self { db }; let mut db = Self { db };
let ver = db.version().unwrap_or(0);
if force_migration && ver > 0 {
db.set_version(ver - 1)?;
}
do_migration(&db, DB_VERSION)?; do_migration(&db, DB_VERSION)?;
@ -168,7 +173,7 @@ impl Database {
} }
pub(crate) fn set_version(&mut self, version: u64) -> Result<()> { pub(crate) fn set_version(&mut self, version: u64) -> Result<()> {
let mut md = self.get::<DBMetadata>(0)?; let mut md = self.get::<DBMetadata>(DB_METADATA_ID)?;
md.version = version; md.version = version;

View File

@ -16,7 +16,7 @@ mod test {
use std::sync::Mutex; use std::sync::Mutex;
lazy_static! { lazy_static! {
pub static ref DB: Database = Database::new(Path::new("../test_database")).unwrap(); pub static ref DB: Database = Database::new(Path::new("../test_database"), false).unwrap();
pub static ref LOCK: Mutex<()> = Mutex::default(); pub static ref LOCK: Mutex<()> = Mutex::default();
} }

View File

@ -63,7 +63,7 @@ mod tests {
#[test] #[test]
fn test_migration_2() { fn test_migration_2() {
let db = Database::new(Path::new("../migration_2_db/")).unwrap(); let db = Database::new(Path::new("../migration_2_db/"), false).unwrap();
let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap(); let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap();

View File

@ -57,7 +57,7 @@ mod tests {
#[test] #[test]
fn test_migration_3() { fn test_migration_3() {
let db = Database::new(Path::new("../migration_3_db/")).unwrap(); let db = Database::new(Path::new("../migration_3_db/"), false).unwrap();
let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap(); let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap();

View File

@ -13,7 +13,7 @@ impl Migration for OutOfStockVoting {
let (id, loc_ivec) = entry?; let (id, loc_ivec) = entry?;
let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap(); let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap();
if !loc["loc_data"]["shop"].is_empty() { if !loc["loc_data"]["Shop"].is_empty() {
for item in loc["loc_data"]["Shop"]["item_listings"].members_mut() { for item in loc["loc_data"]["Shop"]["item_listings"].members_mut() {
item["out_of_stock_votes"] = json::JsonValue::Array(Vec::new()); item["out_of_stock_votes"] = json::JsonValue::Array(Vec::new());
} }
@ -32,7 +32,7 @@ impl Migration for OutOfStockVoting {
let (id, loc_ivec) = entry?; let (id, loc_ivec) = entry?;
let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap(); let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap();
if !loc["loc_data"]["shop"].is_empty() { if !loc["loc_data"]["Shop"].is_empty() {
for item in &mut loc["loc_data"]["Shop"]["item_listings"].members_mut() { for item in &mut loc["loc_data"]["Shop"]["item_listings"].members_mut() {
item["out_of_stock_votes"].clear() item["out_of_stock_votes"].clear()
} }
@ -61,7 +61,7 @@ mod tests {
#[test] #[test]
fn test_migration_4() { fn test_migration_4() {
let db = Database::new(Path::new("../migration_4_db/")).unwrap(); let db = Database::new(Path::new("../migration_4_db/"), false).unwrap();
let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap(); let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap();
@ -130,7 +130,8 @@ mod tests {
let new_loc = json::parse(std::str::from_utf8(&new_loc).unwrap()).unwrap(); let new_loc = json::parse(std::str::from_utf8(&new_loc).unwrap()).unwrap();
assert_eq!(new_loc["loc_data"]["Shop"]["out_of_stock_votes"].len(), 0); println!("{}", new_loc);
assert!(new_loc["loc_data"]["Shop"]["item_listings"][0]["out_of_stock_votes"].is_array());
drop(db); drop(db);

View File

@ -15,7 +15,7 @@ trait Migration {
fn version() -> u64; fn version() -> u64;
} }
fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> { pub(crate) fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> {
for ver in current_version + 1..=target_version { for ver in current_version + 1..=target_version {
match ver { match ver {
2 => PosAndNetherMigration::up(db)?, 2 => PosAndNetherMigration::up(db)?,
@ -28,7 +28,7 @@ fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<(
Ok(()) Ok(())
} }
fn downgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> { pub(crate) fn downgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> {
for ver in (target_version..current_version).rev() { for ver in (target_version..current_version).rev() {
match ver { match ver {
2 => PosAndNetherMigration::down(db)?, 2 => PosAndNetherMigration::down(db)?,

View File

@ -1,7 +1,7 @@
use log::LevelFilter; use log::LevelFilter;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug, Copy)]
pub enum LogLevel { pub enum LogLevel {
None, None,
Warn, Warn,
@ -9,6 +9,12 @@ pub enum LogLevel {
Debug, Debug,
} }
impl Default for LogLevel {
fn default() -> Self {
Self::Info
}
}
impl From<&str> for LogLevel { impl From<&str> for LogLevel {
#[allow(clippy::wildcard_in_or_patterns)] #[allow(clippy::wildcard_in_or_patterns)]
fn from(s: &str) -> Self { fn from(s: &str) -> Self {