Skip to content

Commit

Permalink
add conversion of project - discipline (ongoing)
Browse files Browse the repository at this point in the history
  • Loading branch information
subotic committed Sep 14, 2023
1 parent 43cc6cd commit 9025a1d
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 96 deletions.
97 changes: 82 additions & 15 deletions src/dsp_meta/domain/convert/project.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
use clap::builder::Str;
use hcl::Expression;
use std::collections::HashMap;
use tracing::warn;

use crate::domain::value::{AlternativeName, ContactPoint, CreatedAt, CreatedBy, Description, Discipline, EndDate, HowToCite, IsoCode, Keyword, LangString, Name, Publication, Shortcode, StartDate, TeaserText, URL};
use crate::domain::value::discipline::{Discipline, DisciplineData};
use crate::domain::value::iso_code::IsoCode;
use crate::domain::value::{
AlternativeName, ContactPoint, CreatedAt, CreatedBy, Description, EndDate, HowToCite, Keyword,
LangString, Name, Publication, Shortcode, StartDate, TeaserText, URL,
};
use crate::errors::DspMetaError;

pub struct ExtractedProjectAttributes {
Expand Down Expand Up @@ -333,26 +340,86 @@ impl TryFrom<&hcl::Block> for Discipline {
return Err(DspMetaError::CreateValueObject(msg));
}

if block.labels.len() != 2 {
return Err(DspMetaError::CreateValueObject("The passed number of block labels is not correct. Expected '2', namely 'vocabulary' and 'id'.".to_string()));
if block.labels.len() != 1 {
return Err(DspMetaError::CreateValueObject("The passed number of block labels is not correct. Expected '1', namely 'reference data type' (e.g., 'skos').".to_string()));
}

let vocabulary = block.labels.get(0).ok_or_else(|| {
let reference_data_type = block.labels.first().ok_or_else(|| {
DspMetaError::CreateValueObject(
"The passed discipline block is missing the vocabulary label.".to_string(),
"The passed discipline block is missing the reference data type label.".to_string(),
)
})?;

let id = block.labels.get(1).ok_or_else(|| {
DspMetaError::CreateValueObject(
"The passed discipline block is missing the id label.".to_string(),
)
})?;

Ok(Discipline {
vocabulary: vocabulary.to_owned(),
id: id.to_owned(),
})
match reference_data_type.as_str() {
"skos" || "snf" => {
let mut ref_id: Option<String> = None;
let mut description: Option<String> = None;
let mut url: Option<url::Url> = None;
let attrs: Vec<&hcl::Attribute> = block.body.attributes().collect();
for attr in attrs {
match attr.key() {
"ref_id" => {
ref_id = match attr.expr() {
Expression::String(value) => Ok(Some(value.to_owned())),
_ => Err(DspMetaError::CreateValueObject(
"The passed discipline block ref_id attribute is not of String type.".to_string(),
)),
}?;
}
"description" => {
description = match attr.expr() {
Expression::String(value) => Ok(Some(value.to_owned())),
_ => Err(DspMetaError::CreateValueObject(
"The passed discipline block description attribute is not of String type.".to_string(),
)),
}?;
}
"url" => {
url = match attr.expr() {
Expression::String(value) => Ok(Some(url::Url::parse(value).map_err(|_| {
DspMetaError::CreateValueObject("The passed discipline block url attribute is not a valid url.".to_string())
})?)),
_ => Err(DspMetaError::CreateValueObject(
"The passed discipline block url attribute is not of String type.".to_string(),
)),
}?;
}
_ => {
warn!("Parse error: unknown attribute '{}'.", attr.key());
}
}
}
Ok(Discipline::Skos {
ref_id: ref_id.ok_or_else(|| {
DspMetaError::CreateValueObject(
"The passed discipline block is missing the ref_id attribute.".to_string(),
)
})?,
description: description.ok_or_else(|| {
DspMetaError::CreateValueObject(
"The passed discipline block is missing the description attribute.".to_string(),
)
})?,
url: url.ok_or_else(|| {
DspMetaError::CreateValueObject(
"The passed discipline block is missing the url attribute.".to_string(),
)
})?,
})
}
"text" => {
let mut descriptions: HashMap<IsoCode, String> = HashMap::new();
let attrs: Vec<&hcl::Attribute> = block.body.attributes().collect();
for attr in attrs {
let lang_string = LangString::try_from(attr)?;
descriptions.insert(lang_string.iso_code, lang_string.string);
}
Ok(Discipline::Text(descriptions))
}
_ => {
Err(DspMetaError::CreateValueObject("The passed discipline block is missing the correct reference data type label: 'skos', 'snf', or 'text'.".to_string()))
}
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/dsp_meta/domain/entity/project.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::domain::convert::project::{ExtractedProjectAttributes, ExtractedProjectBlocks};
use crate::domain::value::discipline::Discipline;
use crate::domain::value::{
AlternativeName, ContactPoint, CreatedAt, CreatedBy, Description, Discipline, EndDate,
HowToCite, Keyword, Name, Publication, Shortcode, StartDate, TeaserText, URL,
AlternativeName, ContactPoint, CreatedAt, CreatedBy, Description, EndDate, HowToCite, Keyword,
Name, Publication, Shortcode, StartDate, TeaserText, URL,
};
use crate::errors::DspMetaError;

Expand Down
51 changes: 51 additions & 0 deletions src/dsp_meta/domain/value/discipline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::domain::value::iso_code::IsoCode;
use crate::domain::value::LangString;
use hcl::Attribute;
use std::collections::HashMap;

/// The discipline of a project can be defined in two ways:
/// 1. A reference to a discipline defined in an external reference system (e.g. SNF or SKOS)
/// 2. A text description of the discipline
///
/// Example:
/// ```hcl
/// discipline skos {
/// ref_id = "https://skos.um.es/unesco6/5501"
/// description = "Local history"
/// url = "https://skos.um.es/unesco6/5501"
/// }
/// ```
/// would be represented as:
/// ```rust
/// use dsp_meta::domain::value::Discipline;
/// use dsp_meta::domain::value::Ref;
/// use std::collections::HashMap;
/// use url::Url;
/// Discipline::Snf(Ref{
/// ref_id: "https://skos.um.es/unesco6/5501".to_string(),
/// description: "Local history".to_string(),
/// url: Url::parse("https://skos.um.es/unesco6/5501").unwrap(),
/// })
/// ```
#[derive(Debug, PartialEq)]
pub enum Discipline {
Skos {
ref_id: String,
description: String,
url: url::Url,
},
Snf {
ref_id: String,
description: String,
url: url::Url,
},
Text(HashMap<IsoCode, String>),
}

impl TryFrom<Vec<&hcl::Attribute>> for Discipline {
type Error = ();

fn try_from(value: Vec<&Attribute>) -> Result<Self, Self::Error> {
todo!()
}
}
67 changes: 67 additions & 0 deletions src/dsp_meta/domain/value/iso_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::errors::DspMetaError;
use std::fmt::{Display, Formatter};

/// Language codes according to ISO 639-1
/// Not an exhaustive list.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
pub enum IsoCode {
#[default]
DE, // German
EN, // English
FR, // French
IT, // Italian
ES, // Spanish
PT, // Portuguese
NL, // Dutch
PL, // Polish
RU, // Russian
JA, // Japanese
ZH, // Chinese
AR, // Arabic
FA, // Persian
}

impl Display for IsoCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IsoCode::DE => write!(f, "de"),
IsoCode::EN => write!(f, "en"),
IsoCode::FR => write!(f, "fr"),
IsoCode::IT => write!(f, "it"),
IsoCode::ES => write!(f, "es"),
IsoCode::PT => write!(f, "pt"),
IsoCode::NL => write!(f, "nl"),
IsoCode::PL => write!(f, "pl"),
IsoCode::RU => write!(f, "ru"),
IsoCode::JA => write!(f, "ja"),
IsoCode::ZH => write!(f, "zh"),
IsoCode::AR => write!(f, "ar"),
IsoCode::FA => write!(f, "fa"),
}
}
}

impl TryFrom<&str> for IsoCode {
type Error = DspMetaError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"de" => Ok(IsoCode::DE),
"en" => Ok(IsoCode::EN),
"fr" => Ok(IsoCode::FR),
"it" => Ok(IsoCode::IT),
"es" => Ok(IsoCode::ES),
"pt" => Ok(IsoCode::PT),
"nl" => Ok(IsoCode::NL),
"pl" => Ok(IsoCode::PL),
"ru" => Ok(IsoCode::RU),
"ja" => Ok(IsoCode::JA),
"zh" => Ok(IsoCode::ZH),
"ar" => Ok(IsoCode::AR),
"fa" => Ok(IsoCode::FA),
_ => Err(DspMetaError::CreateValueObject(
"Creating an IsoCode failed because provided value is not allowed.".to_string(),
)),
}
}
}
83 changes: 4 additions & 79 deletions src/dsp_meta/domain/value/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::errors::DspMetaError;
use iso_code::IsoCode;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::fmt::Display;

