repo/sqlite: implement rest methods

This commit is contained in:
Dmitriy Pleshevskiy 2022-08-19 23:01:12 +03:00
parent a6cb3c7804
commit 62ad59ab76
Signed by: pleshevskiy
GPG key ID: 1B59187B161C0215
4 changed files with 126 additions and 45 deletions

View file

@ -15,7 +15,7 @@
//!
use std::path::PathBuf;
pub type TaskId = usize;
pub type TaskIdx = usize;
pub struct Task {
pub name: String,

View file

@ -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<Option<domain::CurrentTaskInfo>, Error>;
fn get_task_opt(&self, id: domain::TaskId) -> Result<Option<domain::Task>, Error>;
fn get_task_opt(&self, id: domain::TaskIdx) -> Result<Option<domain::Task>, Error>;
fn get_tasks(&self) -> Result<Vec<domain::Task>, Error>;
fn remove_task(&self, id: domain::TaskId) -> Result<domain::Task, Error>;
fn remove_task(&self, id: domain::TaskIdx) -> Result<domain::Task, Error>;
fn update_task(
&self,
id: domain::TaskId,
id: domain::TaskIdx,
update_data: UpdateTaskData,
) -> Result<domain::Task, Error>;
fn insert_task(&self, insert_data: InsertTaskData) -> Result<domain::Task, Error>;
fn start_task(&self, id: domain::TaskId) -> Result<domain::Task, Error>;
fn start_task(&self, id: domain::TaskIdx) -> Result<domain::Task, Error>;
fn stop_task(&self) -> Result<domain::Task, Error>;

View file

@ -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<Option<domain::Task>, Error> {
fn get_task_opt(&self, id: domain::TaskIdx) -> Result<Option<domain::Task>, 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<domain::Task, Error> {
fn remove_task(&self, id: domain::TaskIdx) -> Result<domain::Task, Error> {
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<domain::Task, Error> {
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<domain::Task, Error> {
fn start_task(&self, id: domain::TaskIdx) -> Result<domain::Task, Error> {
let tasks = self.get_tasks_impl()?;
if id == 0 || id > tasks.len() {
return Err(Error::NotFound);

View file

@ -12,12 +12,11 @@ struct Task {
project: Option<String>,
link: Option<String>,
dir_path: Option<String>,
/*
current: bool,
created_at: time::OffsetDateTime,
finished_at: Option<time::OffsetDateTime>,
*/
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<Option<domain::CurrentTaskInfo>, 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<Option<domain::Task>, 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<Option<domain::Task>, Error> {
self.get_task_opt_impl(id).map(|t| t.map(From::from))
}
fn get_tasks(&self) -> Result<Vec<domain::Task>, Error> {
@ -125,18 +108,18 @@ impl Repository for SqliteRepo {
.map_err(|_| Error::InvalidData)
}
fn remove_task(&self, id: domain::TaskId) -> Result<domain::Task, Error> {
let task = self.get_task_opt(id)?.ok_or(Error::NotFound)?;
fn remove_task(&self, idx: domain::TaskIdx) -> Result<domain::Task, Error> {
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<domain::Task, Error> {
@ -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<domain::Task, Error> {
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<domain::Task, Error> {
todo!()
fn start_task(&self, idx: domain::TaskIdx) -> Result<domain::Task, Error> {
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<domain::Task, Error> {
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<domain::Task, Error> {
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<Task, Error> {
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<Option<Task>, 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<Option<Task>, 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)
}
}