xapi_rs/data/
statement_ref.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use crate::{
4    data::{DataError, Fingerprint, ObjectType, Validate, ValidationError},
5    emit_error,
6};
7use core::fmt;
8use serde::{Deserialize, Serialize};
9use std::hash::{Hash, Hasher};
10use uuid::Uuid;
11
12/// Structure containing the UUID (Universally Unique Identifier) of a
13/// [Statement][crate::Statement] referenced as the _object_ of another.
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
15pub struct StatementRef {
16    #[serde(rename = "objectType")]
17    object_type: ObjectType,
18    id: Uuid,
19}
20
21impl StatementRef {
22    /// Return a [StatementRef] _Builder_.
23    pub fn builder() -> StatementRefBuilder {
24        StatementRefBuilder::default()
25    }
26
27    /// Return the UUID of the referenced Statement.
28    pub fn id(&self) -> &Uuid {
29        &self.id
30    }
31
32    /// Return TRUE if the `objectType` property is [StatementRef][1]; FALSE
33    /// otherwise.
34    ///
35    /// [1]: ObjectType#variant.StatementRef
36    pub fn check_object_type(&self) -> bool {
37        self.object_type == ObjectType::StatementRef
38    }
39}
40
41impl fmt::Display for StatementRef {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(
44            f,
45            "StatementRef{{ id: \"{}\" }}",
46            self.id
47                .as_hyphenated()
48                .encode_lower(&mut Uuid::encode_buffer())
49        )
50    }
51}
52
53impl Fingerprint for StatementRef {
54    fn fingerprint<H: Hasher>(&self, state: &mut H) {
55        self.id.hash(state)
56    }
57}
58
59impl Validate for StatementRef {
60    fn validate(&self) -> Vec<ValidationError> {
61        let mut vec = vec![];
62
63        if !self.check_object_type() {
64            vec.push(ValidationError::WrongObjectType {
65                expected: ObjectType::StatementRef,
66                found: self.object_type.to_string().into(),
67            })
68        }
69        if self.id.is_max() || self.id.is_nil() {
70            vec.push(ValidationError::ConstraintViolation(
71                "ID should not be all 0's or 1's".into(),
72            ))
73        }
74
75        vec
76    }
77}
78
79/// A Type that knows how to construct a [StatementRef].
80#[derive(Debug, Default)]
81pub struct StatementRefBuilder {
82    _id: Option<Uuid>,
83}
84
85impl StatementRefBuilder {
86    /// Set the `id` field parsing the argument as a UUID.
87    ///
88    /// Raise [DataError] if argument is empty, cannot be parsed into a
89    /// valid UUID, or is all zeroes (`nil` UUID) or ones (`max` UUID).
90    pub fn id(mut self, val: &str) -> Result<Self, DataError> {
91        let val = val.trim();
92        if val.is_empty() {
93            emit_error!(DataError::Validation(ValidationError::Empty("id".into())))
94        } else {
95            let uuid = Uuid::parse_str(val)?;
96            if uuid.is_nil() || uuid.is_max() {
97                emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
98                    "'id' should not be all 0's or 1's".into()
99                )))
100            } else {
101                self._id = Some(uuid);
102                Ok(self)
103            }
104        }
105    }
106
107    /// Set the identifier for this instance using the given UUID.
108    ///
109    /// Raise [DataError] if the given UUID is all zeroes (`nil` UUID) or
110    /// ones (`max` UUID).
111    pub fn id_as_uuid(mut self, uuid: Uuid) -> Result<Self, DataError> {
112        if uuid.is_nil() || uuid.is_max() {
113            emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
114                "ID should not be all 0's or 1's".into()
115            )))
116        } else {
117            self._id = Some(uuid);
118            Ok(self)
119        }
120    }
121
122    /// Create a [StatementRef] instance.
123    ///
124    /// Raise a [DataError] if the ID field is not set.
125    pub fn build(&self) -> Result<StatementRef, DataError> {
126        if self._id.is_none() {
127            emit_error!(DataError::Validation(ValidationError::MissingField(
128                "id".into()
129            )))
130        } else {
131            Ok(StatementRef {
132                object_type: ObjectType::StatementRef,
133                id: self._id.unwrap(),
134            })
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use uuid::uuid;
143
144    const ID1: Uuid = uuid!("9e13cefd-53d3-4eac-b5ed-2cf6693903bb");
145    const ID2: Uuid = uuid!("9e13cefd53d34eacb5ed2cf6693903bb");
146    const JSON: &str =
147        r#"{"objectType":"StatementRef","id":"9e13cefd-53d3-4eac-b5ed-2cf6693903bb"}"#;
148
149    #[test]
150    fn test_serde_hyphenated_uuid() -> Result<(), DataError> {
151        let sr1 = StatementRef::builder().id_as_uuid(ID1)?.build()?;
152        let se_result = serde_json::to_string(&sr1);
153        assert!(se_result.is_ok());
154        let json = se_result.unwrap();
155        assert_eq!(json, JSON);
156
157        let de_result = serde_json::from_str::<StatementRef>(JSON);
158        assert!(de_result.is_ok());
159        let sr2 = de_result.unwrap();
160
161        assert_eq!(sr1, sr2);
162        assert!(sr1 == sr2);
163
164        // -----
165
166        let sr1 = StatementRef::builder()
167            .id("9e13cefd53d34eacb5ed2cf6693903bb")?
168            .build()?;
169        let se_result = serde_json::to_string(&sr1);
170        assert!(se_result.is_ok());
171        let json = se_result.unwrap();
172        assert_eq!(json, JSON);
173
174        let de_result = serde_json::from_str::<StatementRef>(JSON);
175        assert!(de_result.is_ok());
176        let sr2 = de_result.unwrap();
177
178        assert_eq!(sr1, sr2);
179
180        Ok(())
181    }
182
183    #[test]
184    fn test_serde_simple_uuid() -> Result<(), DataError> {
185        let sr1 = StatementRef::builder().id_as_uuid(ID2)?.build()?;
186        let se_result = serde_json::to_string(&sr1);
187        assert!(se_result.is_ok());
188        let json = se_result.unwrap();
189        assert_eq!(json, JSON);
190
191        let de_result = serde_json::from_str::<StatementRef>(JSON);
192        assert!(de_result.is_ok());
193        let sr2 = de_result.unwrap();
194
195        assert_eq!(sr1, sr2);
196
197        // -----
198
199        let sr1 = StatementRef::builder()
200            .id("9e13cefd-53d3-4eac-b5ed-2cf6693903bb")?
201            .build()?;
202        let se_result = serde_json::to_string(&sr1);
203        assert!(se_result.is_ok());
204        let json = se_result.unwrap();
205        assert_eq!(json, JSON);
206
207        let de_result = serde_json::from_str::<StatementRef>(JSON);
208        assert!(de_result.is_ok());
209        let sr2 = de_result.unwrap();
210
211        assert_eq!(sr1, sr2);
212
213        Ok(())
214    }
215
216    #[test]
217    fn test_uuid_as_hyphenated() -> Result<(), DataError> {
218        let uuid = ID2.as_hyphenated();
219        let sr1 = StatementRef::builder()
220            .id_as_uuid(uuid.into_uuid())?
221            .build()?;
222
223        let se_result = serde_json::to_string(&sr1);
224        assert!(se_result.is_ok());
225        let json = se_result.unwrap();
226        assert_eq!(json, JSON);
227
228        let de_result = serde_json::from_str::<StatementRef>(&json);
229        assert!(de_result.is_ok());
230        let sr2 = de_result.unwrap();
231
232        assert_eq!(sr1, sr2);
233
234        Ok(())
235    }
236
237    #[test]
238    fn test_uuid_fmt() -> Result<(), DataError> {
239        let sr1 = StatementRef::builder().id_as_uuid(ID1)?.build()?;
240
241        let hyphenated_uuid = ID1.as_hyphenated();
242        let sr2 = StatementRef::builder()
243            .id_as_uuid(hyphenated_uuid.into_uuid())?
244            .build()?;
245        assert_eq!(sr1, sr2);
246
247        let braced_uuid = ID1.as_braced();
248        let sr3 = StatementRef::builder()
249            .id_as_uuid(braced_uuid.into_uuid())?
250            .build()?;
251        assert_eq!(sr1, sr3);
252
253        let simple_uuid = ID1.as_simple();
254        let sr4 = StatementRef::builder()
255            .id_as_uuid(simple_uuid.into_uuid())?
256            .build()?;
257        assert_eq!(sr1, sr4);
258
259        let urn_uuid = ID1.as_urn();
260        let sr5 = StatementRef::builder()
261            .id_as_uuid(urn_uuid.into_uuid())?
262            .build()?;
263        assert_eq!(sr1, sr5);
264
265        Ok(())
266    }
267}