Skip to content

Commit

Permalink
Migrated to ThisError
Browse files Browse the repository at this point in the history
  • Loading branch information
khan5ula committed Oct 11, 2024
1 parent 323236d commit a4c71c8
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 159 deletions.
6 changes: 1 addition & 5 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,7 @@ pub fn handle_args(conn: Connection, args: NotedArgs) -> Result<(), NoteError> {
match args.command {
Commands::New { content, file, gui } => {
if let Some(file) = file {
let note_content = match read_file_to_string(&file) {
Ok(note_content) => note_content,
Err(e) => return Err(NoteError::FileError(e.to_string())),
};

let note_content = read_file_to_string(&file)?;
create_new_note(&conn, note_content)?;
} else if gui {
create_note_from_gui(&conn)?;
Expand Down
159 changes: 53 additions & 106 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,38 @@ pub fn init_db() -> Result<Connection, NoteError> {
let cwd = env::current_dir().unwrap();
let home_dir = env::var("HOME").expect("Could not get $HOME directory");
let db_path = PathBuf::from(home_dir).join(".local/share/noted/notes.db");

let conn = match Connection::open(cwd.join(db_path)) {
Ok(conn) => conn,
Err(e) => return Err(NoteError::RustqliteError(e)),
};
let conn = Connection::open(cwd.join(db_path)).map_err(NoteError::RustqliteError)?;

create_table(&conn)?;
Ok(conn)
}

pub fn create_table(conn: &Connection) -> Result<(), NoteError> {
match conn.execute(
conn.execute(
"CREATE TABLE IF NOT EXISTS note (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
date NUMBER NOT NULL
)",
(),
) {
Ok(_) => Ok(()),
Err(e) => Err(NoteError::RustqliteError(e)),
}
)
.map_err(NoteError::RustqliteError)?;

Ok(())
}

pub fn create_new_note(conn: &Connection, content: String) -> Result<(), NoteError> {
pub fn create_new_note(conn: &Connection, content: String) -> Result<usize, NoteError> {
let new_note = Note::new(content);

match conn.execute(
conn.execute(
"INSERT INTO note (id, content, date) VALUES (?1, ?2, ?3)",
(
&new_note.get_id().to_string(),
&new_note.get_content(),
&new_note.get_date(),
),
) {
Ok(_) => Ok(()),
Err(e) => Err(NoteError::RustqliteError(e)),
}
)
.map_err(NoteError::RustqliteError)
}

pub fn create_note_from_gui(conn: &Connection) -> Result<(), NoteError> {
Expand Down Expand Up @@ -83,35 +77,25 @@ pub fn create_note_from_gui(conn: &Connection) -> Result<(), NoteError> {
file.write_all(&output.stdout)
.expect("Failed to write to file");

let note_content = match read_file_to_string(&filename) {
Ok(note_content) => note_content,
Err(e) => {
return Err(NoteError::FileError(format!(
"Failed to read note from a file: {}",
e
)))
}
};
let note_content = read_file_to_string(&filename)?;

create_new_note(conn, note_content)?;
fs::remove_file(filename).map_err(|e| NoteError::FileError(e.to_string()))?
fs::remove_file(filename).map_err(NoteError::FileError)?;
}

Ok(())
}

pub fn get_all_notes(conn: &Connection) -> Result<Vec<Note>, NoteError> {
let mut statement = match conn.prepare("SELECT id, content, date FROM note") {
Ok(statement) => statement,
Err(e) => return Err(NoteError::RustqliteError(e)),
};

let note_iterator = match statement.query_map([], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
}) {
Ok(iterator) => iterator,
Err(e) => return Err(NoteError::IterationError(e)),
};
let mut statement = conn
.prepare("SELECT id, content, date FROM note")
.map_err(NoteError::RustqliteError)?;

let note_iterator = statement
.query_map([], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
})
.map_err(NoteError::RustqliteError)?;

note_iter_into_vec(note_iterator)
}
Expand All @@ -126,77 +110,54 @@ pub fn get_notes_with_qty_and_order(
order_by.as_str()
);

let mut statement = match conn.prepare(&query) {
Ok(statement) => statement,
Err(e) => return Err(NoteError::RustqliteError(e)),
};
let mut statement = conn.prepare(&query).map_err(NoteError::RustqliteError)?;

let note_iterator = match statement.query_map([count], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
}) {
Ok(iterator) => iterator,
Err(e) => return Err(NoteError::IterationError(e)),
};
let note_iterator = statement
.query_map([count], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
})
.map_err(NoteError::RustqliteError)?;

