From fd2f77093812a19536487bbf6928d02fb9b1f372 Mon Sep 17 00:00:00 2001 From: Ben Morrison Date: Thu, 5 Sep 2019 03:25:45 -0400 Subject: letting errors flow up --- src/error.rs | 9 +++-- src/logging.rs | 11 +++--- src/main.rs | 18 +++++----- src/posts.rs | 105 +++++++++++++++++++++++++++------------------------------ 4 files changed, 72 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/error.rs b/src/error.rs index 032e2c2..517b5fc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,7 @@ -pub fn helper(res: Result) -> T +// This Result is used elsewhere, not in helper() +pub type Result = std::result::Result>; + +pub fn helper(res: std::result::Result) -> T where V: std::fmt::Debug, { @@ -17,7 +20,7 @@ mod tests { #[test] fn shouldnt_panic() { - let ok: Result<&str, &str> = Ok("okay"); + let ok: std::result::Result<&str, &str> = Ok("okay"); let rhs = helper(ok); assert_eq!("okay", rhs); } @@ -25,7 +28,7 @@ mod tests { #[test] #[should_panic] fn should_panic() { - let err: Result<&str, &str> = Err("oops"); + let err: std::result::Result<&str, &str> = Err("oops"); helper(err); } } diff --git a/src/logging.rs b/src/logging.rs index d138a6c..b42c6b1 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -4,13 +4,14 @@ use std::fs::File; use chrono::offset::Utc; use simplelog::*; +use crate::error; use crate::user; lazy_static! { static ref FILE: String = format!("/tmp/clinte_{}.log", *user::NAME); } -pub fn init() { +pub fn init() -> error::Result<()> { // If the log file exists on startup, // move and timestamp it so we get a // fresh log file. @@ -19,7 +20,7 @@ pub fn init() { let time = Utc::now().to_rfc3339(); new_file.push_str("."); new_file.push_str(&time); - fs::rename(FILE.clone(), new_file).unwrap(); + fs::rename(FILE.clone(), new_file)?; } CombinedLogger::init(vec![ @@ -27,10 +28,12 @@ pub fn init() { WriteLogger::new( LevelFilter::Info, Config::default(), - File::create(FILE.clone()).unwrap(), + File::create(FILE.clone())?, ), ]) .expect("Unable to initialize logging"); + + Ok(()) } #[cfg(test)] @@ -43,7 +46,7 @@ mod tests { fn init_logs() { let blank = " ".bytes().collect::>(); fs::write(&*FILE, &blank).unwrap(); - init(); + init().unwrap(); info!("TEST LOG MESSAGE"); let logfile = fs::read_to_string(&*FILE).unwrap(); diff --git a/src/main.rs b/src/main.rs index f003a5b..e2f793b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod logging; mod posts; mod user; -fn main() { +fn main() -> error::Result<()> { let arg_matches = clap::App::new("clinte") .version(clap::crate_version!()) .author("Ben Morrison (gbmor)") @@ -24,7 +24,7 @@ fn main() { .get_matches(); let start = time::Instant::now(); - logging::init(); + logging::init()?; info!("clinte starting up!"); println!("clinte v{}", clap::crate_version!()); println!("a community notices system"); @@ -36,24 +36,26 @@ fn main() { if arg_matches.subcommand_matches("post").is_some() { info!("New post..."); - posts::create(&db); + posts::create(&db)?; } else if arg_matches.subcommand_matches("update").is_some() { let id: u32 = if let Some(val) = arg_matches.subcommand_matches("update_handler") { - val.value_of("id").unwrap().parse().unwrap() + val.value_of("id").unwrap().parse()? } else { 0 }; info!("Updating post ..."); - posts::update_handler(&db, id); + posts::update_handler(&db, id)?; } else if arg_matches.subcommand_matches("delete").is_some() { let id: u32 = if let Some(val) = arg_matches.subcommand_matches("update_handler") { - val.value_of("id").unwrap().parse().unwrap() + val.value_of("id").unwrap_or_else(|| "0").parse()? } else { 0 }; info!("Deleting post"); - posts::delete_handler(&db, id); + posts::delete_handler(&db, id)?; } - posts::display(&db); + posts::display(&db)?; + + Ok(()) } diff --git a/src/posts.rs b/src/posts.rs index cb546ef..2e1772a 100644 --- a/src/posts.rs +++ b/src/posts.rs @@ -1,17 +1,15 @@ -use std::error::Error; use std::io; use rusqlite; use crate::db; use crate::ed; +use crate::error; use crate::user; -type Result = std::result::Result>; - // Executes the sql statement that inserts a new post // Broken off for unit testing. -pub fn exec_new(stmt: &mut rusqlite::Statement, title: &str, body: &str) -> Result<()> { +pub fn exec_new(stmt: &mut rusqlite::Statement, title: &str, body: &str) -> error::Result<()> { stmt.execute_named(&[ (":title", &title), (":author", &*user::NAME), @@ -33,16 +31,15 @@ fn str_to_utf8(str: &str) -> String { } // First handler for creating a new post. -pub fn create(db: &db::Conn) { +pub fn create(db: &db::Conn) -> error::Result<()> { let mut stmt = db .conn - .prepare("INSERT INTO posts (title, author, body) VALUES (:title, :author, :body)") - .unwrap(); + .prepare("INSERT INTO posts (title, author, body) VALUES (:title, :author, :body)")?; println!(); println!("Title of the new post: "); let mut title = String::new(); - io::stdin().read_line(&mut title).unwrap(); + io::stdin().read_line(&mut title)?; let title = str_to_utf8(title.trim()); let title = if title.len() > 30 { &title[..30] @@ -58,28 +55,27 @@ pub fn create(db: &db::Conn) { &body }; - exec_new(&mut stmt, title, body).unwrap(); + exec_new(&mut stmt, title, body)?; println!(); + Ok(()) } // Shows the most recent posts. -pub fn display(db: &db::Conn) { - let mut stmt = db.conn.prepare("SELECT * FROM posts").unwrap(); - let out = stmt - .query_map(rusqlite::NO_PARAMS, |row| { - let id: u32 = row.get(0)?; - let title: String = row.get(1)?; - let author: String = row.get(2)?; - let body: String = row.get(3)?; - Ok(db::Post { - id, - title, - author, - body, - }) +pub fn display(db: &db::Conn) -> error::Result<()> { + let mut stmt = db.conn.prepare("SELECT * FROM posts")?; + let out = stmt.query_map(rusqlite::NO_PARAMS, |row| { + let id: u32 = row.get(0)?; + let title: String = row.get(1)?; + let author: String = row.get(2)?; + let body: String = row.get(3)?; + Ok(db::Post { + id, + title, + author, + body, }) - .unwrap(); + })?; let mut postvec = Vec::new(); out.for_each(|row| { @@ -96,38 +92,35 @@ pub fn display(db: &db::Conn) { print!("{}", e); } } + + Ok(()) } // First handler to update posts. -pub fn update_handler(db: &db::Conn, id: u32) { +pub fn update_handler(db: &db::Conn, id: u32) -> error::Result<()> { let id_num_in = if id == 0 { println!(); println!("ID number of your post to edit?"); let mut id_num_in = String::new(); - io::stdin().read_line(&mut id_num_in).unwrap(); - id_num_in.trim().parse().unwrap() + io::stdin().read_line(&mut id_num_in)?; + id_num_in.trim().parse()? } else { id }; - let mut get_stmt = db - .conn - .prepare("SELECT * FROM posts WHERE id = :id") - .unwrap(); - - let row = get_stmt - .query_row_named(&[(":id", &id_num_in)], |row| { - let title: String = row.get(1).unwrap(); - let author = row.get(2).unwrap(); - let body = row.get(3).unwrap(); - Ok(vec![title, author, body]) - }) - .unwrap(); + let mut get_stmt = db.conn.prepare("SELECT * FROM posts WHERE id = :id")?; + + let row = get_stmt.query_row_named(&[(":id", &id_num_in)], |row| { + let title: String = row.get(1)?; + let author = row.get(2)?; + let body = row.get(3)?; + Ok(vec![title, author, body]) + })?; if *user::NAME != row[1] { println!(); println!("Username mismatch - can't update_handler post!"); - return; + return Ok(()); } let mut new_title = String::new(); @@ -138,17 +131,18 @@ pub fn update_handler(db: &db::Conn, id: u32) { println!("Title: {}\n\nBody: {}", row[0], row[2]); println!(); println!("Enter new title:"); - io::stdin().read_line(&mut new_title).unwrap(); + io::stdin().read_line(&mut new_title)?; println!(); println!("Enter new body:"); - io::stdin().read_line(&mut new_body).unwrap(); + io::stdin().read_line(&mut new_body)?; println!(); - update(&new_title, &new_body, id_num_in, &db).unwrap(); + update(&new_title, &new_body, id_num_in, &db)?; + Ok(()) } // Allows editing of posts - called by main::update -pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) -> Result<()> { +pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) -> error::Result<()> { let new_title = new_title.trim(); let new_body = new_body.trim(); @@ -164,20 +158,20 @@ pub fn update(new_title: &str, new_body: &str, id_num_in: u32, db: &db::Conn) -> } // Helper to just run a sql statement. -pub fn exec_stmt_no_params(stmt: &mut rusqlite::Statement) -> Result<()> { +pub fn exec_stmt_no_params(stmt: &mut rusqlite::Statement) -> error::Result<()> { stmt.execute(rusqlite::NO_PARAMS)?; Ok(()) } // First handler to remove a post -pub fn delete_handler(db: &db::Conn, id: u32) { +pub fn delete_handler(db: &db::Conn, id: u32) -> error::Result<()> { let id_num_in: u32 = if id == 0 { println!(); println!("ID of the post to delete?"); let mut id_num_in = String::new(); - io::stdin().read_line(&mut id_num_in).unwrap(); - id_num_in.trim().parse().unwrap() + io::stdin().read_line(&mut id_num_in)?; + id_num_in.trim().parse()? } else { id }; @@ -185,21 +179,20 @@ pub fn delete_handler(db: &db::Conn, id: u32) { let del_stmt = format!("DELETE FROM posts WHERE id = {}", id_num_in); let get_stmt = format!("SELECT * FROM posts WHERE id = {}", id_num_in); - let mut get_stmt = db.conn.prepare(&get_stmt).unwrap(); - let mut del_stmt = db.conn.prepare(&del_stmt).unwrap(); + let mut get_stmt = db.conn.prepare(&get_stmt)?; + let mut del_stmt = db.conn.prepare(&del_stmt)?; - let user_in_post: String = get_stmt - .query_row(rusqlite::NO_PARAMS, |row| row.get(2)) - .unwrap(); + let user_in_post: String = get_stmt.query_row(rusqlite::NO_PARAMS, |row| row.get(2))?; if *user::NAME != user_in_post { println!(); println!("Users don't match. Can't delete!"); println!(); - return; + return Ok(()); } - exec_stmt_no_params(&mut del_stmt).unwrap(); + exec_stmt_no_params(&mut del_stmt)?; + Ok(()) } #[cfg(test)] -- cgit 1.4.1-2-gfad0