this/core/
entity.rs

1//! Entity traits defining the core abstraction for all data types
2
3use crate::core::field::FieldValue;
4use anyhow::Result;
5use async_trait::async_trait;
6use std::sync::Arc;
7use uuid::Uuid;
8
9/// Base trait for all entities in the system.
10///
11/// This trait provides the fundamental metadata needed to work with any entity type,
12/// including routing information and service access.
13pub trait Entity: Sized + Send + Sync + 'static {
14    /// The service type that handles operations for this entity
15    type Service: Send + Sync;
16
17    /// The plural resource name used in URLs (e.g., "users", "companies")
18    fn resource_name() -> &'static str;
19
20    /// The singular resource name (e.g., "user", "company")
21    fn resource_name_singular() -> &'static str;
22
23    /// Extract the service instance from the application host/state
24    ///
25    /// This allows the framework to access entity-specific services without
26    /// coupling to specific service implementations
27    fn service_from_host(host: &Arc<dyn std::any::Any + Send + Sync>)
28        -> Result<Arc<Self::Service>>;
29}
30
31/// Trait for data entities that represent concrete domain objects.
32///
33/// Data entities are the primary building blocks of the system. They have:
34/// - A unique identifier
35/// - Tenant isolation
36/// - Searchable fields
37/// - Type information
38pub trait Data: Entity {
39    /// Get the unique identifier for this entity instance
40    fn id(&self) -> Uuid;
41
42    /// Get the tenant ID for multi-tenant isolation
43    fn tenant_id(&self) -> Uuid;
44
45    /// List of fields that should be indexed for searching
46    fn indexed_fields() -> &'static [&'static str];
47
48    /// Get the value of a specific field by name
49    ///
50    /// Returns None if the field doesn't exist or can't be converted
51    fn field_value(&self, field: &str) -> Option<FieldValue>;
52
53    /// Get the type name of this entity (defaults to singular resource name)
54    fn type_name() -> &'static str {
55        Self::resource_name_singular()
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    // Example entity for testing
64    #[derive(Clone)]
65    struct TestEntity {
66        id: Uuid,
67        tenant_id: Uuid,
68        name: String,
69    }
70
71    impl Entity for TestEntity {
72        type Service = ();
73
74        fn resource_name() -> &'static str {
75            "test_entities"
76        }
77
78        fn resource_name_singular() -> &'static str {
79            "test_entity"
80        }
81
82        fn service_from_host(
83            _host: &Arc<dyn std::any::Any + Send + Sync>,
84        ) -> Result<Arc<Self::Service>> {
85            Ok(Arc::new(()))
86        }
87    }
88
89    impl Data for TestEntity {
90        fn id(&self) -> Uuid {
91            self.id
92        }
93
94        fn tenant_id(&self) -> Uuid {
95            self.tenant_id
96        }
97
98        fn indexed_fields() -> &'static [&'static str] {
99            &["name"]
100        }
101
102        fn field_value(&self, field: &str) -> Option<FieldValue> {
103            match field {
104                "name" => Some(FieldValue::String(self.name.clone())),
105                _ => None,
106            }
107        }
108    }
109
110    #[test]
111    fn test_entity_metadata() {
112        assert_eq!(TestEntity::resource_name(), "test_entities");
113        assert_eq!(TestEntity::resource_name_singular(), "test_entity");
114        assert_eq!(TestEntity::type_name(), "test_entity");
115    }
116}