pub mod model;
pub mod parser;
use crate::Result;
use serde::{Deserialize, Serialize};
#[cfg_attr(test, mockall::automock)]
pub trait OntologyParser {
fn parse(&self, json: &str) -> Result<OntologyData>;
fn validate(&self, data: &OntologyData) -> Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OntologyData {
pub metadata: OntologyMetadata,
pub classes: Vec<ClassNode>,
pub properties: Vec<Property>,
pub namespaces: Vec<Namespace>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OntologyMetadata {
pub iri: String,
pub version: Option<String>,
pub title: Option<String>,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ClassNode {
pub id: String,
pub iri: String,
pub label: String,
pub class_type: String,
pub equivalent: Vec<String>,
pub attributes: ClassAttributes,
pub ontology_meta: Option<ClassOntologyMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct ClassAttributes {
pub external: bool,
pub individuals: Option<usize>,
pub properties: std::collections::HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Property {
pub id: String,
pub iri: String,
pub label: String,
pub property_type: PropertyType,
pub domain: String,
pub range: String,
pub characteristics: PropertyCharacteristics,
pub inverse_of: Option<String>,
pub equivalent_to: Vec<String>,
pub disjoint_with: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum PropertyType {
ObjectProperty,
DatatypeProperty,
AnnotationProperty,
SpecialProperty(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct PropertyCharacteristics {
pub functional: bool,
pub inverse_functional: bool,
pub transitive: bool,
pub symmetric: bool,
pub cardinality: Option<Cardinality>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Cardinality {
pub min: Option<u32>,
pub max: Option<u32>,
pub exact: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Namespace {
pub prefix: String,
pub iri: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct ClassOntologyMetadata {
pub term_id: String,
pub preferred_term: Option<String>,
pub domain: Option<String>,
pub maturity: Option<String>,
pub status: Option<String>,
pub authority_score: Option<f32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ontology_data_creation() {
let metadata = OntologyMetadata {
iri: "http://example.org/ontology".to_string(),
version: Some("1.0".to_string()),
title: Some("Test Ontology".to_string()),
description: None,
};
let data = OntologyData {
metadata,
classes: vec![],
properties: vec![],
namespaces: vec![],
};
assert_eq!(data.classes.len(), 0);
assert_eq!(data.metadata.iri, "http://example.org/ontology");
}
#[test]
fn test_class_node_with_attributes() {
let class = ClassNode {
id: "class1".to_string(),
iri: "http://example.org/Class1".to_string(),
label: "Class 1".to_string(),
class_type: "owl:Class".to_string(),
equivalent: vec![],
attributes: ClassAttributes {
external: false,
individuals: Some(10),
properties: std::collections::HashMap::new(),
},
ontology_meta: None,
};
assert_eq!(class.attributes.individuals, Some(10));
assert!(!class.attributes.external);
}
#[test]
fn test_class_ontology_metadata() {
let meta = ClassOntologyMetadata {
term_id: "term1".to_string(),
preferred_term: Some("PreferredTerm".to_string()),
domain: Some("TechnologyDomain".to_string()),
maturity: Some("Stable".to_string()),
status: Some("Active".to_string()),
authority_score: Some(0.95),
};
assert_eq!(meta.term_id, "term1");
assert_eq!(meta.preferred_term, Some("PreferredTerm".to_string()));
assert_eq!(meta.authority_score, Some(0.95));
}
#[test]
fn test_property_with_characteristics() {
let prop = Property {
id: "prop1".to_string(),
iri: "http://example.org/prop1".to_string(),
label: "Property 1".to_string(),
property_type: PropertyType::ObjectProperty,
domain: "class1".to_string(),
range: "class2".to_string(),
characteristics: PropertyCharacteristics {
functional: true,
transitive: false,
symmetric: false,
inverse_functional: false,
cardinality: Some(Cardinality {
min: Some(1),
max: Some(1),
exact: None,
}),
},
inverse_of: None,
equivalent_to: vec![],
disjoint_with: vec![],
};
assert!(prop.characteristics.functional);
assert_eq!(
prop.characteristics.cardinality.as_ref().unwrap().min,
Some(1)
);
}
}