1use crate::core::{Data, EntityReference, Link};
4use anyhow::Result;
5use async_trait::async_trait;
6use uuid::Uuid;
7
8#[async_trait]
13pub trait DataService<T: Data>: Send + Sync {
14 async fn create(&self, tenant_id: &Uuid, entity: T) -> Result<T>;
16
17 async fn get(&self, tenant_id: &Uuid, id: &Uuid) -> Result<Option<T>>;
19
20 async fn list(&self, tenant_id: &Uuid) -> Result<Vec<T>>;
22
23 async fn update(&self, tenant_id: &Uuid, id: &Uuid, entity: T) -> Result<T>;
25
26 async fn delete(&self, tenant_id: &Uuid, id: &Uuid) -> Result<()>;
28
29 async fn search(&self, tenant_id: &Uuid, field: &str, value: &str) -> Result<Vec<T>>;
31}
32
33#[async_trait]
38pub trait LinkService: Send + Sync {
39 async fn create(
41 &self,
42 tenant_id: &Uuid,
43 link_type: &str,
44 source: EntityReference,
45 target: EntityReference,
46 metadata: Option<serde_json::Value>,
47 ) -> Result<Link>;
48
49 async fn get(&self, tenant_id: &Uuid, id: &Uuid) -> Result<Option<Link>>;
51
52 async fn list(&self, tenant_id: &Uuid) -> Result<Vec<Link>>;
54
55 async fn find_by_source(
59 &self,
60 tenant_id: &Uuid,
61 source_id: &Uuid,
62 source_type: &str,
63 link_type: Option<&str>,
64 target_type: Option<&str>,
65 ) -> Result<Vec<Link>>;
66
67 async fn find_by_target(
71 &self,
72 tenant_id: &Uuid,
73 target_id: &Uuid,
74 target_type: &str,
75 link_type: Option<&str>,
76 source_type: Option<&str>,
77 ) -> Result<Vec<Link>>;
78
79 async fn update(
85 &self,
86 tenant_id: &Uuid,
87 id: &Uuid,
88 metadata: Option<serde_json::Value>,
89 ) -> Result<Link>;
90
91 async fn delete(&self, tenant_id: &Uuid, id: &Uuid) -> Result<()>;
93
94 async fn delete_by_entity(
98 &self,
99 tenant_id: &Uuid,
100 entity_id: &Uuid,
101 entity_type: &str,
102 ) -> Result<()>;
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::core::entity::Entity;
109
110 #[allow(dead_code)]
112 #[derive(Clone, Debug)]
113 struct TestEntity {
114 id: Uuid,
115 tenant_id: Uuid,
116 }
117
118 impl Entity for TestEntity {
119 type Service = ();
120 fn resource_name() -> &'static str {
121 "tests"
122 }
123 fn resource_name_singular() -> &'static str {
124 "test"
125 }
126 fn service_from_host(
127 _: &std::sync::Arc<dyn std::any::Any + Send + Sync>,
128 ) -> Result<std::sync::Arc<Self::Service>> {
129 Ok(std::sync::Arc::new(()))
130 }
131 }
132
133 impl Data for TestEntity {
134 fn id(&self) -> Uuid {
135 self.id
136 }
137 fn tenant_id(&self) -> Uuid {
138 self.tenant_id
139 }
140 fn indexed_fields() -> &'static [&'static str] {
141 &[]
142 }
143 fn field_value(&self, _field: &str) -> Option<crate::core::field::FieldValue> {
144 None
145 }
146 }
147
148 #[allow(dead_code)]
150 async fn generic_create<T, S>(service: &S, tenant_id: &Uuid, entity: T) -> Result<T>
151 where
152 T: Data,
153 S: DataService<T>,
154 {
155 service.create(tenant_id, entity).await
156 }
157
158 #[test]
159 fn test_traits_compile() {
160 }
163}