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