This commit is contained in:
Dmitriy Pleshevskiy 2022-08-26 23:19:37 +03:00
parent 7f53459116
commit 09b502404b
Signed by: pleshevskiy
GPG Key ID: 1B59187B161C0215
6 changed files with 85 additions and 18 deletions

17
Cargo.lock generated
View File

@ -284,8 +284,15 @@ dependencies = [
"libsqlite3-sys",
"smallvec",
"time",
"uuid",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "smallvec"
version = "1.9.0"
@ -311,6 +318,7 @@ dependencies = [
"log",
"rusqlite",
"time",
"uuid",
"xdg",
]
@ -364,6 +372,15 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]]
name = "uuid"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [
"sha1_smol",
]
[[package]]
name = "vcpkg"
version = "0.2.15"

View File

@ -13,8 +13,9 @@ 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", "time"] }
rusqlite = { version = "0.28.0", features = ["bundled", "time", "uuid"] }
time = "0.3"
uuid = { version = "1.1.2", features = ["v5"] }
xdg = "2.4.1"

View File

@ -0,0 +1,2 @@
ALTER TABLE tasks
ADD COLUMN uuid BLOB;

View File

@ -8,6 +8,7 @@ CREATE TABLE tasks (
project TEXT ,
link TEXT ,
dir_path TEXT ,
uuid BLOB ,
current BOOLEAN NOT NULL DEFAULT false,

View File

@ -64,7 +64,7 @@ pub struct UpdateTaskData {
}
pub trait Repository {
fn get_current_task_opt(&self) -> Result<Option<domain::CurrentTaskInfo>, Error>;
fn get_current_task_opt(&self) -> Result<Option<domain::Task>, Error>;
fn get_task_opt(&self, id: domain::TaskIdx) -> Result<Option<domain::Task>, Error>;

View File

@ -1,6 +1,7 @@
use std::path::PathBuf;
use rusqlite::{Connection, OptionalExtension};
use uuid::Uuid;
use xdg::BaseDirectories;
use crate::domain;
@ -18,7 +19,7 @@ struct Task {
*/
created_at: time::OffsetDateTime,
idx: i64,
uuid: uuid::Uuid,
}
impl From<Task> for domain::Task {
@ -48,7 +49,7 @@ impl<'r> TryFrom<&'r rusqlite::Row<'_>> for Task {
finished_at: row.get("finished_at")?,
*/
created_at: row.get("created_at")?,
idx: row.get("idx")?,
uuid: row.get("uuid")?,
})
}
}
@ -69,13 +70,10 @@ impl SqliteRepo {
}
impl Repository for SqliteRepo {
fn get_current_task_opt(&self) -> Result<Option<domain::CurrentTaskInfo>, Error> {
fn get_current_task_opt(&self) -> Result<Option<domain::Task>, Error> {
let db_task = self.get_current_task_opt_impl()?;
Ok(db_task.map(|db_task| domain::CurrentTaskInfo {
task_idx: db_task.idx as usize,
task: db_task.into(),
}))
Ok(db_task.map(|db_task| db_task.into()))
}
fn get_task_opt(&self, id: domain::TaskIdx) -> Result<Option<domain::Task>, Error> {
@ -118,11 +116,13 @@ impl Repository for SqliteRepo {
}
fn insert_task(&self, insert_data: super::InsertTaskData) -> Result<domain::Task, Error> {
let created_at = time::OffsetDateTime::now_utc();
let mut stmt = self
.conn
.prepare(
"INSERT INTO tasks (name, project, link, dir_path)
VALUES (?1, ?2, ?3, ?4)",
"INSERT INTO tasks (name, project, link, dir_path, created_at)
VALUES (?1, ?2, ?3, ?4, ?5)",
)
.map_err(|_| Error::PrepareQuery)?;
@ -134,6 +134,7 @@ impl Repository for SqliteRepo {
&insert_data
.dir_path
.and_then(|p| p.into_os_string().into_string().ok()),
&created_at,
))
.map_err(|_| Error::InsertData)?;
@ -243,7 +244,7 @@ impl SqliteRepo {
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")
.prepare("SELECT * FROM active_tasks WHERE current")
.map_err(|_| Error::PrepareQuery)?;
let row = stmt
@ -257,10 +258,14 @@ impl SqliteRepo {
macro_rules! run_migration {
($this:ident, $ver:ident = $version:expr) => {
run_migration!($this, $ver = $version => concat!("migrations/", $version));
run_migration!(
$this,
$ver = $version,
file = concat!("migrations/", $version)
);
};
($this:ident, $ver:ident = $version:expr => $sql_name:expr) => {
($this:ident, $ver:ident = $version:expr, file = $sql_name:expr) => {
$this
.conn
.execute_batch(&format!(
@ -279,6 +284,8 @@ pub enum MigrationError {
Upgrade,
DeleteInfo,
InsertInfo,
StartTransaction,
Db(Error),
}
impl std::fmt::Display for MigrationError {
@ -291,13 +298,14 @@ impl std::fmt::Display for MigrationError {
MigrationError::InsertInfo => {
f.write_str("Cannot insert a new tas information to the database")
}
MigrationError::Db(inner) => write!(f, "Database error: {}", inner),
}
}
}
impl std::error::Error for MigrationError {}
const LATEST_VERSION: i64 = 202208201623;
const LATEST_VERSION: i64 = 202208211624;
impl SqliteRepo {
pub fn upgrade(&self) -> Result<(), MigrationError> {
@ -305,12 +313,50 @@ impl SqliteRepo {
match version {
Some(LATEST_VERSION) => return Ok(()),
None => {
run_migration!(self, version = LATEST_VERSION => "schema");
run_migration!(self, version = LATEST_VERSION, file = "schema");
}
Some(v) => {
if v == 202208162308 {
_ => {
if version == Some(202208162308) {
run_migration!(self, version = 202208201623);
}
if version == Some(202208201623) {
run_migration!(self, version = 202208211624);
let mut stmt = self
.conn
.prepare("SELECT id, created_at, project, name, link FROM tasks")
.map_err(|_| MigrationError::Db(Error::PrepareQuery))?;
let rows = stmt
.query_map([], |row| {
let id: i64 = row.get("id")?;
let created_at: time::OffsetDateTime = row.get("created_at")?;
let project: Option<String> = row.get("project")?;
let name: String = row.get("name")?;
let link: Option<String> = row.get("link")?;
let uuid = Uuid::new_v5(
&Uuid::NAMESPACE_OID,
format!(
"p:{},n:{},l:{},d:{}",
project.unwrap_or_default(),
name,
link.unwrap_or_default(),
created_at.unix_timestamp()
)
.as_bytes(),
);
Ok((id, uuid))
})
.map_err(|_| MigrationError::Db(Error::QueryData))?;
for row in rows {
let (id, uuid) = row.map_err(|_| MigrationError::Db(Error::InvalidData))?;
this.conn
.execute("UPDATE tasks SET uuid = ?2 WHERE id = ?1", (uuid, id))
.map_err(|_| MigrationError::Db(Error::UpdateData))?;
}
}
}
}