note_iter_into_vec(note_iterator)
}

pub fn delete_note(conn: &Connection, id: &String) -> Result<usize, NoteError> {
let like_id = format!("{}%", id);

match conn.execute("DELETE FROM note WHERE id LIKE ?", [like_id]) {
Ok(rows_deleted) => Ok(rows_deleted),
Err(e) => {
println!(
"Couldn't remove a note with given id: '{}' due to: {}",
id, e
);
Err(NoteError::RustqliteError(e))
}
}
conn.execute("DELETE FROM note WHERE id LIKE ?", [like_id])
.map_err(NoteError::RustqliteError)
}

pub fn delete_all_notes(conn: &Connection) -> Result<usize, NoteError> {
match conn.execute("DELETE FROM note", ()) {
Ok(count) => Ok(count),
Err(e) => Err(NoteError::RustqliteError(e)),
}
conn.execute("DELETE FROM note", ())
.map_err(NoteError::RustqliteError)
}

pub fn search_notes_by_content(conn: &Connection, needle: &String) -> Result<Vec<Note>, NoteError> {
let query = "SELECT id, content, date FROM note WHERE content LIKE ?";
let search_with_wildcards = format!("%{}%", needle);

let mut statement = match conn.prepare(query) {
Ok(statement) => statement,
Err(e) => return Err(NoteError::RustqliteError(e)),
};
let mut statement = conn.prepare(query).map_err(NoteError::RustqliteError)?;

let note_iterator = match statement.query_map([search_with_wildcards], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
}) {
Ok(iterator) => iterator,
Err(e) => return Err(NoteError::IterationError(e)),
};
let note_iterator = statement
.query_map([search_with_wildcards], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
})
.map_err(NoteError::RustqliteError)?;

note_iter_into_vec(note_iterator)
}

pub fn search_notes_by_id(conn: &Connection, id: &String) -> Result<Vec<Note>, NoteError> {
let like_id = format!("{}%", id);
let query = "SELECT id, content, date FROM note WHERE id LIKE ?";
let mut statement = conn.prepare(query).map_err(NoteError::RustqliteError)?;

let mut statement = match conn.prepare(query) {
Ok(statement) => statement,
Err(e) => return Err(NoteError::RustqliteError(e)),
};

let note_iterator = match statement.query_map([like_id], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
}) {
Ok(iterator) => iterator,
Err(e) => return Err(NoteError::IterationError(e)),
};
let note_iterator = statement
.query_map([like_id], |row| {
Ok(Note::from_db(row.get(0)?, row.get(1)?, row.get(2)?))
})
.map_err(NoteError::RustqliteError)?;

note_iter_into_vec(note_iterator)
}
Expand Down Expand Up @@ -234,41 +195,27 @@ pub fn edit_note_with_gui(
file.write_all(&output.stdout)
.expect("Failed to write to file");

let note_content = match read_file_to_string(&new_content_filepath) {
Ok(note_content) => note_content,
Err(e) => {
return Err(NoteError::FileError(format!(
"Failed to read note from a file: {}",
e
)))
}
};

fs::remove_file(new_content_filepath).map_err(|e| NoteError::FileError(e.to_string()))?;
fs::remove_file(note_to_edit_path).map_err(|e| NoteError::FileError(e.to_string()))?;
edit_note(conn, id, &note_content)?;
let note_content = read_file_to_string(&new_content_filepath)?;

fs::remove_file(new_content_filepath).map_err(NoteError::FileError)?;
fs::remove_file(note_to_edit_path).map_err(NoteError::FileError)?;
edit_note(conn, id, &note_content)
} else {
// Ensure the note to edit tmp file is removed if the yad operation is cancelled
fs::remove_file(note_to_edit_path).map_err(|e| NoteError::FileError(e.to_string()))?;
fs::remove_file(note_to_edit_path).map_err(NoteError::FileError)?;
Ok(0)
}

Err(NoteError::FileError("Failed to edit a note".to_string()))
}

