acorn-schema 0.4.0

Portable ACORN schema, validation, and codecs
use crate::pid::{PID, RRID};
use crate::research_activity::{TypedIdentifier, TypedRelatedResource};
use crate::standard::crosswalk::{ConversionWarning, Crosswalk, CrosswalkError, CrosswalkSchema};
use crate::standard::datacite::{RelatedIdentifier, RelatedIdentifierType, RelationType, ResourceTypeGeneral};
use acorn_core::prelude::alloc::{vec, String, ToString, Vec};

impl Crosswalk<RelatedIdentifier> for TypedRelatedResource {
    fn crosswalk(&self) -> Result<(RelatedIdentifier, Vec<ConversionWarning>), CrosswalkError> {
        let has_rrid_scheme = self.identifier.scheme.as_deref().is_some_and(|scheme| PID::from(scheme) == PID::RRID);
        match has_rrid_scheme {
            | true => self
                .identifier
                .value
                .parse::<RRID>()
                .map_err(|why| CrosswalkError::TransformationFailed {
                    field: "relatedResources[].identifier.value".to_string(),
                    reason: why.to_string(),
                })
                .and_then(|identifier| {
                    self.relation_type
                        .parse::<RelationType>()
                        .map_err(|why| CrosswalkError::TransformationFailed {
                            field: "relatedResources[].relationType".to_string(),
                            reason: why.to_string(),
                        })
                        .and_then(|relation_type| {
                            self.resource_type_general
                                .as_deref()
                                .map(|value| {
                                    value.parse::<ResourceTypeGeneral>().map_err(|why| CrosswalkError::TransformationFailed {
                                        field: "relatedResources[].resourceTypeGeneral".to_string(),
                                        reason: why.to_string(),
                                    })
                                })
                                .transpose()
                                .map(|resource_type_general| {
                                    let warnings = self
                                        .category
                                        .as_ref()
                                        .map(|_| {
                                            vec![ConversionWarning::no_equivalent(
                                                CrosswalkSchema::Rad,
                                                CrosswalkSchema::DataCite,
                                                "relatedResources[].category",
                                            )]
                                        })
                                        .unwrap_or_default();
                                    let related = RelatedIdentifier::init()
                                        .related_identifier(identifier)
                                        .related_identifier_type(RelatedIdentifierType::Rrid)
                                        .relation_type(relation_type)
                                        .maybe_scheme_uri(self.identifier.scheme_uri.clone())
                                        .maybe_resource_type_general(resource_type_general)
                                        .maybe_relation_type_information(self.relation_type_information.clone())
                                        .build();
                                    (related, warnings)
                                })
                        })
                }),
            | false => Err(CrosswalkError::TransformationFailed {
                field: "relatedResources[].identifier.scheme".to_string(),
                reason: "RRID crosswalk requires identifier scheme RRID".to_string(),
            }),
        }
    }
}
impl Crosswalk<TypedRelatedResource> for RelatedIdentifier {
    fn crosswalk(&self) -> Result<(TypedRelatedResource, Vec<ConversionWarning>), CrosswalkError> {
        match &self.related_identifier_type {
            | Some(RelatedIdentifierType::Rrid) => self
                .related_identifier
                .parse::<RRID>()
                .map_err(|why| CrosswalkError::TransformationFailed {
                    field: "relatedIdentifiers[].relatedIdentifier".to_string(),
                    reason: why.to_string(),
                })
                .and_then(|identifier| {
                    self.relation_type
                        .as_ref()
                        .ok_or_else(|| CrosswalkError::MissingRequiredField("relatedIdentifiers[].relationType".to_string()))
                        .map(|relation_type| relation_type.to_string())
                        .map(|relation_type| {
                            let resource_type_general = self.resource_type_general.as_ref().map(ToString::to_string);
                            let locations = [
                                self.related_metadata_scheme
                                    .as_ref()
                                    .map(|_| "relatedIdentifiers[].relatedMetadataScheme"),
                                self.scheme_type.as_ref().map(|_| "relatedIdentifiers[].schemeType"),
                            ];
                            let warnings = locations
                                .into_iter()
                                .flatten()
                                .map(|field| ConversionWarning::no_equivalent(CrosswalkSchema::DataCite, CrosswalkSchema::Rad, field))
                                .collect();
                            let value = TypedIdentifier::init()
                                .value(identifier)
                                .scheme("RRID")
                                .maybe_scheme_uri(self.scheme_uri.clone())
                                .build();
                            let related = TypedRelatedResource::init()
                                .identifier(value)
                                .relation_type(relation_type)
                                .maybe_relation_type_information(self.relation_type_information.clone())
                                .maybe_resource_type_general(resource_type_general)
                                .build();
                            (related, warnings)
                        })
                }),
            | _ => Err(CrosswalkError::TransformationFailed {
                field: "relatedIdentifiers[].relatedIdentifierType".to_string(),
                reason: "RRID crosswalk requires related identifier type RRID".to_string(),
            }),
        }
    }
}