Skip to content

Commit

Permalink
refactor: add ports and adapters (hex architecture) structure (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
subotic authored Sep 23, 2023
1 parent 7db8526 commit bc9b022
Show file tree
Hide file tree
Showing 35 changed files with 219 additions and 47 deletions.
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ tracing-test.workspace = true
url.workspace = true

[[bin]]
name = "dsp_meta"
name = "dsp_meta_cli"
test = false
doc = false

[[bin]]
name = "dsp_meta_server"
test = false
doc = false
File renamed without changes.
File renamed without changes.
17 changes: 17 additions & 0 deletions src/bin/dsp_meta_server/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use dsp_meta::errors::DspMetaError;
use tracing::{trace, Level};
use tracing_subscriber::FmtSubscriber;

fn main() -> Result<(), DspMetaError> {
// configure tracing library
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::TRACE)
.finish();

tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");

trace!("Hello, world!");

dsp_meta::operation::server::run();
Ok(())
}
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/dataset.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::domain::value::Title;
use crate::errors::DspMetaError;

#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub struct Dataset {
pub title: Title,
}
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/grant.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Grant {
id: String,
}
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub(crate) mod dataset;
pub(crate) mod grant;
pub(crate) mod metadata;
mod organization;
mod person;
mod project;
pub mod project_metadata;
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/organization.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Organization {
id: String,
}
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/person.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(Debug, Default, PartialEq)]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Person {
id: String,
}
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/entity/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::domain::value::{
};
use crate::errors::DspMetaError;

#[derive(Debug, Default, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Project {
pub created_at: CreatedAt,
pub created_by: CreatedBy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::domain::value::version::Version;
use crate::errors::DspMetaError;

