nodedb_fts/backend/traits.rs
1use crate::posting::Posting;
2
3/// Storage backend abstraction for the full-text search engine.
4///
5/// Origin implements this with redb (persistent). Lite implements with
6/// in-memory HashMap. All scoring, BMW, compression, and analysis logic
7/// works identically over any backend.
8///
9/// Write methods take `&self` (not `&mut self`) because:
10/// - Redb provides transactional isolation internally — concurrent writes
11/// are safe through redb's MVCC.
12/// - MemoryBackend uses interior mutability (`RefCell`) to match the same
13/// trait signature, keeping the trait uniform.
14pub trait FtsBackend {
15 /// Error type for backend operations.
16 type Error: std::fmt::Display;
17
18 /// Read the posting list for a term in a collection.
19 fn read_postings(&self, collection: &str, term: &str) -> Result<Vec<Posting>, Self::Error>;
20
21 /// Write/replace the posting list for a term in a collection.
22 fn write_postings(
23 &self,
24 collection: &str,
25 term: &str,
26 postings: &[Posting],
27 ) -> Result<(), Self::Error>;
28
29 /// Remove a term's posting list entirely.
30 fn remove_postings(&self, collection: &str, term: &str) -> Result<(), Self::Error>;
31
32 /// Read the document length (token count) for a document.
33 fn read_doc_length(&self, collection: &str, doc_id: &str) -> Result<Option<u32>, Self::Error>;
34
35 /// Write/replace the document length for a document.
36 fn write_doc_length(
37 &self,
38 collection: &str,
39 doc_id: &str,
40 length: u32,
41 ) -> Result<(), Self::Error>;
42
43 /// Remove a document's length entry.
44 fn remove_doc_length(&self, collection: &str, doc_id: &str) -> Result<(), Self::Error>;
45
46 /// Get all term keys for a collection (for fuzzy matching).
47 /// Returns terms without the collection prefix.
48 fn collection_terms(&self, collection: &str) -> Result<Vec<String>, Self::Error>;
49
50 /// Get total document count and sum of all document lengths for a collection.
51 /// Returns `(doc_count, total_token_sum)`.
52 ///
53 /// Implementations should maintain these incrementally for O(1) lookup.
54 fn collection_stats(&self, collection: &str) -> Result<(u32, u64), Self::Error>;
55
56 /// Increment collection stats after indexing a document.
57 /// `doc_len` is the number of tokens in the newly indexed document.
58 fn increment_stats(&self, collection: &str, doc_len: u32) -> Result<(), Self::Error>;
59
60 /// Decrement collection stats after removing a document.
61 /// `doc_len` is the token count of the removed document.
62 fn decrement_stats(&self, collection: &str, doc_len: u32) -> Result<(), Self::Error>;
63
64 /// Read a metadata blob by key (e.g., "docmap:{collection}", "fieldnorms:{collection}").
65 fn read_meta(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error>;
66
67 /// Write a metadata blob by key.
68 fn write_meta(&self, key: &str, value: &[u8]) -> Result<(), Self::Error>;
69
70 /// Write a segment blob. Key format: "{collection}:seg:{segment_id}".
71 fn write_segment(&self, key: &str, data: &[u8]) -> Result<(), Self::Error>;
72
73 /// Read a segment blob. Returns None if not found.
74 fn read_segment(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error>;
75
76 /// List all segment keys for a collection (prefix "{collection}:seg:").
77 fn list_segments(&self, collection: &str) -> Result<Vec<String>, Self::Error>;
78
79 /// Remove a segment blob.
80 fn remove_segment(&self, key: &str) -> Result<(), Self::Error>;
81
82 /// Remove all entries for a collection prefix. Returns count of removed entries.
83 fn purge_collection(&self, collection: &str) -> Result<usize, Self::Error>;
84}