pub fn edit_note(conn: &Connection, id: &String, content: &String) -> Result<usize, NoteError> {
let like_id = format!("{}%", id);
let updated_timestamp = Note::create_new_timestamp().to_string();

match conn.execute(
conn.execute(
"UPDATE note SET content = ?1, date = ?2 WHERE id LIKE ?3",
[content, &updated_timestamp, &like_id],
) {
Ok(rows_edited) => Ok(rows_edited),
Err(e) => {
println!("Couldn't edit a note with given id: '{}' due to: {}", id, e);
Err(NoteError::RustqliteError(e))
}
}
)
.map_err(NoteError::RustqliteError)
}

pub fn handle_edit_note(conn: &Connection, note: &Note) -> Result<usize, NoteError> {
Expand Down
20 changes: 8 additions & 12 deletions src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::note::Note;
use crate::note::NoteError;
use crate::note::{Note, NoteError};
use rusqlite::Error;
use std::fs::File;
use std::io::Read;
Expand Down Expand Up @@ -36,17 +35,14 @@ pub fn read_y_or_no_input(prompt: &str) -> Result<char, NoteError> {
}

pub fn read_file_to_string(path: &str) -> Result<String, NoteError> {
let mut file = match File::open(path) {
Ok(file) => file,
Err(e) => return Err(NoteError::FileError(e.to_string())),
};

let mut file = File::open(path).map_err(NoteError::FileError)?;
let mut file_content = String::new();

match file.read_to_string(&mut file_content) {
Ok(_) => Ok(file_content),
Err(e) => Err(NoteError::FileError(e.to_string())),
}
let _ = file
.read_to_string(&mut file_content)
.map_err(NoteError::FileError);

Ok(file_content)
}

pub fn print_notes(notes: Vec<Note>) {
Expand Down Expand Up @@ -79,7 +75,7 @@ where
}
},
Err(e) => {
return Err(NoteError::IterationError(e));
return Err(NoteError::RustqliteError(e));
}
}
}
Expand Down
44 changes: 14 additions & 30 deletions src/note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use ansi_term::Colour::Blue;
use chrono::prelude::*;
use chrono::Local;
use rusqlite::Error;
use std::error::Error as StdError;
use std::io::Error as IoError;
use thiserror::Error;

#[derive(Debug)]
pub struct Note {
Expand Down Expand Up @@ -72,37 +73,20 @@ impl fmt::Display for Note {
}
}

#[derive(Debug)]
#[derive(Debug, Error)]
pub enum NoteError {
IterationError(Error),
#[error("Failed to unwrap note: {0}")]
UnwrapNoteError(String),
RustqliteError(Error),
FileError(String),

#[error("SQLite error: {0}")]
RustqliteError(#[from] Error),

#[error("File error: {0}")]
FileError(#[from] IoError),

#[error("Input error: {0}")]
InputError(String),
UnexpectedResultError(String),
}

impl fmt::Display for NoteError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NoteError::IterationError(e) => {
write!(f, "Couldn't iterate through notes: {}", e)
}
NoteError::UnwrapNoteError(e) => write!(f, "Couldn't unwrap note: {}", e),
NoteError::RustqliteError(e) => {
write!(f, "Rustqlite error while handling notes: {}", e)
}
NoteError::FileError(e) => {
write!(f, "Error occured while trying to parse a file: {}", e)
}
NoteError::InputError(e) => {
write!(f, "Error while reading user input: {}", e)
}
NoteError::UnexpectedResultError(e) => {
write!(f, "Received unexpected result: {}", e)
}
}
}
#[error("Unexpected result: {0}")]
UnexpectedResultError(String),
}

impl StdError for NoteError {}
8 changes: 2 additions & 6 deletions tests/db_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,11 @@ mod tests {
}

fn read_file_to_vector(path: PathBuf) -> Result<Vec<String>, NoteError> {
let file = match File::open(path) {
Ok(file) => file,
Err(e) => return Err(NoteError::FileError(e.to_string())),
};

let file = File::open(path).map_err(NoteError::FileError)?;
let buf = BufReader::new(file);

buf.lines()
.map(|l| l.map_err(|e| NoteError::FileError(e.to_string())))
.map(|l| l.map_err(NoteError::FileError))
.collect()
}

Expand Down

0 comments on commit a4c71c8

Please sign in to comment.