chore: clean up warnings and public api

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-03-02 21:39:54 -06:00
parent bf2336386e
commit f098430a78
4 changed files with 99 additions and 102 deletions

View File

@ -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)?)

View File

@ -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,8 +114,8 @@ 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 {
@ -134,12 +132,15 @@ fn tracked_save_info(matches: &ArgMatches) {
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");
match maybe_games {
Some(games) => {
for game in games {
if let Some(name) = game.friendly_name {
print!("[{}] ", name);
@ -149,9 +150,12 @@ fn list_tracked_saves(_matches: &ArgMatches) {
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!(),
}
}

View File

@ -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)
}

103
src/db.rs
View File

@ -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,17 +237,13 @@ 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()))),
}
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)]