sea_core/primitives/
entity.rs

1use crate::ConceptId;
2use crate::SemanticVersion;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6use uuid::Uuid;
7
8/// Represents a business actor, location, or organizational unit.
9///
10/// Entities are the "WHO" in enterprise models - the actors that perform
11/// actions, hold resources, or participate in flows.
12///
13/// # Examples
14///
15/// Basic usage:
16///
17/// ```
18/// use sea_core::primitives::Entity;
19///
20/// let warehouse = Entity::new_with_namespace("Main Warehouse", "default");
21/// assert_eq!(warehouse.name(), "Main Warehouse");
22/// assert_eq!(warehouse.namespace(), "default");
23/// ```
24///
25/// With namespace:
26///
27/// ```
28/// use sea_core::primitives::Entity;
29///
30/// let warehouse = Entity::new_with_namespace("Warehouse A", "logistics");
31/// assert_eq!(warehouse.namespace(), "logistics");
32/// ```
33///
34/// With custom attributes:
35///
36/// ```
37/// use sea_core::primitives::Entity;
38/// use serde_json::json;
39///
40/// let mut factory = Entity::new_with_namespace("Factory", "default");
41/// factory.set_attribute("capacity", json!(5000));
42/// factory.set_attribute("location", json!("Building 3"));
43///
44/// assert_eq!(factory.get_attribute("capacity"), Some(&json!(5000)));
45/// ```
46///
47/// Serialization:
48///
49/// ```
50/// use sea_core::primitives::Entity;
51///
52/// let entity = Entity::new_with_namespace("Test Entity", "default");
53/// let json = serde_json::to_string(&entity).unwrap();
54/// let deserialized: Entity = serde_json::from_str(&json).unwrap();
55/// assert_eq!(entity.name(), deserialized.name());
56/// ```
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct Entity {
59    id: ConceptId,
60    name: String,
61    namespace: String,
62    version: Option<SemanticVersion>,
63    replaces: Option<String>,
64    changes: Vec<String>,
65    attributes: HashMap<String, Value>,
66}
67
68impl Entity {
69    /// Creates a new Entity with a generated UUID (deprecated - use new_with_namespace).
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use sea_core::primitives::Entity;
75    ///
76    /// let entity = Entity::new_with_namespace("Warehouse", "default");
77    /// assert_eq!(entity.name(), "Warehouse");
78    /// ```
79    #[deprecated(note = "use new_with_namespace instead")]
80    pub fn new(name: impl Into<String>) -> Self {
81        let name = name.into();
82        let namespace = "default".to_string();
83        Self {
84            id: ConceptId::from_concept(&namespace, &name),
85            name,
86            namespace,
87            version: None,
88            replaces: None,
89            changes: Vec::new(),
90            attributes: HashMap::new(),
91        }
92    }
93
94    /// Creates a new Entity with a specific namespace.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use sea_core::primitives::Entity;
100    ///
101    /// let entity = Entity::new_with_namespace("Warehouse", "logistics");
102    /// assert_eq!(entity.namespace(), "logistics");
103    /// ```
104    pub fn new_with_namespace(name: impl Into<String>, namespace: impl Into<String>) -> Self {
105        let namespace = namespace.into();
106        let name = name.into();
107        let id = ConceptId::from_concept(&namespace, &name);
108
109        Self {
110            id,
111            name,
112            namespace,
113            version: None,
114            replaces: None,
115            changes: Vec::new(),
116            attributes: HashMap::new(),
117        }
118    }
119
120    /// Sets the entity version.
121    pub fn with_version(mut self, version: SemanticVersion) -> Self {
122        self.version = Some(version);
123        self
124    }
125
126    /// Sets the entity that this version replaces.
127    pub fn with_replaces(mut self, replaces: String) -> Self {
128        self.replaces = Some(replaces);
129        self
130    }
131
132    /// Sets the list of changes in this version.
133    pub fn with_changes(mut self, changes: Vec<String>) -> Self {
134        self.changes = changes;
135        self
136    }
137
138    /// Returns the entity version.
139    pub fn version(&self) -> Option<&SemanticVersion> {
140        self.version.as_ref()
141    }
142
143    /// Returns the entity that this version replaces.
144    pub fn replaces(&self) -> Option<&str> {
145        self.replaces.as_deref()
146    }
147
148    /// Returns the list of changes in this version.
149    pub fn changes(&self) -> &[String] {
150        &self.changes
151    }
152
153    /// Creates an Entity from a legacy UUID for backward compatibility.
154    pub fn from_legacy_uuid(
155        uuid: Uuid,
156        name: impl Into<String>,
157        namespace: impl Into<String>,
158    ) -> Self {
159        Self {
160            id: ConceptId::from_legacy_uuid(uuid),
161            name: name.into(),
162            namespace: namespace.into(),
163            version: None,
164            replaces: None,
165            changes: Vec::new(),
166            attributes: HashMap::new(),
167        }
168    }
169
170    /// Returns the entity's unique identifier.
171    pub fn id(&self) -> &ConceptId {
172        &self.id
173    }
174
175    /// Returns the entity's name.
176    pub fn name(&self) -> &str {
177        &self.name
178    }
179
180    /// Returns the entity's namespace.
181    pub fn namespace(&self) -> &str {
182        &self.namespace
183    }
184
185    /// Sets a custom attribute.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use sea_core::primitives::Entity;
191    /// use serde_json::json;
192    ///
193    /// let mut entity = Entity::new_with_namespace("Factory", "default");
194    /// entity.set_attribute("capacity", json!(5000));
195    /// assert_eq!(entity.get_attribute("capacity"), Some(&json!(5000)));
196    /// ```
197    pub fn set_attribute(&mut self, key: impl Into<String>, value: Value) {
198        self.attributes.insert(key.into(), value);
199    }
200
201    /// Gets a custom attribute.
202    ///
203    /// Returns `None` if the attribute doesn't exist.
204    ///
205    /// # Examples
206    ///
207    /// ```
208    /// use sea_core::primitives::Entity;
209    /// use serde_json::json;
210    ///
211    /// let mut entity = Entity::new_with_namespace("Factory", "default");
212    /// entity.set_attribute("capacity", json!(5000));
213    /// assert_eq!(entity.get_attribute("capacity"), Some(&json!(5000)));
214    /// assert_eq!(entity.get_attribute("missing"), None);
215    /// ```
216    pub fn get_attribute(&self, key: &str) -> Option<&Value> {
217        self.attributes.get(key)
218    }
219
220    /// Returns all attributes as a reference.
221    pub fn attributes(&self) -> &HashMap<String, Value> {
222        &self.attributes
223    }
224}