Skip to main content

brainwires_core/
vector_store.rs

1//! Vector store abstraction
2//!
3//! Provides the `VectorStore` trait for pluggable vector database backends.
4//! Implementations live in downstream crates (storage with LanceDB, rag with
5//! LanceDB/Qdrant) — this trait enables consumers to swap backends without
6//! changing application code.
7
8use anyhow::Result;
9use async_trait::async_trait;
10use serde::{Deserialize, Serialize};
11
12/// Result from a vector similarity search.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct VectorSearchResult {
15    /// Unique identifier for the stored item.
16    pub id: String,
17    /// Similarity score (higher = more similar, typically 0.0–1.0).
18    pub score: f32,
19    /// The text content of the matched chunk.
20    pub content: String,
21    /// Arbitrary metadata associated with the item.
22    pub metadata: serde_json::Value,
23}
24
25/// Trait for vector database operations.
26///
27/// Provides a backend-agnostic interface for storing and searching embeddings.
28/// Implementations should handle connection management internally.
29///
30/// # Example
31///
32/// ```ignore
33/// use brainwires_core::{VectorStore, VectorSearchResult};
34///
35/// async fn search(store: &dyn VectorStore, query_vec: Vec<f32>) -> anyhow::Result<Vec<VectorSearchResult>> {
36///     store.search(query_vec, 10, 0.7).await
37/// }
38/// ```
39#[async_trait]
40pub trait VectorStore: Send + Sync {
41    /// Initialize the store (create tables/collections if needed).
42    async fn initialize(&self, dimension: usize) -> Result<()>;
43
44    /// Insert embeddings with associated content and metadata.
45    ///
46    /// Returns the number of items successfully stored.
47    async fn upsert(
48        &self,
49        ids: Vec<String>,
50        embeddings: Vec<Vec<f32>>,
51        contents: Vec<String>,
52        metadata: Vec<serde_json::Value>,
53    ) -> Result<usize>;
54
55    /// Search for similar vectors.
56    ///
57    /// Returns up to `limit` results with score >= `min_score`.
58    async fn search(
59        &self,
60        query_vector: Vec<f32>,
61        limit: usize,
62        min_score: f32,
63    ) -> Result<Vec<VectorSearchResult>>;
64
65    /// Delete items by their IDs.
66    async fn delete(&self, ids: Vec<String>) -> Result<usize>;
67
68    /// Delete all stored data.
69    async fn clear(&self) -> Result<()>;
70
71    /// Get the number of stored items.
72    async fn count(&self) -> Result<usize>;
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    // Verify the types compile and serialize correctly
80    #[test]
81    fn test_search_result_serialization() {
82        let result = VectorSearchResult {
83            id: "chunk-1".to_string(),
84            score: 0.95,
85            content: "fn main() {}".to_string(),
86            metadata: serde_json::json!({"file": "main.rs", "language": "rust"}),
87        };
88
89        let json = serde_json::to_string(&result).unwrap();
90        let deserialized: VectorSearchResult = serde_json::from_str(&json).unwrap();
91        assert_eq!(deserialized.id, "chunk-1");
92        assert!((deserialized.score - 0.95).abs() < f32::EPSILON);
93    }
94}