Skip to main content

maec/objects/
relationship.rs

1//! MAEC Relationship object
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::common::MaecObject;
7use crate::error::{MaecError, Result};
8
9/// MAEC Relationship
10///
11/// Connects two MAEC objects, expressing how they are related.
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub struct Relationship {
15    /// Common MAEC properties
16    #[serde(flatten)]
17    pub common: crate::common::CommonProperties,
18
19    /// ID of the source object
20    pub source_ref: String,
21
22    /// ID of the target object
23    pub target_ref: String,
24
25    /// Type of relationship (e.g., "derived-from", "variant-of")
26    pub relationship_type: String,
27
28    /// Textual description
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub description: Option<String>,
31}
32
33impl Relationship {
34    pub fn builder() -> RelationshipBuilder {
35        RelationshipBuilder::default()
36    }
37
38    pub fn new(
39        source_ref: impl Into<String>,
40        relationship_type: impl Into<String>,
41        target_ref: impl Into<String>,
42    ) -> Self {
43        Self {
44            common: crate::common::CommonProperties::new("relationship", None),
45            source_ref: source_ref.into(),
46            target_ref: target_ref.into(),
47            relationship_type: relationship_type.into(),
48            description: None,
49        }
50    }
51}
52
53impl MaecObject for Relationship {
54    fn id(&self) -> &str {
55        &self.common.id
56    }
57
58    fn type_(&self) -> &str {
59        &self.common.r#type
60    }
61
62    fn created(&self) -> DateTime<Utc> {
63        self.common.created
64    }
65}
66
67#[derive(Debug, Default)]
68pub struct RelationshipBuilder {
69    id: Option<String>,
70    source_ref: Option<String>,
71    target_ref: Option<String>,
72    relationship_type: Option<String>,
73    description: Option<String>,
74}
75
76impl RelationshipBuilder {
77    pub fn id(mut self, id: impl Into<String>) -> Self {
78        self.id = Some(id.into());
79        self
80    }
81
82    pub fn source_ref(mut self, ref_id: impl Into<String>) -> Self {
83        self.source_ref = Some(ref_id.into());
84        self
85    }
86
87    pub fn target_ref(mut self, ref_id: impl Into<String>) -> Self {
88        self.target_ref = Some(ref_id.into());
89        self
90    }
91
92    pub fn relationship_type(mut self, rel_type: impl Into<String>) -> Self {
93        self.relationship_type = Some(rel_type.into());
94        self
95    }
96
97    pub fn description(mut self, desc: impl Into<String>) -> Self {
98        self.description = Some(desc.into());
99        self
100    }
101
102    pub fn build(self) -> Result<Relationship> {
103        let source_ref = self
104            .source_ref
105            .ok_or(MaecError::MissingField("source_ref"))?;
106        let target_ref = self
107            .target_ref
108            .ok_or(MaecError::MissingField("target_ref"))?;
109        let relationship_type = self
110            .relationship_type
111            .ok_or(MaecError::MissingField("relationship_type"))?;
112
113        let mut common = crate::common::CommonProperties::new("relationship", None);
114        if let Some(id) = self.id {
115            common.id = id;
116        }
117
118        Ok(Relationship {
119            common,
120            source_ref,
121            target_ref,
122            relationship_type,
123            description: self.description,
124        })
125    }
126}