From 62ad59ab761d2505021512fd7daa4ab7f3d76bd9 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Fri, 19 Aug 2022 23:01:12 +0300 Subject: [PATCH] repo/sqlite: implement rest methods --- src/domain.rs | 2 +- src/repo.rs | 10 +-- src/repo/fs.rs | 8 +-- src/repo/sqlite.rs | 151 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 126 insertions(+), 45 deletions(-) diff --git a/src/domain.rs b/src/domain.rs index 45ca64b..093a784 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -15,7 +15,7 @@ //! use std::path::PathBuf; -pub type TaskId = usize; +pub type TaskIdx = usize; pub struct Task { pub name: String, diff --git a/src/repo.rs b/src/repo.rs index c75ec0b..50f66cc 100755 --- a/src/repo.rs +++ b/src/repo.rs @@ -28,6 +28,7 @@ pub enum Error { NotFound, InvalidData, InsertData, + UpdateData, RemoveData, } @@ -40,6 +41,7 @@ impl std::fmt::Display for Error { Error::NotFound => f.write_str("Cannot find data"), Error::InvalidData => f.write_str("Invalid data format"), Error::InsertData => f.write_str("Cannot insert data"), + Error::UpdateData => f.write_str("Cannot update data"), Error::RemoveData => f.write_str("Cannot remove data"), } } @@ -65,21 +67,21 @@ pub struct UpdateTaskData { pub trait Repository { fn get_current_task_opt(&self) -> Result, Error>; - fn get_task_opt(&self, id: domain::TaskId) -> Result, Error>; + fn get_task_opt(&self, id: domain::TaskIdx) -> Result, Error>; fn get_tasks(&self) -> Result, Error>; - fn remove_task(&self, id: domain::TaskId) -> Result; + fn remove_task(&self, id: domain::TaskIdx) -> Result; fn update_task( &self, - id: domain::TaskId, + id: domain::TaskIdx, update_data: UpdateTaskData, ) -> Result; fn insert_task(&self, insert_data: InsertTaskData) -> Result; - fn start_task(&self, id: domain::TaskId) -> Result; + fn start_task(&self, id: domain::TaskIdx) -> Result; fn stop_task(&self) -> Result; diff --git a/src/repo/fs.rs b/src/repo/fs.rs index 86811ef..51bf54b 100644 --- a/src/repo/fs.rs +++ b/src/repo/fs.rs @@ -79,7 +79,7 @@ impl Repository for FsRepo { .map(|cur_task| cur_task.map(From::from)) } - fn get_task_opt(&self, id: domain::TaskId) -> Result, Error> { + fn get_task_opt(&self, id: domain::TaskIdx) -> Result, Error> { let tasks = self.get_tasks_impl()?; if id == 0 || id > tasks.len() { return Err(Error::NotFound); @@ -93,7 +93,7 @@ impl Repository for FsRepo { .map(|tasks| tasks.into_iter().map(Task::into).collect()) } - fn remove_task(&self, id: domain::TaskId) -> Result { + fn remove_task(&self, id: domain::TaskIdx) -> Result { let mut tasks = self.get_tasks_impl()?; if id == 0 || id > tasks.len() { return Err(Error::NotFound); @@ -107,7 +107,7 @@ impl Repository for FsRepo { fn update_task( &self, - id: domain::TaskId, + id: domain::TaskIdx, update_data: UpdateTaskData, ) -> Result { let mut tasks = self.get_tasks_impl()?; @@ -161,7 +161,7 @@ impl Repository for FsRepo { Ok(new_task.into()) } - fn start_task(&self, id: domain::TaskId) -> Result { + fn start_task(&self, id: domain::TaskIdx) -> Result { let tasks = self.get_tasks_impl()?; if id == 0 || id > tasks.len() { return Err(Error::NotFound); diff --git a/src/repo/sqlite.rs b/src/repo/sqlite.rs index ca2ded5..920824c 100644 --- a/src/repo/sqlite.rs +++ b/src/repo/sqlite.rs @@ -12,12 +12,11 @@ struct Task { project: Option, link: Option, dir_path: Option, - + /* current: bool, - created_at: time::OffsetDateTime, finished_at: Option, - + */ idx: i64, } @@ -42,9 +41,11 @@ impl<'r> TryFrom<&'r rusqlite::Row<'_>> for Task { project: row.get("project")?, link: row.get("link")?, dir_path: row.get("dir_path")?, + /* current: row.get("current")?, created_at: row.get("created_at")?, finished_at: row.get("finished_at")?, + */ idx: row.get("idx")?, }) } @@ -79,34 +80,16 @@ impl SqliteRepo { impl Repository for SqliteRepo { fn get_current_task_opt(&self) -> Result, Error> { - let mut stmt = self - .conn - .prepare("SELECT * FROM active_tasks WHERE current IS true") - .map_err(|_| Error::PrepareQuery)?; + let db_task = self.get_current_task_opt_impl()?; - let row = stmt - .query_row([], |row| Task::try_from(row)) - .optional() - .map_err(|_| Error::QueryData)?; - - Ok(row.map(|db_task| domain::CurrentTaskInfo { + Ok(db_task.map(|db_task| domain::CurrentTaskInfo { task_idx: db_task.idx as usize, task: db_task.into(), })) } - fn get_task_opt(&self, id: domain::TaskId) -> Result, Error> { - let mut stmt = self - .conn - .prepare("SELECT * FROM active_tasks WHERE idx = ?") - .map_err(|_| Error::PrepareQuery)?; - - let row = stmt - .query_row([id as i64], |row| Task::try_from(row)) - .optional() - .map_err(|_| Error::QueryData)?; - - Ok(row.map(From::from)) + fn get_task_opt(&self, id: domain::TaskIdx) -> Result, Error> { + self.get_task_opt_impl(id).map(|t| t.map(From::from)) } fn get_tasks(&self) -> Result, Error> { @@ -125,18 +108,18 @@ impl Repository for SqliteRepo { .map_err(|_| Error::InvalidData) } - fn remove_task(&self, id: domain::TaskId) -> Result { - let task = self.get_task_opt(id)?.ok_or(Error::NotFound)?; + fn remove_task(&self, idx: domain::TaskIdx) -> Result { + let db_task = self.get_task_opt_impl(idx)?.ok_or(Error::NotFound)?; let mut stmt = self .conn .prepare("DELETE FROM tasks WHERE id = ?") .map_err(|_| Error::PrepareQuery)?; - stmt.execute([&(id as i64)]) + stmt.execute([&(db_task.id)]) .map_err(|_| Error::RemoveData)?; - Ok(task) + Ok(db_task.into()) } fn insert_task(&self, insert_data: super::InsertTaskData) -> Result { @@ -159,26 +142,122 @@ impl Repository for SqliteRepo { )) .map_err(|_| Error::InsertData)?; - self.get_task_opt(id as usize)?.ok_or(Error::NotFound) + dbg!(id); + + self.get_task_by_id_impl(id).map(From::from) } fn update_task( &self, - id: domain::TaskId, + idx: domain::TaskIdx, update_data: super::UpdateTaskData, ) -> Result { - todo!() + let task = self.get_task_opt_impl(idx)?.ok_or(Error::NotFound)?; + + let mut stmt = self + .conn + .prepare( + "UPDATE tasks + SET name = ?1, + project = ?2, + link = ?3, + dir_path = ?4 + WHERE id = ?5 + ", + ) + .map_err(|_| Error::PrepareQuery)?; + + stmt.execute(( + &update_data.name.unwrap_or(task.name), + &update_data.project.unwrap_or(task.project), + &update_data.link.unwrap_or(task.link), + &update_data + .dir_path + .unwrap_or(task.dir_path.map(PathBuf::from)) + .and_then(|p| p.into_os_string().into_string().ok()), + &task.id, + )) + .map_err(|_| Error::UpdateData)?; + + self.get_task_opt(idx)?.ok_or(Error::NotFound) } - fn start_task(&self, id: domain::TaskId) -> Result { - todo!() + fn start_task(&self, idx: domain::TaskIdx) -> Result { + let db_task = self.get_task_opt_impl(idx)?.ok_or(Error::NotFound)?; + + self.conn + .execute( + "UPDATE tasks SET current = true WHERE id = ?1", + [&db_task.id], + ) + .map_err(|_| Error::UpdateData)?; + + Ok(db_task.into()) } fn stop_task(&self) -> Result { - todo!() + let db_task = self.get_current_task_opt_impl()?.ok_or(Error::NotFound)?; + + self.conn + .execute( + "UPDATE tasks SET current = false WHERE id = ?1", + [&db_task.id], + ) + .map_err(|_| Error::UpdateData)?; + + Ok(db_task.into()) } fn finish_task(&self) -> Result { - todo!() + let db_task = self.get_current_task_opt_impl()?.ok_or(Error::NotFound)?; + + self.conn + .execute( + "UPDATE tasks + SET current = false, + finished_at = CURRENT_TIMESTAMP + WHERE id = ?1", + [&db_task.id], + ) + .map_err(|_| Error::UpdateData)?; + + Ok(db_task.into()) + } +} + +impl SqliteRepo { + fn get_task_by_id_impl(&self, id: i64) -> Result { + let mut stmt = self + .conn + .prepare("SELECT * FROM active_tasks WHERE id = ?") + .map_err(|_| Error::PrepareQuery)?; + + stmt.query_row([id], |row| Task::try_from(row)) + .map_err(|_| Error::QueryData) + } + + fn get_task_opt_impl(&self, idx: domain::TaskIdx) -> Result, Error> { + let mut stmt = self + .conn + .prepare("SELECT * FROM active_tasks WHERE idx = ?") + .map_err(|_| Error::PrepareQuery)?; + + stmt.query_row([idx as i64], |row| Task::try_from(row)) + .optional() + .map_err(|_| Error::QueryData) + } + + fn get_current_task_opt_impl(&self) -> Result, Error> { + let mut stmt = self + .conn + .prepare("SELECT * FROM active_tasks WHERE current IS true") + .map_err(|_| Error::PrepareQuery)?; + + let row = stmt + .query_row([], |row| Task::try_from(row)) + .optional() + .map_err(|_| Error::QueryData)?; + + Ok(row) } }