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}