pub(crate) mod discipline;
mod iso_code;
pub(crate) mod version;

#[derive(Debug, Default, Clone, PartialEq)]
Expand Down Expand Up @@ -72,71 +75,6 @@ impl Default for LangString {
}
}

/// Language codes according to ISO 639-1
/// Not an exhaustive list.
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
pub enum IsoCode {
#[default]
DE, // German
EN, // English
FR, // French
IT, // Italian
ES, // Spanish
PT, // Portuguese
NL, // Dutch
PL, // Polish
RU, // Russian
JA, // Japanese
ZH, // Chinese
AR, // Arabic
FA, // Persian
}

impl Display for IsoCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IsoCode::DE => write!(f, "de"),
IsoCode::EN => write!(f, "en"),
IsoCode::FR => write!(f, "fr"),
IsoCode::IT => write!(f, "it"),
IsoCode::ES => write!(f, "es"),
IsoCode::PT => write!(f, "pt"),
IsoCode::NL => write!(f, "nl"),
IsoCode::PL => write!(f, "pl"),
IsoCode::RU => write!(f, "ru"),
IsoCode::JA => write!(f, "ja"),
IsoCode::ZH => write!(f, "zh"),
IsoCode::AR => write!(f, "ar"),
IsoCode::FA => write!(f, "fa"),
}
}
}

