1pub mod memory;
11pub mod migrations;
12pub mod models;
13#[cfg(not(target_arch = "wasm32"))]
14pub mod sqlite;
15#[cfg(target_arch = "wasm32")]
16pub mod wasm;
17
18use async_trait::async_trait;
19use std::error::Error as StdError;
20use thiserror::Error;
21
22pub use models::{AgentModel, EventModel, MessageModel, MetricModel, TaskModel};
23
24#[cfg(not(target_arch = "wasm32"))]
25pub use sqlite::SqliteStorage;
26#[cfg(target_arch = "wasm32")]
27pub use wasm::WasmStorage;
28pub use memory::MemoryStorage;
29
30#[derive(Error, Debug)]
32pub enum StorageError {
33 #[error("Database error: {0}")]
34 Database(String),
35
36 #[error("Serialization error: {0}")]
37 Serialization(#[from] serde_json::Error),
38
39 #[error("Not found: {0}")]
40 NotFound(String),
41
42 #[error("Transaction error: {0}")]
43 Transaction(String),
44
45 #[error("Migration error: {0}")]
46 Migration(String),
47
48 #[error("Connection pool error: {0}")]
49 Pool(String),
50
51 #[error("Other error: {0}")]
52 Other(String),
53}
54
55impl From<Box<dyn StdError + Send + Sync>> for StorageError {
56 fn from(err: Box<dyn StdError + Send + Sync>) -> Self {
57 StorageError::Other(err.to_string())
58 }
59}
60
61#[async_trait]
63pub trait Storage: Send + Sync {
64 type Error: StdError + Send + Sync + 'static;
65
66 async fn store_agent(&self, agent: &AgentModel) -> Result<(), Self::Error>;
68 async fn get_agent(&self, id: &str) -> Result<Option<AgentModel>, Self::Error>;
69 async fn update_agent(&self, agent: &AgentModel) -> Result<(), Self::Error>;
70 async fn delete_agent(&self, id: &str) -> Result<(), Self::Error>;
71 async fn list_agents(&self) -> Result<Vec<AgentModel>, Self::Error>;
72 async fn list_agents_by_status(&self, status: &str) -> Result<Vec<AgentModel>, Self::Error>;
73
74 async fn store_task(&self, task: &TaskModel) -> Result<(), Self::Error>;
76 async fn get_task(&self, id: &str) -> Result<Option<TaskModel>, Self::Error>;
77 async fn update_task(&self, task: &TaskModel) -> Result<(), Self::Error>;
78 async fn get_pending_tasks(&self) -> Result<Vec<TaskModel>, Self::Error>;
79 async fn get_tasks_by_agent(&self, agent_id: &str) -> Result<Vec<TaskModel>, Self::Error>;
80 async fn claim_task(&self, task_id: &str, agent_id: &str) -> Result<bool, Self::Error>;
81
82 async fn store_event(&self, event: &EventModel) -> Result<(), Self::Error>;
84 async fn get_events_by_agent(&self, agent_id: &str, limit: usize) -> Result<Vec<EventModel>, Self::Error>;
85 async fn get_events_by_type(&self, event_type: &str, limit: usize) -> Result<Vec<EventModel>, Self::Error>;
86 async fn get_events_since(&self, timestamp: i64) -> Result<Vec<EventModel>, Self::Error>;
87
88 async fn store_message(&self, message: &MessageModel) -> Result<(), Self::Error>;
90 async fn get_messages_between(&self, agent1: &str, agent2: &str, limit: usize) -> Result<Vec<MessageModel>, Self::Error>;
91 async fn get_unread_messages(&self, agent_id: &str) -> Result<Vec<MessageModel>, Self::Error>;
92 async fn mark_message_read(&self, message_id: &str) -> Result<(), Self::Error>;
93
94 async fn store_metric(&self, metric: &MetricModel) -> Result<(), Self::Error>;
96 async fn get_metrics_by_agent(&self, agent_id: &str, metric_type: &str) -> Result<Vec<MetricModel>, Self::Error>;
97 async fn get_aggregated_metrics(&self, metric_type: &str, start_time: i64, end_time: i64) -> Result<Vec<MetricModel>, Self::Error>;
98
99 async fn begin_transaction(&self) -> Result<Box<dyn Transaction>, Self::Error>;
101
102 async fn vacuum(&self) -> Result<(), Self::Error>;
104 async fn checkpoint(&self) -> Result<(), Self::Error>;
105 async fn get_storage_size(&self) -> Result<u64, Self::Error>;
106}
107
108#[async_trait]
110pub trait Transaction: Send + Sync {
111 async fn commit(self: Box<Self>) -> Result<(), StorageError>;
112 async fn rollback(self: Box<Self>) -> Result<(), StorageError>;
113}
114
115pub struct QueryBuilder<T> {
117 table: String,
118 conditions: Vec<String>,
119 order_by: Option<String>,
120 limit: Option<usize>,
121 offset: Option<usize>,
122 _phantom: std::marker::PhantomData<T>,
123}
124
125impl<T> QueryBuilder<T> {
126 pub fn new(table: &str) -> Self {
127 Self {
128 table: table.to_string(),
129 conditions: Vec::new(),
130 order_by: None,
131 limit: None,
132 offset: None,
133 _phantom: std::marker::PhantomData,
134 }
135 }
136
137 pub fn where_eq(mut self, field: &str, value: &str) -> Self {
138 self.conditions.push(format!("{} = '{}'", field, value));
139 self
140 }
141
142 pub fn where_like(mut self, field: &str, pattern: &str) -> Self {
143 self.conditions.push(format!("{} LIKE '{}'", field, pattern));
144 self
145 }
146
147 pub fn where_gt(mut self, field: &str, value: i64) -> Self {
148 self.conditions.push(format!("{} > {}", field, value));
149 self
150 }
151
152 pub fn order_by(mut self, field: &str, desc: bool) -> Self {
153 self.order_by = Some(format!("{} {}", field, if desc { "DESC" } else { "ASC" }));
154 self
155 }
156
157 pub fn limit(mut self, limit: usize) -> Self {
158 self.limit = Some(limit);
159 self
160 }
161
162 pub fn offset(mut self, offset: usize) -> Self {
163 self.offset = Some(offset);
164 self
165 }
166
167 pub fn build(&self) -> String {
168 let mut query = format!("SELECT * FROM {}", self.table);
169
170 if !self.conditions.is_empty() {
171 query.push_str(" WHERE ");
172 query.push_str(&self.conditions.join(" AND "));
173 }
174
175 if let Some(ref order) = self.order_by {
176 query.push_str(" ORDER BY ");
177 query.push_str(order);
178 }
179
180 if let Some(limit) = self.limit {
181 query.push_str(&format!(" LIMIT {}", limit));
182 }
183
184 if let Some(offset) = self.offset {
185 query.push_str(&format!(" OFFSET {}", offset));
186 }
187
188 query
189 }
190}
191
192pub trait Repository<T> {
194 type Error: StdError + Send + Sync + 'static;
195
196 fn find_by_id(&self, id: &str) -> Result<Option<T>, Self::Error>;
197 fn find_all(&self) -> Result<Vec<T>, Self::Error>;
198 fn save(&self, entity: &T) -> Result<(), Self::Error>;
199 fn update(&self, entity: &T) -> Result<(), Self::Error>;
200 fn delete(&self, id: &str) -> Result<(), Self::Error>;
201 fn query(&self, builder: QueryBuilder<T>) -> Result<Vec<T>, Self::Error>;
202}
203
204pub async fn init_storage(path: Option<&str>) -> Result<Box<dyn Storage<Error = StorageError>>, StorageError> {
206 #[cfg(not(target_arch = "wasm32"))]
207 {
208 let path = path.unwrap_or("swarm.db");
209 Ok(Box::new(SqliteStorage::new(path).await?))
210 }
211
212 #[cfg(target_arch = "wasm32")]
213 {
214 Ok(Box::new(WasmStorage::new().await?))
215 }
216}
217
218#[cfg(test)]
219mod tests;