use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::error::{EmbeddingError, VectorStoreError};
use crate::layer1_echo::filter::MetadataFilter;
use crate::types::{Document, DocumentId, SearchResult};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum SimilarityMetric {
#[default]
Cosine,
Euclidean,
DotProduct,
}
#[async_trait]
pub trait EmbeddingProvider: Send + Sync {
async fn embed(&self, text: &str) -> Result<Vec<f32>, EmbeddingError>;
async fn embed_batch(&self, texts: &[&str]) -> Result<Vec<Vec<f32>>, EmbeddingError>;
fn dimension(&self) -> usize;
fn model_id(&self) -> &str;
}
#[derive(Debug, Clone)]
pub struct IndexedDocument {
pub document: Document,
pub embedding: Vec<f32>,
}
impl IndexedDocument {
#[must_use]
pub fn new(document: Document, embedding: Vec<f32>) -> Self {
Self {
document,
embedding,
}
}
}
#[async_trait]
pub trait VectorStore: Send + Sync {
async fn insert(&mut self, doc: IndexedDocument) -> Result<(), VectorStoreError>;
async fn insert_batch(&mut self, docs: Vec<IndexedDocument>) -> Result<(), VectorStoreError>;
async fn get(&self, id: &DocumentId) -> Result<Option<IndexedDocument>, VectorStoreError>;
async fn delete(&mut self, id: &DocumentId) -> Result<bool, VectorStoreError>;
async fn update(
&mut self,
id: &DocumentId,
embedding: Vec<f32>,
) -> Result<bool, VectorStoreError>;
async fn upsert(&mut self, doc: IndexedDocument) -> Result<bool, VectorStoreError>;
async fn search(
&self,
query_embedding: &[f32],
top_k: usize,
min_score: Option<f32>,
) -> Result<Vec<SearchResult>, VectorStoreError>;
async fn search_with_filter(
&self,
query_embedding: &[f32],
top_k: usize,
min_score: Option<f32>,
filter: Option<&MetadataFilter>,
) -> Result<Vec<SearchResult>, VectorStoreError>;
async fn count(&self) -> usize;
async fn clear(&mut self) -> Result<(), VectorStoreError>;
fn dimension(&self) -> usize;
fn similarity_metric(&self) -> SimilarityMetric;
}
#[async_trait]
pub trait Echo: Send + Sync {
async fn index(&mut self, document: Document) -> Result<DocumentId, EmbeddingError>;
async fn index_batch(
&mut self,
documents: Vec<Document>,
) -> Result<Vec<DocumentId>, EmbeddingError>;
async fn search(
&self,
query: &str,
top_k: usize,
min_score: Option<f32>,
) -> Result<Vec<SearchResult>, EmbeddingError>;
async fn get(&self, id: &DocumentId) -> Result<Option<Document>, EmbeddingError>;
async fn delete(&mut self, id: &DocumentId) -> Result<bool, EmbeddingError>;
async fn count(&self) -> usize;
async fn clear(&mut self) -> Result<(), EmbeddingError>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_similarity_metric_default() {
let metric = SimilarityMetric::default();
assert_eq!(metric, SimilarityMetric::Cosine);
}
#[test]
fn test_indexed_document_creation() {
let doc = Document::new("test content");
let embedding = vec![0.1, 0.2, 0.3];
let indexed = IndexedDocument::new(doc.clone(), embedding.clone());
assert_eq!(indexed.document.content, "test content");
assert_eq!(indexed.embedding, embedding);
}
}