use crate::domain::{Edge, GraphQuery, Node, NodeId};
use async_trait::async_trait;
use thiserror::Error;
use chrono::{DateTime, Utc};
#[derive(Debug, Clone)]
pub struct SearchQuery {
pub node_types: Vec<String>,
pub search_text: Option<String>,
pub created_after: Option<DateTime<Utc>>,
pub created_before: Option<DateTime<Utc>>,
pub updated_after: Option<DateTime<Utc>>,
pub property_filters: Vec<(String, String)>,
pub limit: usize,
pub offset: usize,
}
impl Default for SearchQuery {
fn default() -> Self {
Self {
node_types: vec![],
search_text: None,
created_after: None,
created_before: None,
updated_after: None,
property_filters: vec![],
limit: 50,
offset: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct SearchResults<T> {
pub items: Vec<T>,
}
#[derive(Error, Debug)]
pub enum StorageError {
#[error("Node not found: {0}")]
NodeNotFound(NodeId),
#[error("Database error: {0}")]
DatabaseError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Constraint violation: {0}")]
ConstraintViolation(String),
}
pub type Result<T> = std::result::Result<T, StorageError>;
#[async_trait]
pub trait GraphStorage: Send + Sync {
async fn create_node(&self, node: &Node) -> Result<Node>;
async fn get_node(&self, id: NodeId) -> Result<Node>;
async fn update_node(&self, node: &Node) -> Result<Node>;
async fn delete_node(&self, id: NodeId) -> Result<()>;
async fn query_nodes(&self, query: &GraphQuery) -> Result<Vec<Node>>;
async fn create_edge(&self, edge: &Edge) -> Result<Edge>;
async fn get_edges_from(&self, node_id: NodeId, edge_type: Option<&str>) -> Result<Vec<Edge>>;
async fn get_edges_to(&self, node_id: NodeId, edge_type: Option<&str>) -> Result<Vec<Edge>>;
async fn get_neighbors(
&self,
node_id: NodeId,
edge_type: Option<&str>,
direction: EdgeDirection,
) -> Result<Vec<Node>>;
async fn search_nodes(&self, query: &SearchQuery) -> Result<SearchResults<Node>>;
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EdgeDirection {
Outgoing,
Incoming,
}
pub mod memory;
pub mod postgres;