Rust CLI ToDo
A console based todo app, written in rust, saving to sqlite.
Update .toml dependencies
cargo install cargo-update
cargo install-update -a
Usage
Create
-b body
-d due_date
td create -b "todo content"
td create -b "todo content" -d 2021-02-15
List
td td list
Delete
-i -> row id
td delete -i 1
Code
main
hideous main function - first actual rust program I am writing
main()
fn main() {
let yaml = load_yaml!("cli.yml");
let matches: ArgMatches = App::from(yaml).get_matches();
// setup db
let connection: Connection = api::database::open_connection();
api::database::initial_table_setup(&connection);
// handle arguments
if let Some(matches) = matches.subcommand_matches(COM_CREATE) {
let mut body: &str = "";
let mut date: &str = "";
if matches.is_present(ARG_BODY) {
body = match matches.value_of(ARG_BODY) {
None => "",
Some(x) => {
x.trim()
}
};
}
if matches.is_present(ARG_DATE) {
date = match matches.value_of(ARG_DATE) {
None => "",
Some(arg_date) => {
if util::util::is_date(arg_date.trim()) {
arg_date.trim()
} else {
println!("Input date of wrong format. Needs yyyy-mm-dd.");
""
}
}
};
}
if !body.is_empty() {
let _rows_modified = actions::create::create(&body, &date, &connection);
}
} else if let Some(matches) = matches.subcommand_matches(COM_DELETE) {
let id = match matches.value_of(ARG_ID) {
None => "",
Some(id) => id
};
if !id.is_empty() {
let _rows_modified = actions::delete::delete(id.trim(), &connection);
} else {
println!("Cannot delete for empty id.")
}
} else if let Some(_) = matches.subcommand_matches(COM_LIST) {
actions::list::list(&connection);
}
// default action
actions::list::list(&connection);
// close app
shutdown();
}
API module
Setup
Database Setup
pub fn open_connection() -> Connection {
return Connection::open(NAME_DATABASE).unwrap();
}
pub fn initial_table_setup(connection: &Connection) -> usize {
let rows_modified: usize = match connection.execute(
"create table if not exists todos (
id integer primary key,
body text not null,
due_date date
)",
NO_PARAMS,
) {
Ok(x) => x,
Err(_) => 0,
};
return rows_modified;
}
Create Entry
Create Entry
use rusqlite::Connection;
use crate::constants::{TABLE_COL_BODY, TABLE_COL_DUE_DATE, TABLE_TODOS};
pub fn create(body: &str, date: &str, connection: &Connection) -> usize {
let mut rows_modified: usize = 0;
if !body.is_empty() {
let query: &str = &*format!(
"INSERT INTO {} ({}, {}) values (?1, ?2)",
TABLE_TODOS,
TABLE_COL_BODY,
TABLE_COL_DUE_DATE
);
rows_modified = match connection.execute(
query,
&[body.to_string(), date.to_string()],
) {
Ok(x) => x,
Err(_) => 0,
};
}
return rows_modified;
}
Read Entries
Get all DB Entries
use rusqlite::{Connection, params};
use crate::constants::TABLE_TODOS;
#[derive(Debug)]
struct Todo {
id: i32,
body: String,
date: String,
}
pub fn list(connection: &Connection) {
let query: &str = &*format!(
"SELECT * FROM {}",
TABLE_TODOS,
);
let mut statement = connection.prepare(
query
).expect("Error preparing SELECT statement.");
let todos_iter = statement.query_map(params![], |row| {
Ok(Todo {
id: row.get(0).expect("Error unwrapping id."),
body: row.get(1).expect("Error unwrapping body."),
date: row.get(2).expect("Error unwrapping date."),
})
}).unwrap();
for todo in todos_iter {
let todo_item: Todo = todo.unwrap();
println!("ID: {} -- {} -> ({})", todo_item.id, todo_item.body, todo_item.date);
}
}
Delete Entry
Delete Entry
use rusqlite::Connection;
use crate::constants::{TABLE_COL_ID, TABLE_TODOS};
pub fn delete(id: &str, connection: &Connection) -> usize {
let mut rows_modified: usize = 0;
if !id.is_empty() {
let query: &str = &*format!(
"DELETE FROM {} where {} like (?1)",
TABLE_TODOS,
TABLE_COL_ID
);
rows_modified = match connection.execute(
query,
&[id],
) {
Ok(x) => x,
Err(_) => 0,
};
}
return rows_modified;
}