Skip to main content

owl_structural_model/
key.rs

1//! Structural key properties, independent of RDF list representation.
2
3use iri_rfc3987::Iri;
4
5use crate::{ObjectPropertyExpression, OperandSet, StructuralModelError};
6
7/// The object and data properties identifying instances in one `HasKey` axiom.
8///
9/// Either list can be empty; together they must contain at least one property.
10/// Object and data properties remain separate even if their IRIs coincide.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12#[serde(deny_unknown_fields)]
13#[serde(try_from = "KeyPropertiesInput")]
14pub struct KeyProperties {
15    // bounded: object properties in one caller-owned structural key axiom.
16    object_properties: OperandSet<ObjectPropertyExpression>,
17    // bounded: data properties in one caller-owned structural key axiom.
18    data_properties: OperandSet<Iri<String>>,
19}
20
21impl KeyProperties {
22    /// Create key properties while preserving the two property categories.
23    ///
24    /// # Errors
25    ///
26    /// Returns [`StructuralModelError::InvalidFormat`] when both lists are empty.
27    pub fn try_new(
28        object_properties: Vec<ObjectPropertyExpression>,
29        data_properties: Vec<Iri<String>>,
30    ) -> Result<Self, StructuralModelError> {
31        if object_properties.is_empty() && data_properties.is_empty() {
32            return Err(StructuralModelError::InvalidFormat {
33                kind: "key properties",
34                value: "0".to_owned(),
35                message: "requires at least one key property",
36            });
37        }
38        Ok(Self {
39            object_properties: OperandSet::new(object_properties),
40            data_properties: OperandSet::new(data_properties),
41        })
42    }
43
44    /// Return the object property expressions.
45    #[must_use]
46    pub fn object_properties(&self) -> &[ObjectPropertyExpression] {
47        self.object_properties.as_slice()
48    }
49
50    /// Return the named data properties.
51    #[must_use]
52    pub fn data_properties(&self) -> &[Iri<String>] {
53        self.data_properties.as_slice()
54    }
55}
56
57#[derive(serde::Deserialize)]
58#[serde(deny_unknown_fields)]
59struct KeyPropertiesInput {
60    // bounded: object properties of one deserialized structural key axiom.
61    object_properties: Vec<ObjectPropertyExpression>,
62    // bounded: data properties of one deserialized structural key axiom.
63    data_properties: Vec<Iri<String>>,
64}
65
66impl TryFrom<KeyPropertiesInput> for KeyProperties {
67    type Error = StructuralModelError;
68
69    fn try_from(input: KeyPropertiesInput) -> Result<Self, Self::Error> {
70        Self::try_new(input.object_properties, input.data_properties)
71    }
72}