Skip to main content

maec/objects/
collection.rs

1//! MAEC Collection object
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::common::{CommonProperties, MaecObject};
7use crate::error::{MaecError, Result};
8
9/// MAEC Collection
10///
11/// Represents a grouping of related MAEC objects.
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub struct Collection {
15    /// Common MAEC properties
16    #[serde(flatten)]
17    pub common: CommonProperties,
18
19    /// Name of the collection
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub name: Option<String>,
22
23    /// Textual description
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub description: Option<String>,
26}
27
28impl Collection {
29    /// Creates a new Collection builder
30    pub fn builder() -> CollectionBuilder {
31        CollectionBuilder::default()
32    }
33
34    /// Creates a minimal Collection
35    pub fn new() -> Self {
36        Self {
37            common: CommonProperties::new("collection", None),
38            name: None,
39            description: None,
40        }
41    }
42
43    /// Validates the Collection structure
44    pub fn validate(&self) -> Result<()> {
45        if self.common.r#type != "collection" {
46            return Err(MaecError::ValidationError(format!(
47                "type must be 'collection', got '{}'",
48                self.common.r#type
49            )));
50        }
51
52        if !crate::common::is_valid_maec_id(&self.common.id) {
53            return Err(MaecError::InvalidId(self.common.id.clone()));
54        }
55
56        Ok(())
57    }
58}
59
60impl Default for Collection {
61    fn default() -> Self {
62        Self::new()
63    }
64}
65
66impl MaecObject for Collection {
67    fn id(&self) -> &str {
68        &self.common.id
69    }
70
71    fn type_(&self) -> &str {
72        &self.common.r#type
73    }
74
75    fn created(&self) -> DateTime<Utc> {
76        self.common.created
77    }
78}
79
80/// Builder for Collection objects
81#[derive(Debug, Default)]
82pub struct CollectionBuilder {
83    id: Option<String>,
84    name: Option<String>,
85    description: Option<String>,
86}
87
88impl CollectionBuilder {
89    pub fn id(mut self, id: impl Into<String>) -> Self {
90        self.id = Some(id.into());
91        self
92    }
93
94    pub fn name(mut self, name: impl Into<String>) -> Self {
95        self.name = Some(name.into());
96        self
97    }
98
99    pub fn description(mut self, desc: impl Into<String>) -> Self {
100        self.description = Some(desc.into());
101        self
102    }
103
104    pub fn build(self) -> Result<Collection> {
105        let mut common = CommonProperties::new("collection", None);
106        if let Some(id) = self.id {
107            common.id = id;
108        }
109
110        let collection = Collection {
111            common,
112            name: self.name,
113            description: self.description,
114        };
115
116        collection.validate()?;
117        Ok(collection)
118    }
119}