diff --git a/Cargo.lock b/Cargo.lock index 69a7339..1c399dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.13.0" @@ -274,6 +283,7 @@ dependencies = [ "hashlink", "libsqlite3-sys", "smallvec", + "time", ] [[package]] @@ -339,6 +349,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "time", "xdg", ] @@ -368,6 +379,24 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + [[package]] name = "unicode-ident" version = "1.0.3" diff --git a/Cargo.toml b/Cargo.toml index 5811503..a139b1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,8 @@ maintenance = { status = "experimental" } [dependencies] clap = { version = "3.2.16", default-features = false, features = ["derive", "std"] } log = "0.4.17" -rusqlite = { version = "0.28.0", features = ["bundled"] } +rusqlite = { version = "0.28.0", features = ["bundled", "time"] } serde = { version = "1.0.142", features = ["derive"] } serde_json = "1.0.83" +time = "0.3" xdg = "2.4.1" diff --git a/database/migrations/202208162308.sql b/database/migrations/202208162308.sql index ab812a6..9d549d5 100644 --- a/database/migrations/202208162308.sql +++ b/database/migrations/202208162308.sql @@ -5,9 +5,9 @@ CREATE TABLE _tas_info ( CREATE TABLE tasks ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, - group TEXT NULL, + project TEXT NULL, link TEXT NULL, - path TEXT NULL, + dir_path TEXT NULL, current BOOLEAN NOT NULL DEFAULT false, @@ -16,10 +16,9 @@ CREATE TABLE tasks ( ); CREATE VIEW active_tasks AS ( - SELECT * - FROM tasks - WHERE finished_at IS NULL - ORDER BY created_at + SELECT t.* + FROM tasks AS t + WHERE t.finished_at IS NULL + ORDER BY t.created_at ); - - +; diff --git a/database/schema.sql b/database/schema.sql index 6a5be81..77cda19 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -5,9 +5,9 @@ CREATE TABLE _tas_info ( CREATE TABLE tasks ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, - group TEXT NULL, + project TEXT NULL, link TEXT NULL, - path TEXT NULL, + dir_path TEXT NULL, current BOOLEAN NOT NULL DEFAULT false, @@ -16,9 +16,8 @@ CREATE TABLE tasks ( ); CREATE VIEW active_tasks AS ( - SELECT * - FROM tasks - WHERE finished_at IS NULL - ORDER BY created_at + SELECT t.* + FROM tasks AS t + WHERE t.finished_at IS NULL + ORDER BY t.created_at ); - diff --git a/src/repo.rs b/src/repo.rs index d27c6a3..d266e98 100755 --- a/src/repo.rs +++ b/src/repo.rs @@ -23,6 +23,8 @@ use crate::domain; #[derive(Debug)] pub enum Error { Connect, + PrepareQuery, + QueryData, NotFound, InvalidData, InsertData, @@ -31,6 +33,9 @@ pub enum Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Error::Connect => f.write_str("Cannot connect to the repository"), + Error::PrepareQuery => f.write_str("Cannot prepare query"), + Error::QueryData => f.write_str("Cannot query data"), Error::NotFound => f.write_str("Cannot find data"), Error::InvalidData => f.write_str("Invalid data format"), Error::InsertData => f.write_str("Cannot insert data"), diff --git a/src/repo/sqlite.rs b/src/repo/sqlite.rs index 51b9aac..3846d22 100644 --- a/src/repo/sqlite.rs +++ b/src/repo/sqlite.rs @@ -1,9 +1,52 @@ +use std::path::PathBuf; + use rusqlite::Connection; use xdg::BaseDirectories; use crate::domain; use crate::repo::{Error, Repository}; +struct Task { + id: i64, + name: String, + project: Option, + link: Option, + dir_path: Option, + + current: bool, + + created_at: time::OffsetDateTime, + finished_at: Option, +} + +impl From for domain::Task { + fn from(repo: Task) -> Self { + Self { + name: repo.name, + project: repo.project, + link: repo.link, + dir_path: repo.dir_path.map(PathBuf::from), + } + } +} + +impl<'r> TryFrom<&'r rusqlite::Row<'_>> for Task { + type Error = rusqlite::Error; + + fn try_from(row: &'r rusqlite::Row<'_>) -> Result { + Ok(Self { + id: row.get("id")?, + name: row.get("name")?, + 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")?, + }) + } +} + const SCHEMA_FILE: &str = "schema.sql"; pub struct SqliteRepo { @@ -28,8 +71,21 @@ impl Repository for SqliteRepo { } fn get_tasks(&self) -> Result, Error> { - todo!() + let mut stmt = self + .conn + .prepare("SELECT * FROM active_tasks") + .map_err(|_| Error::PrepareQuery)?; + + let rows = stmt + .query_map([], |row| Task::try_from(row)) + .map_err(|_| Error::QueryData)?; + + rows.into_iter() + .map(|db_task| db_task.map(From::from).map_err(|_| Error::QueryData)) + .collect::, Error>>() + .map_err(|_| Error::InvalidData) } + fn remove_task(&self, id: domain::TaskId) -> Result { todo!() }