[go: up one dir, main page]

tatou 0.1.1

Tatou is a simple TUI application to manage and organize tasks.
use crate::project::{Project, Task};
use rusqlite::{Connection, params};
use std::path::PathBuf;

#[derive(Debug)]
pub struct DB {
  conn: Connection,
}

impl DB {
  pub fn new(path: PathBuf) -> rusqlite::Result<Self> {
    let conn = Connection::open(path)?;
    conn.execute("PRAGMA foreign_keys = ON;", params![])?;

    Ok(DB { conn })
  }

  pub fn init(&self) -> rusqlite::Result<()> {
    self.conn.execute(
      "CREATE TABLE IF NOT EXISTS Project (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          title TEXT NOT NULL
        )",
      (),
    )?;
    self.conn.execute(
      "CREATE TABLE IF NOT EXISTS Task (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          title TEXT NOT NULL,
          is_done INTEGER NOT NULL DEFAULT 0,
          proj_id INTEGER NOT NULL,
          FOREIGN KEY (proj_id) REFERENCES Project (id) ON DELETE CASCADE
        )",
      (),
    )?;

    Ok(())
  }

  pub fn insert_new_project(&self, project_title: &String) -> rusqlite::Result<i64> {
    self.conn.execute(
      "INSERT INTO Project (title) VALUES (?)",
      params![project_title],
    )?;

    let id = self.conn.last_insert_rowid();
    Ok(id)
  }

  pub fn delete_project_by_id(&self, proj_id: i64) -> rusqlite::Result<()> {
    self
      .conn
      .execute("DELETE FROM Project WHERE id = ?", params![proj_id])?;

    Ok(())
  }

  pub fn get_all_projects(&self) -> rusqlite::Result<Vec<Project>> {
    let mut stmt = self.conn.prepare("SELECT id, title FROM Project")?;
    let proj_iter = stmt.query_map(params![], |row| {
      Ok(Project::new(row.get(0)?, row.get(1)?, vec![]))
    })?;

    let mut all_projects = Vec::new();
    for proj in proj_iter {
      all_projects.push(proj?);
    }

    Ok(all_projects)
  }

  pub fn rename_project_by_id(&self, new_title: &String, proj_id: i64) -> rusqlite::Result<()> {
    self.conn.execute(
      "UPDATE Project SET title = ? WHERE id = ?",
      params![new_title, proj_id],
    )?;

    Ok(())
  }

  pub fn insert_new_task_in_project(
    &self,
    task_title: &String,
    proj_id: i64,
  ) -> rusqlite::Result<i64> {
    self.conn.execute(
      "INSERT INTO Task (title, proj_id) VALUES (?, ?)",
      params![task_title, proj_id],
    )?;

    let id = self.conn.last_insert_rowid();
    Ok(id)
  }

  pub fn delete_task_by_id(&self, task_id: i64) -> rusqlite::Result<()> {
    self
      .conn
      .execute("DELETE FROM Task WHERE id = ?", params![task_id])?;

    Ok(())
  }

  pub fn rename_task_by_id(&self, task_id: i64, new_title: &String) -> rusqlite::Result<()> {
    self.conn.execute(
      "UPDATE Task SET title = ? WHERE id = ?",
      params![new_title, task_id],
    )?;

    Ok(())
  }

  pub fn update_task_status(&self, task_id: i64, is_done: bool) -> rusqlite::Result<()> {
    self.conn.execute(
      "UPDATE Task SET is_done = ? WHERE id = ?",
      params![is_done, task_id],
    )?;

    Ok(())
  }

  pub fn get_all_tasks_in_project(&self, proj_id: i64) -> rusqlite::Result<Vec<Task>> {
    let mut stmt = self
      .conn
      .prepare("SELECT id, title, is_done FROM Task WHERE proj_id = ?")?;

    let task_iter = stmt.query_map(params![proj_id], |row| {
      Ok(Task::new(
        row.get(0)?,
        row.get(1)?,
        row.get::<_, i32>(2)? != 0,
      ))
    })?;

    let mut all_tasks = Vec::new();
    for task in task_iter {
      all_tasks.push(task?);
    }

    Ok(all_tasks)
  }
}