use rusqlite::{named_params, Connection, Error, Result};
pub mod models {
#[derive(Debug, Clone)]
pub struct Todo {
pub id: String,
pub title: String,
pub completed: bool,
}
}
use models::Todo;
pub fn init() -> Result<Connection, Error> {
let conn = Connection::open("./.todos.db")?;
conn.execute(
r#"
CREATE TABLE IF NOT EXISTS todos (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
completed BOOLEAN NOT NULL
)
"#,
(),
)?;
Ok(conn)
}
pub fn add_todo(conn: &Connection, todo: Todo) -> Result<usize, Error> {
conn.execute(
"INSERT INTO todos (id, title, completed) VALUES (?1, ?2, ?3)",
[&todo.id, &todo.title, &(todo.completed as i32).to_string()],
)
}
pub fn complete_todo(conn: &Connection, id: &str) -> Result<usize, Error> {
conn.execute("UPDATE todos SET completed = 1 WHERE id = ?1", [&id])
}
pub fn delete_todo(conn: &Connection, id: &str) -> Result<usize, Error> {
conn.execute("DELETE FROM todos WHERE id = ?1", [&id])
}
pub fn show_all(conn: &Connection) -> Result<Vec<Todo>, Error> {
let mut stmt = conn.prepare("SELECT id, title, completed FROM todos")?;
let rows = stmt.query_map([], |row| {
Ok(Todo {
id: row.get(0)?,
title: row.get(1)?,
completed: row.get::<_, i32>(2)? != 0,
})
})?;
rows.collect()
}
pub fn show_one(conn: &Connection, id: &str) -> Result<Vec<Todo>, Error> {
let mut stmt = conn.prepare("SELECT id, title, completed FROM todos WHERE id = ?1")?;
let rows = stmt.query_map([id], |row| {
Ok(Todo {
id: row.get(0)?,
title: row.get(1)?,
completed: row.get::<_, i32>(2)? != 0,
})
})?;
rows.collect()
}
pub fn update_todo(
conn: &Connection,
id: &str,
new_title: Option<&str>,
new_completed: Option<bool>,
) -> Result<usize, Error> {
let mut parts = Vec::new();
if new_title.is_some() {
parts.push("title = :title");
}
if new_completed.is_some() {
parts.push("completed = :completed");
}
if parts.is_empty() {
return Ok(0);
}
let sql = format!("UPDATE todos SET {} WHERE id = :id", parts.join(", "));
let mut stmt = conn.prepare(&sql)?;
let completed_int = new_completed.map(|c| if c { 1 } else { 0 });
match (new_title, completed_int) {
(Some(title), Some(completed)) => stmt.execute(named_params! {
":title": title,
":completed": completed,
":id": id,
}),
(Some(title), None) => stmt.execute(named_params! {
":title": title,
":id": id,
}),
(None, Some(completed)) => stmt.execute(named_params! {
":completed": completed,
":id": id,
}),
_ => Ok(0), }
}