1use anyhow::Result;
4use chrono::{DateTime, Utc};
5use std::sync::Arc;
6use uuid::Uuid;
7
8pub trait Entity: Clone + Send + Sync + 'static {
19 type Service: Send + Sync;
21
22 fn resource_name() -> &'static str;
24
25 fn resource_name_singular() -> &'static str;
27
28 fn service_from_host(host: &Arc<dyn std::any::Any + Send + Sync>)
30 -> Result<Arc<Self::Service>>;
31
32 fn id(&self) -> Uuid;
36
37 fn entity_type(&self) -> &str;
39
40 fn created_at(&self) -> DateTime<Utc>;
42
43 fn updated_at(&self) -> DateTime<Utc>;
45
46 fn deleted_at(&self) -> Option<DateTime<Utc>>;
48
49 fn status(&self) -> &str;
51
52 fn is_deleted(&self) -> bool {
56 self.deleted_at().is_some()
57 }
58
59 fn is_active(&self) -> bool {
61 self.status() == "active" && !self.is_deleted()
62 }
63}
64
65pub trait Data: Entity {
72 fn name(&self) -> &str;
74
75 fn indexed_fields() -> &'static [&'static str];
77
78 fn field_value(&self, field: &str) -> Option<crate::core::field::FieldValue>;
80
81 fn display(&self) {
83 println!(
84 "[{}] {} - {} ({})",
85 self.id(),
86 self.entity_type(),
87 self.name(),
88 self.status()
89 );
90 }
91}
92
93pub trait Link: Entity {
100 fn source_id(&self) -> Uuid;
102
103 fn target_id(&self) -> Uuid;
105
106 fn link_type(&self) -> &str;
108
109 fn display(&self) {
111 println!(
112 "[{}] {} → {} (type: {}, status: {})",
113 self.id(),
114 self.source_id(),
115 self.target_id(),
116 self.link_type(),
117 self.status()
118 );
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use serde::{Deserialize, Serialize};
126
127 #[derive(Clone, Debug, Serialize, Deserialize)]
129 struct TestEntity {
130 id: Uuid,
131 entity_type: String,
132 created_at: DateTime<Utc>,
133 updated_at: DateTime<Utc>,
134 deleted_at: Option<DateTime<Utc>>,
135 status: String,
136 }
137
138 impl Entity for TestEntity {
139 type Service = ();
140
141 fn resource_name() -> &'static str {
142 "test_entities"
143 }
144
145 fn resource_name_singular() -> &'static str {
146 "test_entity"
147 }
148
149 fn service_from_host(
150 _host: &Arc<dyn std::any::Any + Send + Sync>,
151 ) -> Result<Arc<Self::Service>> {
152 Ok(Arc::new(()))
153 }
154
155 fn id(&self) -> Uuid {
156 self.id
157 }
158
159 fn entity_type(&self) -> &str {
160 &self.entity_type
161 }
162
163 fn created_at(&self) -> DateTime<Utc> {
164 self.created_at
165 }
166
167 fn updated_at(&self) -> DateTime<Utc> {
168 self.updated_at
169 }
170
171 fn deleted_at(&self) -> Option<DateTime<Utc>> {
172 self.deleted_at
173 }
174
175 fn status(&self) -> &str {
176 &self.status
177 }
178 }
179
180 #[test]
181 fn test_entity_is_deleted() {
182 let now = Utc::now();
183 let mut entity = TestEntity {
184 id: Uuid::new_v4(),
185 entity_type: "test".to_string(),
186 created_at: now,
187 updated_at: now,
188 deleted_at: None,
189 status: "active".to_string(),
190 };
191
192 assert!(!entity.is_deleted());
193 assert!(entity.is_active());
194
195 entity.deleted_at = Some(now);
196 assert!(entity.is_deleted());
197 assert!(!entity.is_active());
198 }
199
200 #[test]
201 fn test_entity_metadata() {
202 assert_eq!(TestEntity::resource_name(), "test_entities");
203 assert_eq!(TestEntity::resource_name_singular(), "test_entity");
204 }
205}