use async_trait::async_trait;
use super::entities::{EmbeddingId, SimilarityEdge, EdgeType, StoredVector, VectorMetadata};
use super::error::VectorError;
pub type RepoResult<T> = Result<T, VectorError>;
#[async_trait]
pub trait VectorIndexRepository: Send + Sync {
async fn insert(&self, id: &EmbeddingId, vector: &[f32]) -> RepoResult<()>;
async fn search(&self, query: &[f32], k: usize) -> RepoResult<Vec<(EmbeddingId, f32)>>;
async fn batch_insert(&self, items: &[(EmbeddingId, Vec<f32>)]) -> RepoResult<()>;
async fn remove(&self, id: &EmbeddingId) -> RepoResult<()>;
async fn contains(&self, id: &EmbeddingId) -> RepoResult<bool>;
async fn len(&self) -> RepoResult<usize>;
async fn is_empty(&self) -> RepoResult<bool> {
Ok(self.len().await? == 0)
}
async fn clear(&self) -> RepoResult<()>;
fn dimensions(&self) -> usize;
}
#[async_trait]
pub trait VectorIndexRepositoryExt: VectorIndexRepository {
async fn search_with_filter<F>(
&self,
query: &[f32],
k: usize,
filter: F,
) -> RepoResult<Vec<(EmbeddingId, f32)>>
where
F: Fn(&EmbeddingId) -> bool + Send + Sync;
async fn search_within_radius(
&self,
query: &[f32],
radius: f32,
max_results: usize,
) -> RepoResult<Vec<(EmbeddingId, f32)>>;
async fn get_vectors(&self, ids: &[EmbeddingId]) -> RepoResult<Vec<Option<StoredVector>>>;
async fn get_vector(&self, id: &EmbeddingId) -> RepoResult<Option<StoredVector>>;
async fn update_metadata(&self, id: &EmbeddingId, metadata: VectorMetadata) -> RepoResult<()>;
async fn list_ids(&self, offset: usize, limit: usize) -> RepoResult<Vec<EmbeddingId>>;
}
#[async_trait]
pub trait GraphEdgeRepository: Send + Sync {
async fn add_edge(&self, edge: SimilarityEdge) -> RepoResult<()>;
async fn add_edges(&self, edges: &[SimilarityEdge]) -> RepoResult<()>;
async fn remove_edge(&self, from: &EmbeddingId, to: &EmbeddingId) -> RepoResult<()>;
async fn get_edges_from(&self, id: &EmbeddingId) -> RepoResult<Vec<SimilarityEdge>>;
async fn get_edges_to(&self, id: &EmbeddingId) -> RepoResult<Vec<SimilarityEdge>>;
async fn get_edges_by_type(
&self,
id: &EmbeddingId,
edge_type: EdgeType,
) -> RepoResult<Vec<SimilarityEdge>>;
async fn get_strong_edges(
&self,
id: &EmbeddingId,
min_similarity: f32,
) -> RepoResult<Vec<SimilarityEdge>>;
async fn edge_count(&self) -> RepoResult<usize>;
async fn clear(&self) -> RepoResult<()>;
async fn remove_edges_for(&self, id: &EmbeddingId) -> RepoResult<()>;
}
#[async_trait]
pub trait GraphTraversal: GraphEdgeRepository {
async fn shortest_path(
&self,
from: &EmbeddingId,
to: &EmbeddingId,
max_depth: usize,
) -> RepoResult<Option<Vec<EmbeddingId>>>;
async fn neighbors_within_hops(
&self,
id: &EmbeddingId,
hops: usize,
) -> RepoResult<Vec<(EmbeddingId, usize)>>;
async fn connected_components(&self) -> RepoResult<Vec<Vec<EmbeddingId>>>;
async fn centrality_scores(&self) -> RepoResult<Vec<(EmbeddingId, f32)>>;
}
#[async_trait]
pub trait IndexPersistence: Send + Sync {
async fn save(&self, path: &std::path::Path) -> RepoResult<()>;
async fn load(path: &std::path::Path) -> RepoResult<Self>
where
Self: Sized;
async fn export(&self, path: &std::path::Path, format: ExportFormat) -> RepoResult<()>;
async fn import(&self, path: &std::path::Path, format: ExportFormat) -> RepoResult<usize>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportFormat {
Bincode,
Json,
Numpy,
Csv,
}
#[derive(Debug, Clone)]
pub struct IndexStats {
pub vector_count: usize,
pub memory_bytes: usize,
pub avg_search_latency_us: f64,
pub build_time_ms: u64,
pub dimensions: usize,
pub levels: usize,
pub avg_connections: f64,
}
#[async_trait]
pub trait IndexMonitoring: Send + Sync {
async fn stats(&self) -> RepoResult<IndexStats>;
async fn memory_usage(&self) -> RepoResult<MemoryUsage>;
async fn verify(&self) -> RepoResult<VerificationResult>;
}
#[derive(Debug, Clone)]
pub struct MemoryUsage {
pub vectors_bytes: usize,
pub graph_bytes: usize,
pub id_map_bytes: usize,
pub metadata_bytes: usize,
pub total_bytes: usize,
}
#[derive(Debug, Clone)]
pub struct VerificationResult {
pub is_valid: bool,
pub issues: Vec<String>,
pub orphaned_nodes: usize,
pub broken_links: usize,
}
impl VerificationResult {
pub fn ok() -> Self {
Self {
is_valid: true,
issues: Vec::new(),
orphaned_nodes: 0,
broken_links: 0,
}
}
pub fn failed(issues: Vec<String>) -> Self {
Self {
is_valid: false,
issues,
orphaned_nodes: 0,
broken_links: 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_verification_result() {
let ok = VerificationResult::ok();
assert!(ok.is_valid);
assert!(ok.issues.is_empty());
let failed = VerificationResult::failed(vec!["test issue".into()]);
assert!(!failed.is_valid);
assert_eq!(failed.issues.len(), 1);
}
}