impl TryFrom<&str> for IsoCode {
type Error = DspMetaError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"de" => Ok(IsoCode::DE),
"en" => Ok(IsoCode::EN),
"fr" => Ok(IsoCode::FR),
"it" => Ok(IsoCode::IT),
"es" => Ok(IsoCode::ES),
"pt" => Ok(IsoCode::PT),
"nl" => Ok(IsoCode::NL),
"pl" => Ok(IsoCode::PL),
"ru" => Ok(IsoCode::RU),
"ja" => Ok(IsoCode::JA),
"zh" => Ok(IsoCode::ZH),
"ar" => Ok(IsoCode::AR),
"fa" => Ok(IsoCode::FA),
_ => Err(DspMetaError::CreateValueObject(
"Creating an IsoCode failed because provided value is not allowed.".to_string(),
)),
}
}
}

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

Expand Down Expand Up @@ -241,19 +179,6 @@ pub struct ContactPoint(pub String);
#[derive(Debug, Default, PartialEq)]
pub struct Title(pub String);

#[derive(Debug, Default, PartialEq)]
pub struct Discipline {
pub discipline_type: DisciplineType,
pub description: LangString,
pub url: URL,
}

#[derive(Debug, Default, PartialEq)]
pub enum DisciplineType {
#[default]
Snf,
}

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

Expand Down

0 comments on commit 9025a1d

Please sign in to comment.