Skip to main content

mnemo_postgres/
pgvector_index.rs

1use std::path::Path;
2use std::sync::atomic::{AtomicUsize, Ordering};
3
4use mnemo_core::error::Result;
5use mnemo_core::index::VectorIndex;
6use uuid::Uuid;
7
8/// A no-op `VectorIndex` for use with PostgreSQL + pgvector.
9///
10/// Because pgvector handles vector storage and similarity search natively
11/// inside PostgreSQL, there is no need for a separate in-process HNSW index.
12/// All vector operations are performed via SQL in `PgStorage`.
13///
14/// The only meaningful state tracked here is the element count, maintained
15/// with an `AtomicUsize` so callers can still query `len()` / `is_empty()`.
16pub struct PgVectorIndex {
17    count: AtomicUsize,
18}
19
20impl PgVectorIndex {
21    /// Create a new no-op pgvector index wrapper.
22    pub fn new() -> Self {
23        Self {
24            count: AtomicUsize::new(0),
25        }
26    }
27}
28
29impl Default for PgVectorIndex {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl VectorIndex for PgVectorIndex {
36    fn add(&self, _id: Uuid, _vector: &[f32]) -> Result<()> {
37        self.count.fetch_add(1, Ordering::Relaxed);
38        Ok(())
39    }
40
41    fn remove(&self, _id: Uuid) -> Result<()> {
42        // Saturating subtract: do not wrap below zero.
43        let _ = self
44            .count
45            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |n| {
46                if n > 0 { Some(n - 1) } else { Some(0) }
47            });
48        Ok(())
49    }
50
51    fn search(&self, _query: &[f32], _limit: usize) -> Result<Vec<(Uuid, f32)>> {
52        // Vector search is handled via SQL in PgStorage.
53        Ok(Vec::new())
54    }
55
56    fn filtered_search(
57        &self,
58        _query: &[f32],
59        _limit: usize,
60        _filter: &dyn Fn(Uuid) -> bool,
61    ) -> Result<Vec<(Uuid, f32)>> {
62        // Vector search is handled via SQL in PgStorage.
63        Ok(Vec::new())
64    }
65
66    fn save(&self, _path: &Path) -> Result<()> {
67        // No local state to persist -- vectors live in PostgreSQL.
68        Ok(())
69    }
70
71    fn load(&self, _path: &Path) -> Result<()> {
72        // No local state to restore -- vectors live in PostgreSQL.
73        Ok(())
74    }
75
76    fn len(&self) -> usize {
77        self.count.load(Ordering::Relaxed)
78    }
79}