Skip to main content

agent_office/storage/
mod.rs

1use crate::domain::{Edge, GraphQuery, Node, NodeId, EdgeId};
2use async_trait::async_trait;
3use thiserror::Error;
4use chrono::{DateTime, Utc};
5
6/// Advanced search query with full-text, time range, and pagination support
7#[derive(Debug, Clone)]
8pub struct SearchQuery {
9    /// Node types to search (e.g., "mail", "note", "agent")
10    pub node_types: Vec<String>,
11    /// Full-text search pattern (PostgreSQL tsquery compatible)
12    pub search_text: Option<String>,
13    /// Search in specific fields/properties
14    pub search_fields: Vec<String>,
15    /// Created/modified after this time
16    pub created_after: Option<DateTime<Utc>>,
17    /// Created/modified before this time
18    pub created_before: Option<DateTime<Utc>>,
19    /// Updated after this time
20    pub updated_after: Option<DateTime<Utc>>,
21    /// Property filters
22    pub property_filters: Vec<(String, String)>,
23    /// Maximum results to return
24    pub limit: usize,
25    /// Offset for pagination
26    pub offset: usize,
27    /// Order by field (created_at, updated_at, relevance)
28    pub order_by: OrderBy,
29    /// Order direction
30    pub order_direction: OrderDirection,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq)]
34pub enum OrderBy {
35    CreatedAt,
36    UpdatedAt,
37    Relevance,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq)]
41pub enum OrderDirection {
42    Asc,
43    Desc,
44}
45
46impl Default for SearchQuery {
47    fn default() -> Self {
48        Self {
49            node_types: vec![],
50            search_text: None,
51            search_fields: vec![],
52            created_after: None,
53            created_before: None,
54            updated_after: None,
55            property_filters: vec![],
56            limit: 50,
57            offset: 0,
58            order_by: OrderBy::UpdatedAt,
59            order_direction: OrderDirection::Desc,
60        }
61    }
62}
63
64/// Search results with pagination info
65#[derive(Debug, Clone)]
66pub struct SearchResults<T> {
67    pub items: Vec<T>,
68    pub total_count: usize,
69    pub returned_count: usize,
70    pub has_more: bool,
71    pub limit: usize,
72    pub offset: usize,
73}
74
75#[derive(Error, Debug)]
76pub enum StorageError {
77    #[error("Node not found: {0}")]
78    NodeNotFound(NodeId),
79    
80    #[error("Edge not found: {0}")]
81    EdgeNotFound(EdgeId),
82    
83    #[error("Database error: {0}")]
84    DatabaseError(String),
85    
86    #[error("Serialization error: {0}")]
87    SerializationError(String),
88    
89    #[error("Constraint violation: {0}")]
90    ConstraintViolation(String),
91}
92
93pub type Result<T> = std::result::Result<T, StorageError>;
94
95#[async_trait]
96pub trait GraphStorage: Send + Sync {
97    // Node operations
98    async fn create_node(&self, node: &Node) -> Result<Node>;
99    async fn get_node(&self, id: NodeId) -> Result<Node>;
100    async fn update_node(&self, node: &Node) -> Result<Node>;
101    async fn delete_node(&self, id: NodeId) -> Result<()>;
102    async fn query_nodes(&self, query: &GraphQuery) -> Result<Vec<Node>>;
103    
104    // Edge operations
105    async fn create_edge(&self, edge: &Edge) -> Result<Edge>;
106    async fn get_edge(&self, id: EdgeId) -> Result<Edge>;
107    async fn delete_edge(&self, id: EdgeId) -> Result<()>;
108    async fn get_edges_from(&self, node_id: NodeId, edge_type: Option<&str>) -> Result<Vec<Edge>>;
109    async fn get_edges_to(&self, node_id: NodeId, edge_type: Option<&str>) -> Result<Vec<Edge>>;
110    
111    // Graph traversal
112    async fn get_neighbors(
113        &self,
114        node_id: NodeId,
115        edge_type: Option<&str>,
116        direction: EdgeDirection,
117    ) -> Result<Vec<Node>>;
118    
119    // Advanced search with full-text, time range, and pagination
120    async fn search_nodes(&self, query: &SearchQuery) -> Result<SearchResults<Node>>;
121    
122    // Count total results without fetching
123    async fn count_nodes(&self, query: &SearchQuery) -> Result<usize>;
124}
125
126#[derive(Debug, Clone, Copy, PartialEq)]
127pub enum EdgeDirection {
128    Outgoing,
129    Incoming,
130    Both,
131}
132
133#[async_trait]
134pub trait TransactionalGraphStorage: GraphStorage {
135    async fn begin_transaction(&self) -> Result<Box<dyn GraphTransaction>>;
136}
137
138#[async_trait]
139pub trait GraphTransaction: Send + Sync {
140    async fn commit(self: Box<Self>) -> Result<()>;
141    async fn rollback(self: Box<Self>) -> Result<()>;
142}
143
144pub mod memory;
145pub mod postgres;