this/core/
service.rs

1//! Service traits for data and link operations
2
3use crate::core::{link::LinkEntity, Data};
4use anyhow::Result;
5use async_trait::async_trait;
6use uuid::Uuid;
7
8/// Service trait for managing data entities
9///
10/// Implementations provide CRUD operations for a specific entity type.
11/// The framework is agnostic to the underlying storage mechanism.
12#[async_trait]
13pub trait DataService<T: Data>: Send + Sync {
14    /// Create a new entity
15    async fn create(&self, entity: T) -> Result<T>;
16
17    /// Get an entity by ID
18    async fn get(&self, id: &Uuid) -> Result<Option<T>>;
19
20    /// List all entities
21    async fn list(&self) -> Result<Vec<T>>;
22
23    /// Update an existing entity
24    async fn update(&self, id: &Uuid, entity: T) -> Result<T>;
25
26    /// Delete an entity
27    async fn delete(&self, id: &Uuid) -> Result<()>;
28
29    /// Search entities by field values
30    async fn search(&self, field: &str, value: &str) -> Result<Vec<T>>;
31}
32
33/// Service trait for managing links between entities
34///
35/// This service is completely agnostic to entity types - it only manages
36/// relationships using UUIDs and string identifiers.
37#[async_trait]
38pub trait LinkService: Send + Sync {
39    /// Create a new link between two entities
40    async fn create(&self, link: LinkEntity) -> Result<LinkEntity>;
41
42    /// Get a specific link by ID
43    async fn get(&self, id: &Uuid) -> Result<Option<LinkEntity>>;
44
45    /// List all links
46    async fn list(&self) -> Result<Vec<LinkEntity>>;
47
48    /// Find links by source entity
49    ///
50    /// Optionally filter by link_type and/or target_type
51    async fn find_by_source(
52        &self,
53        source_id: &Uuid,
54        link_type: Option<&str>,
55        target_type: Option<&str>,
56    ) -> Result<Vec<LinkEntity>>;
57
58    /// Find links by target entity
59    ///
60    /// Optionally filter by link_type and/or source_type
61    async fn find_by_target(
62        &self,
63        target_id: &Uuid,
64        link_type: Option<&str>,
65        source_type: Option<&str>,
66    ) -> Result<Vec<LinkEntity>>;
67
68    /// Update a link's metadata
69    ///
70    /// This allows updating the metadata associated with a link without
71    /// recreating it. Useful for adding/modifying contextual information
72    /// like status, dates, permissions, etc.
73    async fn update(&self, id: &Uuid, link: LinkEntity) -> Result<LinkEntity>;
74
75    /// Delete a link
76    async fn delete(&self, id: &Uuid) -> Result<()>;
77
78    /// Delete all links involving a specific entity
79    ///
80    /// Used when deleting an entity to maintain referential integrity
81    async fn delete_by_entity(&self, entity_id: &Uuid) -> Result<()>;
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::core::entity::Entity;
88    use chrono::{DateTime, Utc};
89
90    // Mock entity for testing
91    #[allow(dead_code)]
92    #[derive(Clone, Debug)]
93    struct TestEntity {
94        id: Uuid,
95        entity_type: String,
96        created_at: DateTime<Utc>,
97        updated_at: DateTime<Utc>,
98        deleted_at: Option<DateTime<Utc>>,
99        status: String,
100        name: String,
101    }
102
103    impl Entity for TestEntity {
104        type Service = ();
105
106        fn resource_name() -> &'static str {
107            "tests"
108        }
109
110        fn resource_name_singular() -> &'static str {
111            "test"
112        }
113
114        fn service_from_host(
115            _: &std::sync::Arc<dyn std::any::Any + Send + Sync>,
116        ) -> Result<std::sync::Arc<Self::Service>> {
117            Ok(std::sync::Arc::new(()))
118        }
119
120        fn id(&self) -> Uuid {
121            self.id
122        }
123
124        fn entity_type(&self) -> &str {
125            &self.entity_type
126        }
127
128        fn created_at(&self) -> DateTime<Utc> {
129            self.created_at
130        }
131
132        fn updated_at(&self) -> DateTime<Utc> {
133            self.updated_at
134        }
135
136        fn deleted_at(&self) -> Option<DateTime<Utc>> {
137            self.deleted_at
138        }
139
140        fn status(&self) -> &str {
141            &self.status
142        }
143    }
144
145    impl Data for TestEntity {
146        fn name(&self) -> &str {
147            &self.name
148        }
149
150        fn indexed_fields() -> &'static [&'static str] {
151            &[]
152        }
153
154        fn field_value(&self, _field: &str) -> Option<crate::core::field::FieldValue> {
155            None
156        }
157    }
158
159    // The traits compile and can be used in generic contexts
160    #[allow(dead_code)]
161    async fn generic_create<T, S>(service: &S, entity: T) -> Result<T>
162    where
163        T: Data,
164        S: DataService<T>,
165    {
166        service.create(entity).await
167    }
168
169    #[test]
170    fn test_traits_compile() {
171        // This test just verifies that the traits are correctly defined
172        // and can be used in generic contexts
173    }
174}