pub mod commands;
pub mod database;
pub mod models;
mod tui;
pub use commands::{Cli, Commands, execute_command};
pub use models::{Todo, TodoList};
use sqlx::SqlitePool;
pub struct TodoManager {
pub todolist: TodoList,
pool: SqlitePool,
}
impl TodoManager {
pub async fn new() -> color_eyre::Result<Self> {
if let Some(parent) = std::path::Path::new("todos.db").parent()
&& !parent.as_os_str().is_empty()
&& !parent.exists()
{
std::fs::create_dir_all(parent)?;
}
let pool = SqlitePool::connect("sqlite:todos.db?mode=rwc").await?;
sqlx::migrate!("./migrations").run(&pool).await?;
let mut todolist = TodoList::new();
todolist.load_from_db(&pool).await?;
Ok(Self { todolist, pool })
}
pub async fn with_db_path(db_path: &str) -> color_eyre::Result<Self> {
if let Some(parent) = std::path::Path::new(db_path).parent()
&& !parent.as_os_str().is_empty()
&& !parent.exists()
{
std::fs::create_dir_all(parent)?;
}
let pool = SqlitePool::connect(&format!("sqlite:{}?mode=rwc", db_path)).await?;
sqlx::migrate!("./migrations").run(&pool).await?;
let mut todolist = TodoList::new();
todolist.load_from_db(&pool).await?;
Ok(Self { todolist, pool })
}
pub async fn add(&mut self, content: &str) -> color_eyre::Result<()> {
self.todolist
.add_todo_db(content.to_string(), &self.pool)
.await?;
self.todolist.sync_to_db(&self.pool).await?;
Ok(())
}
pub async fn finish(&mut self, content: &str) -> color_eyre::Result<()> {
self.todolist
.finish_todo_db(content.to_string(), &self.pool)
.await?;
self.todolist.sync_to_db(&self.pool).await?;
Ok(())
}
pub async fn edit(&mut self, find: &str, replace: &str) -> color_eyre::Result<()> {
self.todolist
.edit_todo_db(find.to_string(), replace.to_string(), &self.pool)
.await?;
self.todolist.sync_to_db(&self.pool).await?;
Ok(())
}
pub async fn clean(&mut self) -> color_eyre::Result<()> {
self.todolist.clean_todo_db(&self.pool).await?;
Ok(())
}
pub fn list(&self) -> impl Iterator<Item = &Todo> {
self.todolist.todos.values()
}
pub fn list_pending(&self) -> impl Iterator<Item = &Todo> {
self.todolist.todos.values().filter(|t| !t.finished)
}
pub fn list_finished(&self) -> impl Iterator<Item = &Todo> {
self.todolist.todos.values().filter(|t| t.finished)
}
pub async fn get(&self, content: &str) -> color_eyre::Result<Option<Todo>> {
let result = sqlx::query_as::<_, Todo>("SELECT * FROM todos WHERE content = ? LIMIT 1")
.bind(content)
.fetch_optional(&self.pool)
.await?;
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
#[ignore] async fn test_todo_manager_new() {
let result = TodoManager::with_db_path(":memory:").await;
assert!(result.is_ok(), "TodoManager should initialize with valid migrations");
}
}