/// The Metadata struct represents the metadata of a DSP project.
#[derive(Debug, Default, PartialEq)]
pub struct Metadata {
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ProjectMetadata {
pub version: Version,
pub project: Project,
pub datasets: Vec<Dataset>,
Expand All @@ -17,7 +17,7 @@ pub struct Metadata {
pub persons: Vec<Person>,
}

impl TryFrom<&hcl::Body> for Metadata {
impl TryFrom<&hcl::Body> for ProjectMetadata {
type Error = DspMetaError;

fn try_from(body: &hcl::Body) -> Result<Self, Self::Error> {
Expand Down Expand Up @@ -54,7 +54,7 @@ impl TryFrom<&hcl::Body> for Metadata {
}
}

let metadata = Metadata {
let metadata = ProjectMetadata {
version: version.ok_or_else(|| {
DspMetaError::ParseVersion("Version attribute is not provided.".to_string())
})?,
Expand Down
8 changes: 4 additions & 4 deletions src/dsp_meta/domain/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mod convert;
pub(crate) mod entity;
pub mod entity;
pub mod value;

#[cfg(test)]
mod tests {
use hcl::body;

use crate::domain::entity::metadata::Metadata;
use crate::domain::entity::project_metadata::ProjectMetadata;

#[test]
fn try_from_multiple_projects_error() {
Expand All @@ -19,15 +19,15 @@ mod tests {
}
);

let project = Metadata::try_from(&input);
let project = ProjectMetadata::try_from(&input);
assert!(project.is_err());
}

#[test]
fn try_from_no_project_error() {
let input = body!();

let project = Metadata::try_from(&input);
let project = ProjectMetadata::try_from(&input);
assert!(project.is_err());
}
}
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/discipline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::errors::DspMetaError;
/// url = "https://skos.um.es/unesco6/5501"
/// }
/// ```
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum Discipline {
Skos(RefData),
Snf(RefData),
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::errors::DspMetaError;

const KEYWORD_BLOCK_IDENTIFIER: &str = "keyword";

#[derive(Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Keyword(HashMap<IsoCode, String>);

impl TryFrom<&hcl::Block> for Keyword {
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/lang_text_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::domain::value::iso_code::IsoCode;
use crate::errors::DspMetaError;

/// Represents multiple strings in different languages.
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub struct LangTextData(pub HashMap<IsoCode, String>);

/// FIXME: Move to the API layer where the service adapter will be implemented
Expand Down
4 changes: 2 additions & 2 deletions src/dsp_meta/domain/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub struct StartDate(pub String);
#[derive(Debug, Default, Clone, PartialEq)]
pub struct EndDate(pub String);

#[derive(Debug, Default, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ContactPoint(pub String);

#[derive(Debug, Default, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Title(pub String);
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/publication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::errors::DspMetaError;

const PUBLICATION_BLOCK_IDENTIFIER: &str = "publication";

#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub enum Publication {
SimpleText(SimpleTextData),
}
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/ref_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use tracing::warn;

use crate::errors::DspMetaError;

#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub struct RefData {
pub(crate) ref_id: String,
pub(crate) description: String,
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/simple_text_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::errors::DspMetaError;

const TEXT_ATTRIBUTE_IDENTIFIER: &str = "text";

#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct SimpleTextData(pub String);

impl TryFrom<Vec<&hcl::Attribute>> for SimpleTextData {
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const LABEL_ATTRIBUTE_KEY: &str = "label";
///
/// Use [`Attribute::new`] to construct an [`Attribute`] from a value that is convertible to this
/// crate's [`Expression`] type.
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Url {
pub href: url::Url,
pub label: String,
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_meta/domain/value/version.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hcl::Expression;

#[derive(Debug, Default, PartialEq)]
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Version(pub u64);

/// Given a list of attributes, try to extract the version.
Expand Down
1 change: 1 addition & 0 deletions src/dsp_meta/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub enum DspMetaError {
ParseProject(String),
ParseDataset(String),
CreateValueObject(String),
NotFound,
}

impl From<io::Error> for DspMetaError {
Expand Down
15 changes: 2 additions & 13 deletions src/dsp_meta/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
pub mod domain;
pub mod errors;
pub mod operation;

use std::path::Path;

use domain::entity::metadata::Metadata;

use crate::errors::DspMetaError;

pub fn load<P: AsRef<Path>>(path: P) -> Result<Metadata, DspMetaError> {
let input = std::fs::read_to_string(path)?;
let body: hcl::Body = hcl::from_str(&input)?;
let metadata = Metadata::try_from(&body)?;
Ok(metadata)
}
mod repo;
mod service;

#[cfg(test)]
mod tests {
Expand Down
6 changes: 4 additions & 2 deletions src/dsp_meta/operation/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use std::path::Path;

use tracing::info;

use crate::domain::entity::project_metadata::ProjectMetadata;
use crate::errors::DspMetaError;
use crate::load;

pub fn convert<P: AsRef<Path>>(source_path: &P, _target_path: &P) -> Result<(), DspMetaError> {
info!("Hello from convert!");
let _ = load(source_path)?;
let input = std::fs::read_to_string(source_path)?;
let body: hcl::Body = hcl::from_str(&input)?;
let _metadata = ProjectMetadata::try_from(&body)?;

Ok(())
}
1 change: 1 addition & 0 deletions src/dsp_meta/operation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod convert;
pub mod server;
pub mod validate;
9 changes: 9 additions & 0 deletions src/dsp_meta/operation/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use tracing::trace;

use crate::repo::project_metadata_repository::ProjectMetadataRepository;
use crate::service::project_metadata_service::ProjectMetadataService;

pub fn run() {
trace!("tracing from dsp_meta::core::server::run()");
let _project_metadata_service = ProjectMetadataService::new(ProjectMetadataRepository::new());
}
6 changes: 4 additions & 2 deletions src/dsp_meta/operation/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use std::path::Path;

use tracing::info;

use crate::domain::entity::project_metadata::ProjectMetadata;
use crate::errors::DspMetaError;
use crate::load;

/// Read projects definition from .toml
pub fn validate<P: AsRef<Path>>(project_path: &P) -> Result<(), DspMetaError> {
info!("Hello from validate!");
let _ = load(project_path)?;
let input = std::fs::read_to_string(project_path)?;
let body: hcl::Body = hcl::from_str(&input)?;
let _metadata = ProjectMetadata::try_from(&body)?;
Ok(())
}

Expand Down
1 change: 1 addition & 0 deletions src/dsp_meta/repo/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod project_metadata_repository;
73 changes: 73 additions & 0 deletions src/dsp_meta/repo/project_metadata_repository.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use tracing::trace;

use crate::domain::entity::project_metadata::ProjectMetadata;
use crate::domain::value::Shortcode;
use crate::errors::DspMetaError;
use crate::service::project_metadata_repository_contract::ProjectMetadataRepositoryContract;

pub struct ProjectMetadataRepository {
db: Arc<RwLock<HashMap<String, ProjectMetadata>>>,
}

impl ProjectMetadataRepository {
pub fn new() -> Self {
trace!("ProjectMetadataRepository::new");
let db: Arc<RwLock<HashMap<String, ProjectMetadata>>> =
Arc::new(RwLock::new(HashMap::new()));
Self { db }
}
}

impl ProjectMetadataRepositoryContract for ProjectMetadataRepository {
fn get_by_shortcode(&self, shortcode: Shortcode) -> Result<ProjectMetadata, DspMetaError> {
let db = self.db.read().unwrap();
match db.get(shortcode.0.as_str()) {
Some(metadata) => Ok(metadata.clone()),
None => Err(DspMetaError::NotFound),
}
}

fn get_all(&self) -> Result<Vec<ProjectMetadata>, DspMetaError> {
let mut result: Vec<ProjectMetadata> = vec![];
let db = self.db.read().unwrap();

for project_metadata in db.values() {
result.push(project_metadata.clone());
}

Ok(result)
}

fn store(&self, shortcode: Shortcode, metadata: ProjectMetadata) -> Result<(), DspMetaError> {
let mut db = self.db.write().unwrap();
db.insert(shortcode.0, metadata);
Ok(())
}

fn delete(&self, shortcode: Shortcode) -> Result<(), DspMetaError> {
let mut db = self.db.write().unwrap();

match db.remove(shortcode.0.as_str()) {
Some(_) => Ok(()),
None => Ok(()),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn successfully_store_project_metadata() {
let metadata = ProjectMetadata::default();
let shortcode = Shortcode("1234".to_owned());

let repo = ProjectMetadataRepository::new();
let result = repo.store(shortcode, metadata);
assert!(result.is_ok());
}
}
3 changes: 3 additions & 0 deletions src/dsp_meta/service/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub(crate) mod project_metadata_api_contract;
pub(crate) mod project_metadata_repository_contract;
pub(crate) mod project_metadata_service;
10 changes: 10 additions & 0 deletions src/dsp_meta/service/project_metadata_api_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::domain::entity::project_metadata::ProjectMetadata;
use crate::domain::value::Shortcode;
use crate::errors::DspMetaError;

pub trait ProjectMetadataApiContract {
fn get_by_shortcode(&self, id: Shortcode) -> Result<ProjectMetadata, DspMetaError>;
fn get_all(&self) -> Result<Vec<ProjectMetadata>, DspMetaError>;
fn store(&self, id: Shortcode, metadata: ProjectMetadata) -> Result<(), DspMetaError>;
fn delete(&self, id: Shortcode) -> Result<(), DspMetaError>;
}
Loading

0 comments on commit bc9b022

Please sign in to comment.