Skip to content

Commit

Permalink
implement activity traits I
Browse files Browse the repository at this point in the history
Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com>
  • Loading branch information
simonsan committed Mar 25, 2024
1 parent 4bd98c3 commit 405f80a
Show file tree
Hide file tree
Showing 15 changed files with 615 additions and 76 deletions.
35 changes: 2 additions & 33 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ clap_complete = "4.5.1"
clap_complete_nushell = "4.5.1"
derive_more = { version = "0.99.17", default-features = false }
dialoguer = "0.11.0"
diesel = "2.1.5"
directories = "5.0.1"
displaydoc = "0.2.4"
dotenvy = "0.15.7"
Expand Down Expand Up @@ -102,13 +101,12 @@ clap = { workspace = true, features = ["env", "wrap_help", "derive"] }
clap_complete = { workspace = true }
clap_complete_nushell = { workspace = true }
dialoguer = { workspace = true, features = ["history", "fuzzy-select"] }
diesel = { workspace = true, features = ["sqlite"] }
directories = { workspace = true }
eyre = { workspace = true }
human-panic = { workspace = true }
pace_cli = { workspace = true }
pace_core = { workspace = true, features = ["cli"] }
pace_time = { workspace = true, features = ["cli"] }
pace_core = { workspace = true, features = ["cli", "db"] }
pace_time = { workspace = true, features = ["cli", "db"] }
serde = { workspace = true }
serde_derive = { workspace = true }
thiserror = { workspace = true }
Expand Down
9 changes: 5 additions & 4 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ include = [
]

[features]
default = ["cli"]
default = ["cli", "db"]
cli = ["clap"]
sqlite = ["dep:rusqlite", "dep:libsqlite3-sys"]
db = ["rusqlite"]
rusqlite = ["dep:rusqlite", "dep:libsqlite3-sys"]
clap = ["dep:clap"]

[dependencies]
Expand All @@ -40,10 +41,10 @@ merge = { workspace = true }
miette = { workspace = true, features = ["fancy"] }
once_cell = { workspace = true }
open = { workspace = true }
pace_time = { workspace = true }
pace_time = { workspace = true, features = ["rusqlite"] }
parking_lot = { workspace = true, features = ["deadlock_detection"] }
rayon = { workspace = true }
rusqlite = { workspace = true, optional = true, features = ["bundled"] }
rusqlite = { workspace = true, optional = true, features = ["bundled", "chrono"] }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
Expand Down
5 changes: 2 additions & 3 deletions crates/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ This crate exposes a few features for controlling dependency usage:
- **cli** - Enables support for CLI features by enabling `merge` and `clap`
features. *This feature is enabled by default*.

- **sqlite** - Enables a dependency on the `rusqlite` crate and enables
persistence to a SQLite database. *This feature is disabled by default as it's
not yet implemented*.
- **rusqlite** - Enables a dependency on the `rusqlite` crate and enables
persistence to a SQLite database. *This feature is enabled by default*.

## Examples

Expand Down
9 changes: 8 additions & 1 deletion crates/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,21 @@ pub struct ExportConfig {
/// Default: `sqlite`
///
/// Options: `sqlite`, `postgres`, `mysql`, `sql-server`
#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)]
#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default, displaydoc::Display, EnumString)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum DatabaseEngineKind {
#[default]
/// SQLite
Sqlite,

/// Postgres
Postgres,

/// MySQL
Mysql,

/// SQL Server
SqlServer,
}

Expand Down
19 changes: 19 additions & 0 deletions crates/core/src/domain/activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use pace_time::{
date_time::PaceDateTime,
duration::{calculate_duration, duration_to_str, PaceDuration},
};

