1pub mod error;
29pub mod memory;
30pub mod stub;
31
32#[cfg(feature = "real-pg")]
33pub mod real_pg;
34
35pub use error::VectorError;
36pub use memory::InMemoryVectorStore;
37pub use stub::StubVectorStore;
38
39#[cfg(feature = "real-pg")]
40pub use real_pg::{RealPgConfig, RealPgVectorStore};
41
42use async_trait::async_trait;
43use std::collections::HashMap;
44use std::str::FromStr;
45
46pub const MAX_TOP_K: usize = 10_000;
53
54pub fn validate_top_k(top_k: usize) -> Result<usize, VectorError> {
60 if top_k == 0 {
61 return Err(VectorError::TopKExceeded {
62 requested: top_k,
63 max: MAX_TOP_K,
64 });
65 }
66 if top_k > MAX_TOP_K {
67 return Err(VectorError::TopKExceeded {
68 requested: top_k,
69 max: MAX_TOP_K,
70 });
71 }
72 Ok(top_k)
73}
74
75#[derive(Debug, Clone)]
77pub struct VectorRecord {
78 pub id: String,
79 pub vector: Vec<f32>,
80 pub score: Option<f32>,
81 pub metadata: Option<HashMap<String, serde_json::Value>>,
82}
83
84impl VectorRecord {
85 pub fn new(id: impl Into<String>, vector: Vec<f32>) -> Self {
86 Self {
87 id: id.into(),
88 vector,
89 score: None,
90 metadata: None,
91 }
92 }
93
94 pub fn with_score(mut self, score: f32) -> Self {
95 self.score = Some(score);
96 self
97 }
98
99 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
100 self.metadata = Some(metadata);
101 self
102 }
103}
104
105#[derive(Debug, Clone)]
107pub struct SearchResult {
108 pub id: String,
109 pub score: f32,
110 pub vector: Vec<f32>,
111 pub text: Option<String>,
112 pub metadata: Option<HashMap<String, serde_json::Value>>,
113}
114
115impl SearchResult {
116 pub fn new(id: impl Into<String>, score: f32, vector: Vec<f32>) -> Self {
117 Self {
118 id: id.into(),
119 score,
120 vector,
121 text: None,
122 metadata: None,
123 }
124 }
125
126 pub fn with_text(mut self, text: impl Into<String>) -> Self {
127 self.text = Some(text.into());
128 self
129 }
130
131 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
132 self.metadata = Some(metadata);
133 self
134 }
135}
136
137#[derive(Debug, Clone, Copy, Default, PartialEq)]
139pub enum VectorMetric {
140 #[default]
141 Cosine,
142 Euclidean,
143 DotProduct,
144}
145
146impl VectorMetric {
147 pub fn pg_operator(&self) -> &'static str {
149 match self {
150 VectorMetric::Cosine => "<=>",
151 VectorMetric::Euclidean => "<->",
152 VectorMetric::DotProduct => "<#>",
153 }
154 }
155
156 pub fn as_str(&self) -> &'static str {
157 match self {
158 VectorMetric::Cosine => "cosine",
159 VectorMetric::Euclidean => "euclidean",
160 VectorMetric::DotProduct => "dotproduct",
161 }
162 }
163}
164
165impl FromStr for VectorMetric {
166 type Err = String;
167
168 fn from_str(s: &str) -> Result<Self, Self::Err> {
169 match s {
170 "cosine" => Ok(VectorMetric::Cosine),
171 "euclidean" => Ok(VectorMetric::Euclidean),
172 "dotproduct" => Ok(VectorMetric::DotProduct),
173 _ => Err(format!("unknown vector metric: {}", s)),
174 }
175 }
176}
177
178#[async_trait]
183pub trait PgVectorStore: Send + Sync {
184 async fn create_collection(
186 &self,
187 name: &str,
188 dimension: usize,
189 metric: Option<VectorMetric>,
190 ) -> Result<(), VectorError>;
191
192 async fn delete_collection(&self, name: &str) -> Result<(), VectorError>;
194
195 async fn insert(&self, collection: &str, records: Vec<VectorRecord>)
197 -> Result<(), VectorError>;
198
199 async fn search(
204 &self,
205 collection: &str,
206 query: &[f32],
207 top_k: usize,
208 ) -> Result<Vec<SearchResult>, VectorError>;
209
210 async fn get(&self, collection: &str, id: &str) -> Result<Option<VectorRecord>, VectorError>;
212
213 async fn delete(&self, collection: &str, ids: Vec<String>) -> Result<u64, VectorError>;
215
216 async fn count(&self, collection: &str) -> Result<usize, VectorError>;
218}