chore: clean up warnings and public api
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| use crate::utils::{self, ProjectDirError}; | ||||
| use log::{debug, info, trace, warn}; | ||||
| use log::debug; | ||||
| use save_sync::db::{establish_connection, query::GameSaveQuery, Database}; | ||||
| use save_sync::game::{GameFile, GameSaveLocation}; | ||||
| use std::path::{Path, PathBuf}; | ||||
| @@ -158,13 +158,13 @@ impl Archive { | ||||
| } | ||||
|  | ||||
| impl Archive { | ||||
|     pub fn drop_game<P: AsRef<Path>>(path: P) -> Result<Option<()>, GameDropError> { | ||||
|     pub fn drop_game<P: AsRef<Path>>(path: P) -> Result<usize, GameDropError> { | ||||
|         let conn = establish_connection(); | ||||
|         let query = GameSaveQuery::Path(path.as_ref()); | ||||
|         Ok(Database::drop_game_save(&conn, query)?) | ||||
|     } | ||||
|  | ||||
|     pub fn drop_game_with_friendly(name: &str) -> Result<Option<()>, GameDropError> { | ||||
|     pub fn drop_game_with_friendly(name: &str) -> Result<usize, GameDropError> { | ||||
|         let conn = establish_connection(); | ||||
|         let query = GameSaveQuery::FriendlyName(name); | ||||
|         Ok(Database::drop_game_save(&conn, query)?) | ||||
|   | ||||
| @@ -2,9 +2,7 @@ use clap::{crate_authors, crate_description, crate_version, ArgMatches}; | ||||
| use clap::{App, Arg, SubCommand}; | ||||
| use client::archive::Archive; | ||||
| use dotenv::dotenv; | ||||
| use log::{debug, info}; | ||||
| use save_sync::db::{establish_connection, Database}; | ||||
| use std::path::Path; | ||||
| use log::info; | ||||
|  | ||||
| fn main() { | ||||
|     dotenv().ok(); | ||||
| @@ -116,42 +114,48 @@ fn tracked_save_info(matches: &ArgMatches) { | ||||
|         Archive::get_game(path_str).expect("Failed to get game save info from Archive") | ||||
|     }; | ||||
|  | ||||
|     let game = maybe_game.expect("No tracked game save found"); | ||||
|     match maybe_game { | ||||
|         Some(game) => { | ||||
|             if let Some(name) = game.friendly_name { | ||||
|                 println!("Friendly Name: {}", name); | ||||
|             } else { | ||||
|                 println!("Friendly Name: None"); | ||||
|             } | ||||
|  | ||||
|     if let Some(name) = game.friendly_name { | ||||
|         println!("Friendly Name: {}", name); | ||||
|     } else { | ||||
|         println!("Friendly Name: None"); | ||||
|     } | ||||
|             println!("Original Path: {:?}", game.original_path); | ||||
|             println!("UUID: {:?}", game.uuid); | ||||
|             println!("---\nFiles:"); | ||||
|  | ||||
|     println!("Original Path: {:?}", game.original_path); | ||||
|     println!("UUID: {:?}", game.uuid); | ||||
|     println!("---\nFiles:"); | ||||
|  | ||||
|     for file in game.files { | ||||
|         println!("Path: {:?}", file.original_path); | ||||
|         println!("Hash: {}", file.hash); | ||||
|         println!(); | ||||
|             for file in game.files { | ||||
|                 println!("Path: {:?}", file.original_path); | ||||
|                 println!("Hash: {}", file.hash); | ||||
|                 println!(); | ||||
|             } | ||||
|         } | ||||
|         None => println!("No tracked game save was found."), | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn list_tracked_saves(_matches: &ArgMatches) { | ||||
|     let games = Archive::get_all_games() | ||||
|         .expect("Failed to get all Games from the Archive") | ||||
|         .expect("There are no tracked Games"); | ||||
|     let maybe_games = Archive::get_all_games().expect("Failed to get all Games from the Archive"); | ||||
|  | ||||
|     for game in games { | ||||
|         if let Some(name) = game.friendly_name { | ||||
|             print!("[{}] ", name); | ||||
|     match maybe_games { | ||||
|         Some(games) => { | ||||
|             for game in games { | ||||
|                 if let Some(name) = game.friendly_name { | ||||
|                     print!("[{}] ", name); | ||||
|                 } | ||||
|                 println!("{:?}", game.original_path); | ||||
|                 println!("UUID: {:?}", game.uuid); | ||||
|                 println!("---"); | ||||
|             } | ||||
|         } | ||||
|         println!("{:?}", game.original_path); | ||||
|         println!("UUID: {:?}", game.uuid); | ||||
|         println!("---"); | ||||
|         None => println!("There are no tracked games"), | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn drop_save(matches: &ArgMatches) { | ||||
|     let maybe_compromised = if let Some(name) = matches.value_of("friendly") { | ||||
|     let items_deleted = if let Some(name) = matches.value_of("friendly") { | ||||
|         Archive::drop_game_with_friendly(name).expect("Archive failed to delete from database") | ||||
|     } else { | ||||
|         let path_str = matches | ||||
| @@ -161,8 +165,9 @@ fn drop_save(matches: &ArgMatches) { | ||||
|         Archive::drop_game(path_str).expect("Archive failed to delete from database") | ||||
|     }; | ||||
|  | ||||
|     match maybe_compromised { | ||||
|         Some(()) => println!("Game successfully dropped from the list"), | ||||
|         None => panic!("Database Invariant broken. Database is corrupted."), | ||||
|     match items_deleted { | ||||
|         0 => println!("Save Sync can't drop what was never tracked to begin with"), | ||||
|         1 => println!("Save Sync successfully dropped the game from the list of tracked games"), | ||||
|         _ => unreachable!(), | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,27 +1,6 @@ | ||||
| use directories::ProjectDirs; | ||||
| use std::path::Path; | ||||
| use thiserror::Error; | ||||
|  | ||||
| pub fn calc_file_hash(path: &Path) -> Option<u64> { | ||||
|     unimplemented!() | ||||
| } | ||||
|  | ||||
| pub fn archive_directory(src: &Path, dst: &Path) -> Result<(), Box<dyn std::error::Error>> { | ||||
|     unimplemented!() | ||||
| } | ||||
|  | ||||
| pub fn archive_file(src: &Path, dst: &Path) -> Result<(), Box<dyn std::error::Error>> { | ||||
|     unimplemented!() | ||||
| } | ||||
|  | ||||
| pub fn unarchive_directory(src: &Path, dst: &Path) -> Result<(), Box<dyn std::error::Error>> { | ||||
|     unimplemented!() | ||||
| } | ||||
|  | ||||
| pub fn unarchive_file(src: &Path, dst: &Path) -> Result<(), Box<dyn std::error::Error>> { | ||||
|     unimplemented!() | ||||
| } | ||||
|  | ||||
| pub fn get_project_dirs() -> Result<ProjectDirs, ProjectDirError> { | ||||
|     ProjectDirs::from("dev", "musuka", "save-sync").ok_or(ProjectDirError::HomeNotSet) | ||||
| } | ||||
|   | ||||
							
								
								
									
										109
									
								
								src/db.rs
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								src/db.rs
									
									
									
									
									
								
							| @@ -74,13 +74,11 @@ impl Database { | ||||
|     pub fn write_game_file(conn: &SqliteConnection, file: &GameFile, needle: i32) -> Result<()> { | ||||
|         use super::models::NewGameFile; | ||||
|         use super::schema::game_file; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::InvalidPath; | ||||
|  | ||||
|         let hash_bytes: [u8; 8] = file.hash.to_be_bytes(); | ||||
|         let path = &file.original_path; | ||||
|         let path_str = path | ||||
|             .to_str() | ||||
|             .ok_or_else(|| InvalidPathError(path.clone()))?; | ||||
|         let path_str = path.to_str().ok_or_else(|| InvalidPath(path.clone()))?; | ||||
|  | ||||
|         let new_game_file = NewGameFile { | ||||
|             original_path: path_str, | ||||
| @@ -104,7 +102,7 @@ impl Database { | ||||
|     ) -> ResultantOption<GameFile> { | ||||
|         use super::models::DbGameFile; | ||||
|         use super::schema::game_file::dsl::{file_hash, game_file, original_path}; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::{InvalidPath, UnexpectedBehaviour}; | ||||
|  | ||||
|         let game_files = match query { | ||||
|             GameFileQuery::Hash(hash) => { | ||||
| @@ -116,17 +114,17 @@ impl Database { | ||||
|             GameFileQuery::Path(path) => { | ||||
|                 let path_str = path | ||||
|                     .to_str() | ||||
|                     .ok_or_else(|| InvalidPathError(path.to_path_buf()))?; | ||||
|                     .ok_or_else(|| InvalidPath(path.to_path_buf()))?; | ||||
|                 game_file | ||||
|                     .filter(original_path.eq(path_str)) | ||||
|                     .load::<DbGameFile>(conn)? | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let maybe_game_files = if game_files.len() == 1 { | ||||
|             Some((&game_files[0]).into()) | ||||
|         } else { | ||||
|             None | ||||
|         let maybe_game_files = match game_files.len() { | ||||
|             0 => None, | ||||
|             1 => Some((&game_files[0]).into()), | ||||
|             num => return Err(UnexpectedBehaviour(format!("{:?}", query), num)), | ||||
|         }; | ||||
|  | ||||
|         Ok(maybe_game_files) | ||||
| @@ -168,9 +166,9 @@ impl Database { | ||||
|  | ||||
| // Drop GameFile Implementations | ||||
| impl Database { | ||||
|     fn drop_game_file(conn: &SqliteConnection, query: GameFileQuery) -> ResultantOption<()> { | ||||
|     fn drop_game_file(conn: &SqliteConnection, query: GameFileQuery) -> Result<usize> { | ||||
|         use super::schema::game_file::dsl::{file_hash, game_file, original_path}; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::{InvalidPath, UnexpectedBehaviour}; | ||||
|  | ||||
|         let num_deleted = match query { | ||||
|             GameFileQuery::Hash(hash) => { | ||||
| @@ -181,13 +179,17 @@ impl Database { | ||||
|             GameFileQuery::Path(path) => { | ||||
|                 let path_str = path | ||||
|                     .to_str() | ||||
|                     .ok_or_else(|| InvalidPathError(path.to_path_buf()))?; | ||||
|                     .ok_or_else(|| InvalidPath(path.to_path_buf()))?; | ||||
|                 let expr = game_file.filter(original_path.eq(path_str)); | ||||
|                 diesel::delete(expr).execute(conn)? | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         Ok(if num_deleted == 1 { Some(()) } else { None }) | ||||
|         if num_deleted <= 1 { | ||||
|             Ok(num_deleted) | ||||
|         } else { | ||||
|             Err(UnexpectedBehaviour(format!("{:?}", query), num_deleted)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -219,13 +221,10 @@ impl Database { | ||||
|         // Write Game Save Location to Database | ||||
|         use super::models::NewGameSaveLocation; | ||||
|         use super::schema::game_save_location; | ||||
|         use DatabaseEntry::Location; | ||||
|         use DatabaseError::{InvalidPathError, MissingDatabaseEntry}; | ||||
|         use DatabaseError::InvalidPath; | ||||
|  | ||||
|         let path = &save_loc.original_path; | ||||
|         let original_path = path | ||||
|             .to_str() | ||||
|             .ok_or_else(|| InvalidPathError(path.clone()))?; | ||||
|         let original_path = path.to_str().ok_or_else(|| InvalidPath(path.clone()))?; | ||||
|  | ||||
|         let new_game_save = NewGameSaveLocation { | ||||
|             friendly_name: save_loc.friendly_name.as_deref(), | ||||
| @@ -238,16 +237,12 @@ impl Database { | ||||
|             .execute(conn)?; | ||||
|  | ||||
|         // Get the ID of the Game Save in the database | ||||
|         let maybe_id = Self::get_game_save_id(conn, GameSaveQuery::Uuid(save_loc.uuid))?; | ||||
|         let id = Self::get_game_save_id(conn, GameSaveQuery::Uuid(save_loc.uuid))? | ||||
|             .expect("Failed to read entry in database after writing it."); | ||||
|  | ||||
|         match maybe_id { | ||||
|             Some(id) => { | ||||
|                 // Write all the GameFiles into the database | ||||
|                 for game_file in &save_loc.files { | ||||
|                     Self::write_game_file(conn, game_file, id)?; | ||||
|                 } | ||||
|             } | ||||
|             None => return Err(MissingDatabaseEntry(Location(save_loc.clone()))), | ||||
|         // Write all the GameFiles into the database | ||||
|         for game_file in &save_loc.files { | ||||
|             Self::write_game_file(conn, game_file, id)?; | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
| @@ -264,7 +259,7 @@ impl Database { | ||||
|         use super::schema::game_save_location::dsl::{ | ||||
|             friendly_name, game_save_location, id, original_path, uuid, | ||||
|         }; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::{InvalidPath, UnexpectedBehaviour}; | ||||
|  | ||||
|         let save_locs = match query { | ||||
|             GameSaveQuery::Id(needle) => game_save_location | ||||
| @@ -276,7 +271,7 @@ impl Database { | ||||
|             GameSaveQuery::Path(path) => { | ||||
|                 let path_str = path | ||||
|                     .to_str() | ||||
|                     .ok_or_else(|| InvalidPathError(path.to_path_buf()))?; | ||||
|                     .ok_or_else(|| InvalidPath(path.to_path_buf()))?; | ||||
|                 game_save_location | ||||
|                     .filter(original_path.eq(path_str)) | ||||
|                     .load::<DbGameSaveLocation>(conn)? | ||||
| @@ -289,10 +284,10 @@ impl Database { | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let maybe_save_loc = if save_locs.len() == 1 { | ||||
|             Some((&save_locs[0]).into()) | ||||
|         } else { | ||||
|             None | ||||
|         let maybe_save_loc = match save_locs.len() { | ||||
|             0 => None, | ||||
|             1 => Some((&save_locs[0]).into()), | ||||
|             num => return Err(UnexpectedBehaviour(format!("{:?}", query), num)), | ||||
|         }; | ||||
|  | ||||
|         Ok(maybe_save_loc) | ||||
| @@ -302,7 +297,7 @@ impl Database { | ||||
|         use super::schema::game_save_location::dsl::{ | ||||
|             friendly_name, game_save_location, id, original_path, uuid, | ||||
|         }; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::{InvalidPath, UnexpectedBehaviour}; | ||||
|  | ||||
|         let ids = match query { | ||||
|             GameSaveQuery::Id(id_value) => vec![id_value], // Why? | ||||
| @@ -320,7 +315,7 @@ impl Database { | ||||
|             GameSaveQuery::Path(path) => { | ||||
|                 let path_str = path | ||||
|                     .to_str() | ||||
|                     .ok_or_else(|| InvalidPathError(path.to_path_buf()))?; | ||||
|                     .ok_or_else(|| InvalidPath(path.to_path_buf()))?; | ||||
|                 game_save_location | ||||
|                     .select(id) | ||||
|                     .filter(original_path.eq(path_str)) | ||||
| @@ -328,31 +323,44 @@ impl Database { | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         // FIXME: Is there are more ergonomic way of doing this? | ||||
|         Ok(if ids.len() == 1 { Some(ids[0]) } else { None }) | ||||
|         let maybe_id = match ids.len() { | ||||
|             0 => None, | ||||
|             1 => Some(ids[0]), | ||||
|             num => return Err(UnexpectedBehaviour(format!("{:?}", query), num)), | ||||
|         }; | ||||
|  | ||||
|         Ok(maybe_id) | ||||
|     } | ||||
|  | ||||
|     pub fn get_all_game_saves(conn: &SqliteConnection) -> ResultantOption<Vec<GameSaveLocation>> { | ||||
|         use super::models::DbGameSaveLocation; | ||||
|         use super::schema::game_save_location::dsl::game_save_location; | ||||
|  | ||||
|         let db_save_locs = game_save_location | ||||
|         let save_locs = game_save_location | ||||
|             .load::<DbGameSaveLocation>(conn)? | ||||
|             .iter() | ||||
|             .map(GameSaveLocation::from) | ||||
|             .collect(); | ||||
|             .collect::<Vec<GameSaveLocation>>(); | ||||
|  | ||||
|         Ok(Some(db_save_locs)) | ||||
|         let empty = save_locs.is_empty(); | ||||
|         Ok(if empty { None } else { Some(save_locs) }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Drop GameSaveLocation Implementations | ||||
| impl Database { | ||||
|     pub fn drop_game_save(conn: &SqliteConnection, query: GameSaveQuery) -> ResultantOption<()> { | ||||
|     pub fn drop_game_save(conn: &SqliteConnection, query: GameSaveQuery) -> Result<usize> { | ||||
|         use super::schema::game_save_location::dsl::{ | ||||
|             friendly_name, game_save_location, id, original_path, uuid, | ||||
|         }; | ||||
|         use DatabaseError::InvalidPathError; | ||||
|         use DatabaseError::{InvalidPath, UnexpectedBehaviour}; | ||||
|  | ||||
|         // Drop all files related to the to-be-deleted Game Save | ||||
|         if let Some(game_save) = Self::get_game_save(conn, query)? { | ||||
|             for file in game_save.files { | ||||
|                 Self::drop_game_file(conn, GameFileQuery::Hash(file.hash))?; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         let num_deleted = match query { | ||||
|             GameSaveQuery::Id(needle) => { | ||||
| @@ -366,7 +374,7 @@ impl Database { | ||||
|             GameSaveQuery::Path(path) => { | ||||
|                 let path_str = path | ||||
|                     .to_str() | ||||
|                     .ok_or_else(|| InvalidPathError(path.to_path_buf()))?; | ||||
|                     .ok_or_else(|| InvalidPath(path.to_path_buf()))?; | ||||
|                 let expr = game_save_location.filter(original_path.eq(path_str)); | ||||
|                 diesel::delete(expr).execute(conn)? | ||||
|             } | ||||
| @@ -377,19 +385,24 @@ impl Database { | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         // FIXME: Is there are more ergonomic way of doing this? | ||||
|         Ok(if num_deleted == 1 { Some(()) } else { None }) | ||||
|         if num_deleted <= 1 { | ||||
|             Ok(num_deleted) | ||||
|         } else { | ||||
|             Err(UnexpectedBehaviour(format!("{:?}", query), num_deleted)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Error)] | ||||
| pub enum DatabaseError { | ||||
|     #[error("The path {0:?} can not be converted to a UTF-8 String")] | ||||
|     InvalidPathError(PathBuf), | ||||
|     InvalidPath(PathBuf), | ||||
|     #[error(transparent)] | ||||
|     OrmError(#[from] diesel::result::Error), | ||||
|     Orm(#[from] diesel::result::Error), | ||||
|     #[error("Expected {0:?} to be present in the DB but it was not")] | ||||
|     MissingDatabaseEntry(DatabaseEntry), | ||||
|     #[error("The Query: \"{0}\" affected {1} database entries (it should only affect one)")] | ||||
|     UnexpectedBehaviour(String, usize), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user