use crate::error::{EditError, Result};
use crate::transaction::Transaction;
use ontocore_core::OntologyFormat;
use ontocore_obo::{self, OboPatchOp};
use ontocore_owl::{self, PatchDiagnostic, PatchOp};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EditFormat {
Turtle,
Obo,
RdfXml,
OwlXml,
}
impl EditFormat {
pub fn from_ontology_format(format: OntologyFormat) -> Result<Self> {
match format {
OntologyFormat::Turtle => Ok(Self::Turtle),
OntologyFormat::Obo => Ok(Self::Obo),
OntologyFormat::Owl | OntologyFormat::RdfXml => Ok(Self::RdfXml),
OntologyFormat::OwlXml => Ok(Self::OwlXml),
other => Err(EditError::UnsupportedFormat(other.as_str().to_string())),
}
}
pub fn from_path(path: &Path) -> Result<Self> {
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
Self::from_ontology_format(OntologyFormat::from_extension(ext))
}
pub fn to_ontology_format(self) -> OntologyFormat {
match self {
Self::Turtle => OntologyFormat::Turtle,
Self::Obo => OntologyFormat::Obo,
Self::RdfXml => OntologyFormat::RdfXml,
Self::OwlXml => OntologyFormat::OwlXml,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplyTextResult {
pub applied: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub preview_text: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub diagnostics: Vec<PatchDiagnostic>,
}
impl From<ontocore_owl::ApplyPatchResult> for ApplyTextResult {
fn from(value: ontocore_owl::ApplyPatchResult) -> Self {
Self {
applied: value.applied,
preview_text: value.preview_text,
diagnostics: value.diagnostics,
}
}
}
pub fn apply_transaction_to_text(
transaction: &Transaction,
source: &str,
preview_only: bool,
namespaces: &BTreeMap<String, String>,
) -> Result<ApplyTextResult> {
apply_transaction_to_text_as(
transaction,
source,
preview_only,
namespaces,
transaction.format()?,
)
}
pub fn apply_transaction_to_text_as(
transaction: &Transaction,
source: &str,
preview_only: bool,
namespaces: &BTreeMap<String, String>,
format: EditFormat,
) -> Result<ApplyTextResult> {
match format {
EditFormat::Turtle => {
let patches: Vec<PatchOp> = transaction.turtle_patches()?;
Ok(ontocore_owl::apply_patches_to_text(source, &patches, preview_only, namespaces)?
.into())
}
EditFormat::Obo => {
let patches: Vec<OboPatchOp> = transaction.obo_patches()?;
let result = ontocore_obo::apply_patches_to_text(source, &patches, preview_only)?;
Ok(ApplyTextResult {
applied: result.applied,
preview_text: result.preview_text,
diagnostics: result
.diagnostics
.into_iter()
.map(|d| PatchDiagnostic { severity: d.severity, message: d.message })
.collect(),
})
}
EditFormat::RdfXml | EditFormat::OwlXml => {
let patches: Vec<PatchOp> = transaction.turtle_patches()?;
Ok(ontocore_owl::apply_xml_patches_to_text(
source,
format.to_ontology_format(),
&patches,
preview_only,
namespaces,
)?
.into())
}
}
}
pub fn apply_transaction_to_path(
transaction: &Transaction,
document_path: &Path,
preview_only: bool,
namespaces: &BTreeMap<String, String>,
) -> Result<ontocore_owl::ApplyPatchResult> {
let format = EditFormat::from_path(document_path)?;
match format {
EditFormat::Turtle => {
let patches = transaction.turtle_patches()?;
ontocore_owl::apply_patches(document_path, &patches, preview_only, namespaces)
.map_err(EditError::from)
}
EditFormat::Obo => {
let patches = transaction.obo_patches()?;
let result = ontocore_obo::apply_patches(document_path, &patches, preview_only)?;
Ok(ontocore_owl::ApplyPatchResult {
applied: result.applied,
preview_text: result.preview_text,
diagnostics: result
.diagnostics
.into_iter()
.map(|d| PatchDiagnostic { severity: d.severity, message: d.message })
.collect(),
document_path: result.document_path,
})
}
EditFormat::RdfXml | EditFormat::OwlXml => {
let patches = transaction.turtle_patches()?;
ontocore_owl::apply_xml_patches(document_path, &patches, preview_only, namespaces)
.map_err(EditError::from)
}
}
}