Skip to main content

owl_structural_model/
patch.rs

1//! Structural ontology patch values.
2
3use iri_rfc3987::Iri;
4
5use crate::{Annotation, Axiom, OntologyId, StructuralModelError};
6
7const KIND_ONTOLOGY_PATCH: &str = "ontology patch";
8
9/// A non-empty collection of structural changes for one ontology identity.
10#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
11#[serde(deny_unknown_fields)]
12#[serde(
13    try_from = "OntologyPatchInput<L, B>",
14    bound(deserialize = "L: serde::Deserialize<'de>, B: serde::Deserialize<'de>")
15)]
16pub struct OntologyPatch<L = crate::OwlLiteral, B = crate::BlankNodeId> {
17    target: OntologyId,
18    // bounded: one submitted patch/change request, never a workspace stream.
19    operations: Vec<OntologyPatchOperation<L, B>>,
20}
21
22impl<L, B> OntologyPatch<L, B> {
23    /// Create a non-empty ontology patch.
24    ///
25    /// # Errors
26    ///
27    /// Returns [`StructuralModelError::InvalidFormat`] when no operations are
28    /// supplied.
29    pub fn try_new(
30        target: OntologyId,
31        operations: Vec<OntologyPatchOperation<L, B>>,
32    ) -> Result<Self, StructuralModelError> {
33        if operations.is_empty() {
34            return Err(StructuralModelError::InvalidFormat {
35                kind: KIND_ONTOLOGY_PATCH,
36                value: "0 operations".to_owned(),
37                message: "requires at least one operation",
38            });
39        }
40        Ok(Self { target, operations })
41    }
42
43    /// Return the patch target ontology ID.
44    #[must_use]
45    pub fn target(&self) -> &OntologyId {
46        &self.target
47    }
48
49    /// Return patch operations.
50    #[must_use]
51    pub fn operations(&self) -> &[OntologyPatchOperation<L, B>] {
52        &self.operations
53    }
54}
55
56/// One structural ontology patch operation.
57#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
58#[serde(deny_unknown_fields)]
59pub enum OntologyPatchOperation<L = crate::OwlLiteral, B = crate::BlankNodeId> {
60    /// Add an import declaration.
61    AddImport {
62        /// Imported ontology IRI.
63        import_iri: Iri<String>,
64    },
65    /// Remove an import declaration.
66    RemoveImport {
67        /// Imported ontology IRI.
68        import_iri: Iri<String>,
69    },
70    /// Add an ontology annotation.
71    AddAnnotation {
72        /// Ontology annotation.
73        annotation: Annotation<L, B>,
74    },
75    /// Remove an ontology annotation.
76    RemoveAnnotation {
77        /// Ontology annotation.
78        annotation: Annotation<L, B>,
79    },
80    /// Add a structural axiom.
81    AddAxiom {
82        /// Structural axiom.
83        axiom: Axiom<L, B>,
84    },
85    /// Remove a structural axiom.
86    RemoveAxiom {
87        /// Structural axiom.
88        axiom: Axiom<L, B>,
89    },
90}
91
92#[derive(serde::Deserialize)]
93#[serde(deny_unknown_fields)]
94#[serde(rename = "OntologyPatch<L, B>")]
95struct OntologyPatchInput<L, B> {
96    target: OntologyId,
97    // bounded: operations of one submitted structural patch.
98    operations: Vec<OntologyPatchOperation<L, B>>,
99}
100
101impl<L, B> TryFrom<OntologyPatchInput<L, B>> for OntologyPatch<L, B> {
102    type Error = StructuralModelError;
103
104    fn try_from(input: OntologyPatchInput<L, B>) -> Result<Self, Self::Error> {
105        Self::try_new(input.target, input.operations)
106    }
107}