Skip to main content

weavatrix_memory/domain/
node.rs

1use crate::{EntityId, MemoryError, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub struct MemoryNode {
7    pub id: EntityId,
8    pub kind: String,
9    pub label: String,
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub repository: Option<String>,
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub branch: Option<String>,
14    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
15    pub attributes: BTreeMap<String, String>,
16}
17
18impl MemoryNode {
19    /// Creates a memory entity.
20    ///
21    /// # Errors
22    ///
23    /// Rejects empty or whitespace-padded kind and an empty label.
24    pub fn new(id: EntityId, kind: impl Into<String>, label: impl Into<String>) -> Result<Self> {
25        let node = Self {
26            id,
27            kind: kind.into(),
28            label: label.into(),
29            repository: None,
30            branch: None,
31            attributes: BTreeMap::new(),
32        };
33        node.validate()?;
34        Ok(node)
35    }
36
37    #[must_use]
38    pub fn in_repository(mut self, repository: impl Into<String>) -> Self {
39        self.repository = Some(repository.into());
40        self
41    }
42
43    #[must_use]
44    pub fn on_branch(mut self, branch: impl Into<String>) -> Self {
45        self.branch = Some(branch.into());
46        self
47    }
48
49    #[must_use]
50    pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
51        self.attributes.insert(key.into(), value.into());
52        self
53    }
54
55    pub(crate) fn validate(&self) -> Result<()> {
56        super::validate_text("node.kind", &self.kind)?;
57        if self.label.is_empty() {
58            return Err(MemoryError::InvalidValue {
59                field: "node.label",
60                reason: "must be non-empty",
61            });
62        }
63        super::validate_optional_text("node.repository", self.repository.as_deref())?;
64        super::validate_optional_text("node.branch", self.branch.as_deref())?;
65        for key in self.attributes.keys() {
66            super::validate_text("node.attribute.key", key)?;
67        }
68        Ok(())
69    }
70}