Skip to main content

arri_repr/
metadata.rs

1use std::ops::BitOr;
2
3use ronky_derive::Serializable as SerializableDerive;
4
5/// Macro to merge fields from one struct into another.
6///
7/// This macro checks if a field in the source struct (`$other`) is `Some`
8/// and, if so, clones its value into the corresponding field of the target
9/// struct (`$self`).
10macro_rules! merge_fields {
11    ($self:expr, $other:expr, $($field:ident),*) => {
12        $(
13            if let Some(value) = &$other.$field {
14                $self.$field = Some(value.clone());
15            }
16        )*
17    };
18}
19
20/// Represents metadata schema for Arri.
21///
22/// This struct defines the metadata schema, including optional fields
23/// such as `id`, `description`, and deprecation-related information.
24#[derive(Default, Debug, Clone, PartialEq, Eq, SerializableDerive)]
25#[arri_disable(metadata, nullable)]
26pub struct MetadataSchema {
27    /// Unique identifier for the metadata schema.
28    pub id: Option<String>,
29    /// Description of the metadata schema.
30    pub description: Option<String>,
31    /// Indicates whether the schema is deprecated.
32    pub is_deprecated: Option<bool>,
33    /// Version since which the schema is deprecated.
34    pub deprecated_since: Option<String>,
35    /// Message explaining the deprecation.
36    pub deprecated_message: Option<String>,
37}
38
39impl MetadataSchema {
40    /// Creates a new, empty `MetadataSchema`.
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    /// Sets the `id` field of the metadata schema.
46    ///
47    /// # Arguments
48    ///
49    /// * `id` - A value that can be converted to a `String`.
50    pub fn set_id(&mut self, id: impl ToString) -> &mut Self {
51        self.id = Some(id.to_string());
52        self
53    }
54
55    /// Sets the `description` field of the metadata schema.
56    ///
57    /// # Arguments
58    ///
59    /// * `description` - A value that can be converted to a `String`.
60    pub fn set_description(&mut self, description: impl ToString) -> &mut Self {
61        self.description = Some(description.to_string());
62        self
63    }
64
65    /// Sets the `is_deprecated` field of the metadata schema.
66    ///
67    /// # Arguments
68    ///
69    /// * `flag` - A boolean indicating whether the schema is deprecated.
70    pub fn set_deprecated(&mut self, flag: bool) -> &mut Self {
71        self.is_deprecated = Some(flag);
72        self
73    }
74
75    /// Sets the `deprecated_since` field of the metadata schema.
76    ///
77    /// # Arguments
78    ///
79    /// * `version` - A value that can be converted to a `String` representing the version.
80    pub fn set_deprecated_since(&mut self, version: impl ToString) -> &mut Self {
81        self.deprecated_since = Some(version.to_string());
82        self
83    }
84
85    /// Sets the `deprecated_message` field of the metadata schema.
86    ///
87    /// # Arguments
88    ///
89    /// * `message` - A value that can be converted to a `String` explaining the deprecation.
90    pub fn set_deprecated_message(&mut self, message: impl ToString) -> &mut Self {
91        self.deprecated_message = Some(message.to_string());
92        self
93    }
94
95    /// Merges another `MetadataSchema` into this one.
96    ///
97    /// Fields in the other schema take precedence if they are `Some`.
98    ///
99    /// # Arguments
100    ///
101    /// * `other` - A reference to another `MetadataSchema` to merge.
102    ///
103    /// # Returns
104    ///
105    /// A new `MetadataSchema` with merged fields.
106    pub fn merge(mut self, other: &Self) -> Self {
107        merge_fields!(
108            self,
109            other,
110            id,
111            description,
112            deprecated_since,
113            deprecated_message
114        );
115
116        // Handle non-String fields separately
117        if let Some(is_deprecated) = other.is_deprecated {
118            self.is_deprecated = Some(is_deprecated);
119        }
120
121        self
122    }
123}
124
125impl BitOr for MetadataSchema {
126    type Output = Self;
127
128    fn bitor(self, other: Self) -> Self::Output {
129        self.merge(&other)
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use crate::Serializable;
137
138    #[test]
139    fn test_metadata_schema_defaults() {
140        let schema = MetadataSchema::new();
141        assert_eq!(schema.id, None);
142        assert_eq!(schema.description, None);
143        assert_eq!(schema.is_deprecated, None);
144        assert_eq!(schema.deprecated_since, None);
145        assert_eq!(schema.deprecated_message, None);
146    }
147
148    #[test]
149    fn test_metadata_schema_setters() {
150        let mut schema = MetadataSchema::new();
151        schema
152            .set_id("123")
153            .set_description("Test description")
154            .set_deprecated(true)
155            .set_deprecated_since("1.0.0")
156            .set_deprecated_message("Deprecated for testing");
157
158        assert_eq!(schema.id, Some("123".to_string()));
159        assert_eq!(schema.description, Some("Test description".to_string()));
160        assert_eq!(schema.is_deprecated, Some(true));
161        assert_eq!(schema.deprecated_since, Some("1.0.0".to_string()));
162        assert_eq!(
163            schema.deprecated_message,
164            Some("Deprecated for testing".to_string())
165        );
166    }
167
168    #[test]
169    fn test_metadata_schema_merge() {
170        let mut schema1 = MetadataSchema::new();
171        schema1.set_id("123").set_description("Schema 1");
172
173        let mut schema2 = MetadataSchema::new();
174        schema2
175            .set_description("Schema 2")
176            .set_deprecated(true)
177            .set_deprecated_since("2.0.0");
178
179        let merged = schema1.merge(&schema2);
180
181        assert_eq!(merged.id, Some("123".to_string()));
182        assert_eq!(merged.description, Some("Schema 2".to_string()));
183        assert_eq!(merged.is_deprecated, Some(true));
184        assert_eq!(merged.deprecated_since, Some("2.0.0".to_string()));
185        assert_eq!(merged.deprecated_message, None);
186    }
187
188    #[test]
189    fn test_metadata_schema_serialization() {
190        let mut schema = MetadataSchema::new();
191        schema
192            .set_id("123")
193            .set_description("Test description")
194            .set_deprecated(true)
195            .set_deprecated_since("1.0.0")
196            .set_deprecated_message("Deprecated for testing");
197
198        let serialized = schema.serialize();
199        assert!(serialized.is_some());
200        let serialized_str = serialized.unwrap();
201        assert!(serialized_str.contains("\"id\":\"123\""));
202        assert!(serialized_str.contains("\"description\":\"Test description\""));
203        assert!(serialized_str.contains("\"isDeprecated\":true"));
204        assert!(serialized_str.contains("\"deprecatedSince\":\"1.0.0\""));
205        assert!(serialized_str.contains("\"deprecatedNote\":\"Deprecated for testing\""));
206    }
207
208    #[test]
209    fn test_metadata_schema_bitor_operator() {
210        let mut schema1 = MetadataSchema::new();
211        schema1.set_id("123");
212
213        let mut schema2 = MetadataSchema::new();
214        schema2.set_description("Schema 2");
215
216        let merged = schema1 | schema2;
217
218        assert_eq!(merged.id, Some("123".to_string()));
219        assert_eq!(merged.description, Some("Schema 2".to_string()));
220    }
221}