1use crate::error::{EditError, Result};
2use crate::transaction::Transaction;
3use ontocore_core::OntologyFormat;
4use ontocore_obo::{self, OboPatchOp};
5use ontocore_owl::{self, PatchDiagnostic, PatchOp};
6use serde::{Deserialize, Serialize};
7use std::collections::BTreeMap;
8use std::path::Path;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum EditFormat {
12 Turtle,
13 Obo,
14 RdfXml,
16 OwlXml,
18}
19
20impl EditFormat {
21 pub fn from_ontology_format(format: OntologyFormat) -> Result<Self> {
22 match format {
23 OntologyFormat::Turtle => Ok(Self::Turtle),
24 OntologyFormat::Obo => Ok(Self::Obo),
25 OntologyFormat::Owl | OntologyFormat::RdfXml => Ok(Self::RdfXml),
26 OntologyFormat::OwlXml => Ok(Self::OwlXml),
27 other => Err(EditError::UnsupportedFormat(other.as_str().to_string())),
28 }
29 }
30
31 pub fn from_path(path: &Path) -> Result<Self> {
32 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
33 Self::from_ontology_format(OntologyFormat::from_extension(ext))
34 }
35
36 pub fn to_ontology_format(self) -> OntologyFormat {
37 match self {
38 Self::Turtle => OntologyFormat::Turtle,
39 Self::Obo => OntologyFormat::Obo,
40 Self::RdfXml => OntologyFormat::RdfXml,
41 Self::OwlXml => OntologyFormat::OwlXml,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct ApplyTextResult {
48 pub applied: bool,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub preview_text: Option<String>,
51 #[serde(default, skip_serializing_if = "Vec::is_empty")]
52 pub diagnostics: Vec<PatchDiagnostic>,
53}
54
55impl From<ontocore_owl::ApplyPatchResult> for ApplyTextResult {
56 fn from(value: ontocore_owl::ApplyPatchResult) -> Self {
57 Self {
58 applied: value.applied,
59 preview_text: value.preview_text,
60 diagnostics: value.diagnostics,
61 }
62 }
63}
64
65pub fn apply_transaction_to_text(
67 transaction: &Transaction,
68 source: &str,
69 preview_only: bool,
70 namespaces: &BTreeMap<String, String>,
71) -> Result<ApplyTextResult> {
72 apply_transaction_to_text_as(
73 transaction,
74 source,
75 preview_only,
76 namespaces,
77 transaction.format()?,
78 )
79}
80
81pub fn apply_transaction_to_text_as(
83 transaction: &Transaction,
84 source: &str,
85 preview_only: bool,
86 namespaces: &BTreeMap<String, String>,
87 format: EditFormat,
88) -> Result<ApplyTextResult> {
89 match format {
90 EditFormat::Turtle => {
91 let patches: Vec<PatchOp> = transaction.turtle_patches()?;
92 Ok(ontocore_owl::apply_patches_to_text(source, &patches, preview_only, namespaces)?
93 .into())
94 }
95 EditFormat::Obo => {
96 let patches: Vec<OboPatchOp> = transaction.obo_patches()?;
97 let result = ontocore_obo::apply_patches_to_text(source, &patches, preview_only)?;
98 Ok(ApplyTextResult {
99 applied: result.applied,
100 preview_text: result.preview_text,
101 diagnostics: result
102 .diagnostics
103 .into_iter()
104 .map(|d| PatchDiagnostic { severity: d.severity, message: d.message })
105 .collect(),
106 })
107 }
108 EditFormat::RdfXml | EditFormat::OwlXml => {
109 let patches: Vec<PatchOp> = transaction.turtle_patches()?;
110 Ok(ontocore_owl::apply_xml_patches_to_text(
111 source,
112 format.to_ontology_format(),
113 &patches,
114 preview_only,
115 namespaces,
116 )?
117 .into())
118 }
119 }
120}
121
122pub fn apply_transaction_to_path(
123 transaction: &Transaction,
124 document_path: &Path,
125 preview_only: bool,
126 namespaces: &BTreeMap<String, String>,
127) -> Result<ontocore_owl::ApplyPatchResult> {
128 let format = EditFormat::from_path(document_path)?;
129 match format {
130 EditFormat::Turtle => {
131 let patches = transaction.turtle_patches()?;
132 ontocore_owl::apply_patches(document_path, &patches, preview_only, namespaces)
133 .map_err(EditError::from)
134 }
135 EditFormat::Obo => {
136 let patches = transaction.obo_patches()?;
137 let result = ontocore_obo::apply_patches(document_path, &patches, preview_only)?;
138 Ok(ontocore_owl::ApplyPatchResult {
139 applied: result.applied,
140 preview_text: result.preview_text,
141 diagnostics: result
142 .diagnostics
143 .into_iter()
144 .map(|d| PatchDiagnostic { severity: d.severity, message: d.message })
145 .collect(),
146 document_path: result.document_path,
147 })
148 }
149 EditFormat::RdfXml | EditFormat::OwlXml => {
150 let patches = transaction.turtle_patches()?;
151 ontocore_owl::apply_xml_patches(document_path, &patches, preview_only, namespaces)
152 .map_err(EditError::from)
153 }
154 }
155}