1use crate::database::VirtualDatabase;
7use crate::schema::VbrSchemaDefinition;
8use crate::{Error, Result};
9use mockforge_core::intelligent_behavior::rules::StateMachine;
10use std::collections::HashMap;
11use tracing::warn;
12
13#[derive(Debug, Clone)]
15pub struct Entity {
16 pub name: String,
18
19 pub schema: VbrSchemaDefinition,
21
22 pub table_name: String,
24
25 pub state_machine: Option<StateMachine>,
30}
31
32impl Entity {
33 pub fn new(name: String, schema: VbrSchemaDefinition) -> Self {
35 let table_name = name.to_lowercase() + "s"; Self {
37 name,
38 schema,
39 table_name,
40 state_machine: None,
41 }
42 }
43
44 pub fn with_state_machine(
46 name: String,
47 schema: VbrSchemaDefinition,
48 state_machine: StateMachine,
49 ) -> Self {
50 let table_name = name.to_lowercase() + "s";
51 Self {
52 name,
53 schema,
54 table_name,
55 state_machine: Some(state_machine),
56 }
57 }
58
59 pub fn set_state_machine(&mut self, state_machine: StateMachine) {
61 self.state_machine = Some(state_machine);
62 }
63
64 pub fn state_machine(&self) -> Option<&StateMachine> {
66 self.state_machine.as_ref()
67 }
68
69 pub fn has_state_machine(&self) -> bool {
71 self.state_machine.is_some()
72 }
73
74 pub async fn apply_state_transition(
83 &self,
84 database: &dyn VirtualDatabase,
85 record_id: &str,
86 new_state: &str,
87 state_field_name: Option<&str>,
88 ) -> Result<()> {
89 let derived_field;
94 let field_name = if let Some(name) = state_field_name {
95 name
96 } else if let Some(ref sm) = self.state_machine {
97 let candidate = format!("{}_status", sm.resource_type.to_ascii_lowercase());
99 if self.schema.base.fields.iter().any(|f| f.name == candidate) {
101 derived_field = candidate;
102 &derived_field
103 } else {
104 "status"
105 }
106 } else {
107 "status"
108 };
109
110 let field_exists = self.schema.base.fields.iter().any(|f| f.name == field_name);
112
113 if !field_exists {
114 warn!(
117 "State field '{}' not found in entity schema, attempting update anyway",
118 field_name
119 );
120 }
121
122 let query = format!("UPDATE {} SET {} = ? WHERE id = ?", self.table_name, field_name);
124
125 database
126 .execute(
127 &query,
128 &[
129 serde_json::Value::String(new_state.to_string()),
130 serde_json::Value::String(record_id.to_string()),
131 ],
132 )
133 .await
134 .map_err(|e| Error::generic(format!("Failed to update entity state: {}", e)))?;
135
136 Ok(())
137 }
138
139 pub async fn get_current_state(
143 &self,
144 database: &dyn VirtualDatabase,
145 record_id: &str,
146 state_field_name: Option<&str>,
147 ) -> Result<Option<String>> {
148 let field_name = state_field_name.unwrap_or("status");
149
150 let query = format!("SELECT {} FROM {} WHERE id = ?", field_name, self.table_name);
151
152 let results = database
153 .query(&query, &[serde_json::Value::String(record_id.to_string())])
154 .await
155 .map_err(|e| Error::generic(format!("Failed to query entity state: {}", e)))?;
156
157 if let Some(row) = results.first() {
158 if let Some(value) = row.get(field_name) {
159 if let Some(state) = value.as_str() {
160 return Ok(Some(state.to_string()));
161 }
162 }
163 }
164
165 Ok(None)
166 }
167
168 pub async fn can_transition(
173 &self,
174 database: &dyn VirtualDatabase,
175 record_id: &str,
176 to_state: &str,
177 state_field_name: Option<&str>,
178 ) -> Result<bool> {
179 let state_machine = self
180 .state_machine
181 .as_ref()
182 .ok_or_else(|| Error::generic("Entity does not have a state machine configured"))?;
183
184 let current_state = self
186 .get_current_state(database, record_id, state_field_name)
187 .await?
188 .ok_or_else(|| {
189 Error::generic(format!("Record '{}' not found or has no state", record_id))
190 })?;
191
192 Ok(state_machine.can_transition(¤t_state, to_state))
194 }
195
196 pub fn name(&self) -> &str {
198 &self.name
199 }
200
201 pub fn table_name(&self) -> &str {
203 &self.table_name
204 }
205}
206
207#[derive(Clone)]
209pub struct EntityRegistry {
210 entities: HashMap<String, Entity>,
212}
213
214impl EntityRegistry {
215 pub fn new() -> Self {
217 Self {
218 entities: HashMap::new(),
219 }
220 }
221
222 pub fn register(&mut self, entity: Entity) -> Result<()> {
224 let name = entity.name.clone();
225 if self.entities.contains_key(&name) {
226 return Err(Error::generic(format!("Entity '{}' already registered", name)));
227 }
228 self.entities.insert(name, entity);
229 Ok(())
230 }
231
232 pub fn get(&self, name: &str) -> Option<&Entity> {
234 self.entities.get(name)
235 }
236
237 pub fn list(&self) -> Vec<String> {
239 self.entities.keys().cloned().collect()
240 }
241
242 pub fn exists(&self, name: &str) -> bool {
244 self.entities.contains_key(name)
245 }
246
247 pub fn remove(&mut self, name: &str) -> Result<()> {
249 self.entities
250 .remove(name)
251 .ok_or_else(|| Error::generic(format!("Entity '{}' not found", name)))?;
252 Ok(())
253 }
254}
255
256impl Default for EntityRegistry {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use mockforge_data::SchemaDefinition;
266
267 fn create_test_schema(name: &str) -> VbrSchemaDefinition {
268 let base_schema = SchemaDefinition::new(name.to_string());
269 VbrSchemaDefinition::new(base_schema)
270 }
271
272 #[test]
274 fn test_entity_creation() {
275 let base_schema = SchemaDefinition::new("User".to_string());
276 let vbr_schema = VbrSchemaDefinition::new(base_schema);
277 let entity = Entity::new("User".to_string(), vbr_schema);
278
279 assert_eq!(entity.name(), "User");
280 assert_eq!(entity.table_name(), "users");
281 }
282
283 #[test]
284 fn test_entity_table_name_pluralization() {
285 let entity = Entity::new("Order".to_string(), create_test_schema("Order"));
286 assert_eq!(entity.table_name(), "orders");
287
288 let entity2 = Entity::new("Product".to_string(), create_test_schema("Product"));
289 assert_eq!(entity2.table_name(), "products");
290 }
291
292 #[test]
293 fn test_entity_table_name_lowercase() {
294 let entity = Entity::new("UserProfile".to_string(), create_test_schema("UserProfile"));
295 assert_eq!(entity.table_name(), "userprofiles");
296 }
297
298 #[test]
299 fn test_entity_no_state_machine() {
300 let entity = Entity::new("Item".to_string(), create_test_schema("Item"));
301 assert!(!entity.has_state_machine());
302 assert!(entity.state_machine().is_none());
303 }
304
305 #[test]
306 fn test_entity_clone() {
307 let entity = Entity::new("Test".to_string(), create_test_schema("Test"));
308 let cloned = entity.clone();
309 assert_eq!(entity.name(), cloned.name());
310 assert_eq!(entity.table_name(), cloned.table_name());
311 }
312
313 #[test]
314 fn test_entity_debug() {
315 let entity = Entity::new("DebugEntity".to_string(), create_test_schema("DebugEntity"));
316 let debug = format!("{:?}", entity);
317 assert!(debug.contains("Entity"));
318 assert!(debug.contains("DebugEntity"));
319 }
320
321 #[test]
322 fn test_entity_name_getter() {
323 let entity = Entity::new("Customer".to_string(), create_test_schema("Customer"));
324 assert_eq!(entity.name(), "Customer");
325 assert_eq!(entity.name, "Customer");
326 }
327
328 #[test]
330 fn test_entity_registry() {
331 let mut registry = EntityRegistry::new();
332
333 let base_schema = SchemaDefinition::new("User".to_string());
334 let vbr_schema = VbrSchemaDefinition::new(base_schema);
335 let entity = Entity::new("User".to_string(), vbr_schema);
336
337 assert!(registry.register(entity).is_ok());
338 assert!(registry.exists("User"));
339 assert!(registry.get("User").is_some());
340 }
341
342 #[test]
343 fn test_entity_registry_duplicate() {
344 let mut registry = EntityRegistry::new();
345
346 let base_schema1 = SchemaDefinition::new("User".to_string());
347 let vbr_schema1 = VbrSchemaDefinition::new(base_schema1);
348 let entity1 = Entity::new("User".to_string(), vbr_schema1);
349
350 let base_schema2 = SchemaDefinition::new("User".to_string());
351 let vbr_schema2 = VbrSchemaDefinition::new(base_schema2);
352 let entity2 = Entity::new("User".to_string(), vbr_schema2);
353
354 assert!(registry.register(entity1).is_ok());
355 assert!(registry.register(entity2).is_err());
356 }
357
358 #[test]
359 fn test_entity_registry_default() {
360 let registry = EntityRegistry::default();
361 assert!(registry.list().is_empty());
362 }
363
364 #[test]
365 fn test_entity_registry_new() {
366 let registry = EntityRegistry::new();
367 assert!(registry.list().is_empty());
368 assert!(!registry.exists("Anything"));
369 }
370
371 #[test]
372 fn test_entity_registry_get_nonexistent() {
373 let registry = EntityRegistry::new();
374 assert!(registry.get("NonExistent").is_none());
375 }
376
377 #[test]
378 fn test_entity_registry_list() {
379 let mut registry = EntityRegistry::new();
380
381 registry
382 .register(Entity::new("User".to_string(), create_test_schema("User")))
383 .unwrap();
384 registry
385 .register(Entity::new("Order".to_string(), create_test_schema("Order")))
386 .unwrap();
387 registry
388 .register(Entity::new("Product".to_string(), create_test_schema("Product")))
389 .unwrap();
390
391 let list = registry.list();
392 assert_eq!(list.len(), 3);
393 assert!(list.contains(&"User".to_string()));
394 assert!(list.contains(&"Order".to_string()));
395 assert!(list.contains(&"Product".to_string()));
396 }
397
398 #[test]
399 fn test_entity_registry_exists() {
400 let mut registry = EntityRegistry::new();
401 registry
402 .register(Entity::new("User".to_string(), create_test_schema("User")))
403 .unwrap();
404
405 assert!(registry.exists("User"));
406 assert!(!registry.exists("Order"));
407 assert!(!registry.exists("user")); }
409
410 #[test]
411 fn test_entity_registry_remove() {
412 let mut registry = EntityRegistry::new();
413 registry
414 .register(Entity::new("User".to_string(), create_test_schema("User")))
415 .unwrap();
416
417 assert!(registry.exists("User"));
418 assert!(registry.remove("User").is_ok());
419 assert!(!registry.exists("User"));
420 }
421
422 #[test]
423 fn test_entity_registry_remove_nonexistent() {
424 let mut registry = EntityRegistry::new();
425 let result = registry.remove("NonExistent");
426 assert!(result.is_err());
427 }
428
429 #[test]
430 fn test_entity_registry_clone() {
431 let mut registry = EntityRegistry::new();
432 registry
433 .register(Entity::new("User".to_string(), create_test_schema("User")))
434 .unwrap();
435
436 let cloned = registry.clone();
437 assert!(cloned.exists("User"));
438 assert_eq!(cloned.list().len(), 1);
439 }
440
441 #[test]
442 fn test_entity_registry_multiple_operations() {
443 let mut registry = EntityRegistry::new();
444
445 registry
447 .register(Entity::new("A".to_string(), create_test_schema("A")))
448 .unwrap();
449 registry
450 .register(Entity::new("B".to_string(), create_test_schema("B")))
451 .unwrap();
452
453 assert_eq!(registry.list().len(), 2);
455 assert!(registry.exists("A"));
456 assert!(registry.exists("B"));
457
458 registry.remove("A").unwrap();
460 assert_eq!(registry.list().len(), 1);
461 assert!(!registry.exists("A"));
462 assert!(registry.exists("B"));
463
464 registry
466 .register(Entity::new("C".to_string(), create_test_schema("C")))
467 .unwrap();
468 assert_eq!(registry.list().len(), 2);
469 }
470
471 #[test]
472 fn test_entity_registry_get_returns_reference() {
473 let mut registry = EntityRegistry::new();
474 registry
475 .register(Entity::new("User".to_string(), create_test_schema("User")))
476 .unwrap();
477
478 let entity = registry.get("User").unwrap();
479 assert_eq!(entity.name(), "User");
480 assert_eq!(entity.table_name(), "users");
481 }
482}