Skip to main content

xapi_data/
statement_ref.rs

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