use serde_derive::{Deserialize, Serialize};
use std::{collections::HashSet, fmt::Display};
use strum_macros::EnumString;
Expand Down Expand Up @@ -81,8 +82,10 @@ impl From<(ActivityGuid, Activity)> for ActivityItem {
PartialOrd,
Ord,
EnumString,
strum::Display,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
// #[serde(untagged)]
pub enum ActivityKind {
/// A generic activity
Expand Down Expand Up @@ -270,6 +273,10 @@ impl ActivityEndOptions {
pub const fn new(end: PaceDateTime, duration: PaceDuration) -> Self {
Self { end, duration }
}

pub fn as_tuple(&self) -> (PaceDateTime, PaceDuration) {
(self.end, self.duration)
}
}

#[derive(
Expand Down Expand Up @@ -307,6 +314,18 @@ impl ActivityKindOptions {
#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialEq, PartialOrd, Eq, Copy, Hash)]
pub struct ActivityGuid(Ulid);

impl ActivityGuid {
#[must_use]
pub fn new() -> Self {
Self(Ulid::new())
}

#[must_use]
pub fn with_id(id: Ulid) -> Self {
Self(id)
}
}

impl Display for ActivityGuid {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
Expand Down
17 changes: 16 additions & 1 deletion crates/core/src/domain/status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use serde_derive::{Deserialize, Serialize};
use strum::EnumString;

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "kebab-case")]
Expand All @@ -16,8 +17,22 @@ pub enum TaskStatus {
Waiting,
}

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[derive(
Debug,
Clone,
Copy,
Default,
Serialize,
Deserialize,
PartialEq,
Eq,
PartialOrd,
Ord,
EnumString,
strum::Display,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum ActivityStatusKind {
/// The initial state of an activity once it's created in the system but not yet started.
#[default]
Expand Down
45 changes: 35 additions & 10 deletions crates/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use pace_time::error::PaceTimeErrorKind;
use std::{error::Error, io, path::PathBuf};
use thiserror::Error;

use crate::domain::activity::{Activity, ActivityGuid};
use crate::{
config::DatabaseEngineKind,
domain::activity::{Activity, ActivityGuid},
};

/// Result type that is being returned from test functions and methods that can fail and thus have errors.
pub type TestResult<T> = Result<T, Box<dyn Error + 'static>>;
Expand Down Expand Up @@ -163,10 +166,17 @@ pub enum PaceErrorKind {
#[error(transparent)]
Template(#[from] TemplatingErrorKind),

/// SQLite database error: {0}
/// SQLite error: {0}
#[error(transparent)]
#[cfg(feature = "sqlite")]
SQLite(#[from] SqliteDatabaseStoreErrorKind),
#[cfg(feature = "rusqlite")]
SQLite(#[from] rusqlite::Error),

/// Database error: {0}
#[error(transparent)]
Database(#[from] DatabaseErrorKind),

/// Database storage not configured
DatabaseStorageNotConfigured,
}

/// [`ActivityLogErrorKind`] describes the errors that can happen while dealing with the activity log.
Expand Down Expand Up @@ -306,11 +316,25 @@ pub enum ActivityStoreErrorKind {

/// [`SqliteDatabaseStoreErrorKind`] describes the errors that can happen while dealing with the SQLite database.
#[non_exhaustive]
#[cfg(feature = "sqlite")]
#[derive(Error, Debug, Display)]
pub enum SqliteDatabaseStoreErrorKind {
/// Error connecting to database: {0}
ConnectionFailed(String),
pub enum DatabaseErrorKind {
/// Error connecting to database: {0} - {1}
ConnectionFailed(String, String),

/// No connection string provided
NoConnectionString,

/// No configuration settings provided in configuration file, please set them up with `pace setup config`
NoConfigSettings,

/// This database engine is currently not supported: {0}
UnsupportedDatabaseEngine(DatabaseEngineKind),

/// Activity with id {0} not found
ActivityNotFound(ActivityGuid),

/// Failed to create activity: {0}
ActivityCreationFailed(Activity),
}

trait PaceErrorMarker: Error {}
Expand All @@ -321,11 +345,12 @@ impl PaceErrorMarker for toml::ser::Error {}
impl PaceErrorMarker for serde_json::Error {}
impl PaceErrorMarker for chrono::ParseError {}
impl PaceErrorMarker for chrono::OutOfRangeError {}
#[cfg(feature = "rusqlite")]
impl PaceErrorMarker for rusqlite::Error {}
impl PaceErrorMarker for ActivityLogErrorKind {}
impl PaceErrorMarker for PaceTimeErrorKind {}
impl PaceErrorMarker for ActivityStoreErrorKind {}
#[cfg(feature = "sqlite")]
impl PaceErrorMarker for SqliteDatabaseStoreErrorKind {}
impl PaceErrorMarker for DatabaseErrorKind {}
impl PaceErrorMarker for TemplatingErrorKind {}

impl<E> From<E> for PaceError
Expand Down
44 changes: 39 additions & 5 deletions crates/core/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ use crate::{
hold::HoldOptions, resume::ResumeOptions, DeleteOptions, EndOptions, KeywordOptions,
UpdateOptions,
},
config::{ActivityLogStorageKind, PaceConfig},
config::{ActivityLogStorageKind, DatabaseEngineKind, PaceConfig},
domain::{
activity::{Activity, ActivityGuid, ActivityItem, ActivityKind},
filter::{ActivityFilterKind, FilteredActivities},
status::ActivityStatusKind,
},
error::{PaceErrorKind, PaceOptResult, PaceResult},
error::{DatabaseErrorKind, PaceErrorKind, PaceOptResult, PaceResult},
service::activity_store::ActivityStore,
storage::{file::TomlActivityStorage, in_memory::InMemoryActivityStorage},
storage::{
file::TomlActivityStorage, in_memory::InMemoryActivityStorage,
sqlite::SqliteActivityStorage,
},
};

/// A type of storage that can be synced to a persistent medium - a file
Expand All @@ -27,9 +30,10 @@ pub mod file;
/// An in-memory storage backend for activities.
pub mod in_memory;

#[cfg(feature = "sqlite")]
#[cfg(feature = "rusqlite")]
pub mod sqlite;


/// Get the storage backend from the configuration.
///
/// # Arguments
Expand All @@ -49,7 +53,35 @@ pub fn get_storage_from_config(config: &PaceConfig) -> PaceResult<Arc<StorageKin
TomlActivityStorage::new(config.general().activity_log_options().path())?.into()
}
ActivityLogStorageKind::Database => {
return Err(PaceErrorKind::DatabaseStorageNotImplemented.into())
if config.database().is_some() {
let Some(db_config) = config.database() else {
return Err(DatabaseErrorKind::NoConfigSettings.into());
};

match db_config.engine() {
DatabaseEngineKind::Sqlite => {
#[cfg(feature = "rusqlite")]
{
let connection_string = config
.database()
.as_ref()
.ok_or(DatabaseErrorKind::NoConnectionString)?
.connection_string();

debug!("Connecting to database: {}", &connection_string);

SqliteActivityStorage::new(connection_string.clone())?.into()
}
#[cfg(not(feature = "rusqlite"))]
return Err(PaceErrorKind::DatabaseStorageNotImplemented.into());
}
engine => {
return Err(DatabaseErrorKind::UnsupportedDatabaseEngine(*engine).into())
}
}
}

return Err(PaceErrorKind::DatabaseStorageNotConfigured.into());
}
#[cfg(test)]
ActivityLogStorageKind::InMemory => InMemoryActivityStorage::new().into(),
Expand All @@ -65,6 +97,7 @@ pub enum StorageKind {
ActivityStore,
InMemoryActivityStorage,
TomlActivityStorage,
SqliteActivityStorage,
}

impl Display for StorageKind {
Expand All @@ -75,6 +108,7 @@ impl Display for StorageKind {
write!(f, "StorageKind: InMemoryActivityStorage")
}
Self::TomlActivityStorage(_) => write!(f, "StorageKind: TomlActivityStorage"),
Self::SqliteActivityStorage(_) => write!(f, "StorageKind: SqliteActivityStorage"),
}
}
}
Expand Down
Loading

0 comments on commit 405f80a

Please sign in to comment.