1use std::collections::HashMap;
4use uuid::Uuid;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9#[cfg(feature = "serde")]
11use chrono;
12
13pub type Vector = Vec<f32>;
15
16pub type DocumentId = String;
18
19pub type Metadata = HashMap<String, MetadataValue>;
21
22#[derive(Debug, Clone, PartialEq)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[cfg_attr(feature = "serde", serde(untagged))]
26pub enum MetadataValue {
27 String(String),
28 Integer(i64),
29 Float(f64),
30 Boolean(bool),
31 Array(Vec<MetadataValue>),
32 Object(HashMap<String, MetadataValue>),
33 Null,
34}
35
36impl From<String> for MetadataValue {
37 fn from(s: String) -> Self {
38 MetadataValue::String(s)
39 }
40}
41
42impl From<&str> for MetadataValue {
43 fn from(s: &str) -> Self {
44 MetadataValue::String(s.to_string())
45 }
46}
47
48impl From<i64> for MetadataValue {
49 fn from(i: i64) -> Self {
50 MetadataValue::Integer(i)
51 }
52}
53
54impl From<f64> for MetadataValue {
55 fn from(f: f64) -> Self {
56 MetadataValue::Float(f)
57 }
58}
59
60impl From<bool> for MetadataValue {
61 fn from(b: bool) -> Self {
62 MetadataValue::Boolean(b)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69pub enum SimilarityMetric {
70 Cosine,
72 Euclidean,
74 DotProduct,
76 Manhattan,
78 Hamming,
80}
81
82impl Default for SimilarityMetric {
83 fn default() -> Self {
84 SimilarityMetric::Cosine
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
90#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
91pub enum FilterCondition {
92 Eq(String, MetadataValue),
94 Ne(String, MetadataValue),
96 Gt(String, MetadataValue),
98 Gte(String, MetadataValue),
100 Lt(String, MetadataValue),
102 Lte(String, MetadataValue),
104 In(String, Vec<MetadataValue>),
106 NotIn(String, Vec<MetadataValue>),
108 Exists(String),
110 NotExists(String),
112 Contains(String, String),
114 StartsWith(String, String),
116 EndsWith(String, String),
118 Regex(String, String),
120 And(Vec<FilterCondition>),
122 Or(Vec<FilterCondition>),
124 Not(Box<FilterCondition>),
126}
127
128impl FilterCondition {
129 pub fn eq(field: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
131 FilterCondition::Eq(field.into(), value.into())
132 }
133
134 pub fn ne(field: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
136 FilterCondition::Ne(field.into(), value.into())
137 }
138
139 pub fn gt(field: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
141 FilterCondition::Gt(field.into(), value.into())
142 }
143
144 pub fn lt(field: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
146 FilterCondition::Lt(field.into(), value.into())
147 }
148
149 pub fn in_values(field: impl Into<String>, values: Vec<impl Into<MetadataValue>>) -> Self {
151 FilterCondition::In(
152 field.into(),
153 values.into_iter().map(|v| v.into()).collect(),
154 )
155 }
156
157 pub fn and(conditions: Vec<FilterCondition>) -> Self {
159 FilterCondition::And(conditions)
160 }
161
162 pub fn or(conditions: Vec<FilterCondition>) -> Self {
164 FilterCondition::Or(conditions)
165 }
166
167 pub fn not(condition: FilterCondition) -> Self {
169 FilterCondition::Not(Box::new(condition))
170 }
171
172 pub fn exists(field: impl Into<String>) -> Self {
174 FilterCondition::Exists(field.into())
175 }
176
177 pub fn contains(field: impl Into<String>, substring: impl Into<String>) -> Self {
179 FilterCondition::Contains(field.into(), substring.into())
180 }
181}
182
183#[derive(Debug, Clone)]
185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
186pub struct IndexConfig {
187 pub name: String,
189 pub dimension: usize,
191 pub metric: SimilarityMetric,
193 pub options: HashMap<String, MetadataValue>,
195}
196
197impl IndexConfig {
198 pub fn new(name: impl Into<String>, dimension: usize) -> Self {
200 Self {
201 name: name.into(),
202 dimension,
203 metric: SimilarityMetric::default(),
204 options: HashMap::new(),
205 }
206 }
207
208 pub fn with_metric(mut self, metric: SimilarityMetric) -> Self {
210 self.metric = metric;
211 self
212 }
213
214 pub fn with_option(mut self, key: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
216 self.options.insert(key.into(), value.into());
217 self
218 }
219}
220
221#[derive(Debug, Clone)]
223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
224pub struct IndexInfo {
225 pub name: String,
227 pub dimension: usize,
229 pub metric: SimilarityMetric,
231 pub vector_count: usize,
233 pub size_bytes: u64,
235 pub created_at: Option<chrono::DateTime<chrono::Utc>>,
237 pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
239 pub metadata: Metadata,
241}
242
243#[derive(Debug, Clone)]
245#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
246pub struct Document {
247 pub id: DocumentId,
249 pub content: String,
251 pub embedding: Option<Vector>,
253 pub metadata: Metadata,
255}
256
257impl Document {
258 pub fn new(id: impl Into<DocumentId>, content: impl Into<String>) -> Self {
260 Self {
261 id: id.into(),
262 content: content.into(),
263 embedding: None,
264 metadata: HashMap::new(),
265 }
266 }
267
268 pub fn with_content(content: impl Into<String>) -> Self {
270 Self::new(Uuid::new_v4().to_string(), content)
271 }
272
273 pub fn with_embedding(mut self, embedding: Vector) -> Self {
275 self.embedding = Some(embedding);
276 self
277 }
278
279 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<MetadataValue>) -> Self {
281 self.metadata.insert(key.into(), value.into());
282 self
283 }
284
285 pub fn with_all_metadata(mut self, metadata: Metadata) -> Self {
287 self.metadata = metadata;
288 self
289 }
290}
291
292#[derive(Debug, Clone)]
294#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
295pub struct SearchRequest {
296 pub index_name: String,
298 pub query: SearchQuery,
300 pub top_k: usize,
302 pub filter: Option<FilterCondition>,
304 pub include_vectors: bool,
306 pub include_metadata: bool,
308 pub options: HashMap<String, MetadataValue>,
310}
311
312impl SearchRequest {
313 pub fn new(index_name: impl Into<String>, vector: Vector) -> Self {
315 Self {
316 index_name: index_name.into(),
317 query: SearchQuery::Vector(vector),
318 top_k: 10,
319 filter: None,
320 include_vectors: false,
321 include_metadata: true,
322 options: HashMap::new(),
323 }
324 }
325
326 pub fn new_text(index_name: impl Into<String>, text: impl Into<String>) -> Self {
328 Self {
329 index_name: index_name.into(),
330 query: SearchQuery::Text(text.into()),
331 top_k: 10,
332 filter: None,
333 include_vectors: false,
334 include_metadata: true,
335 options: HashMap::new(),
336 }
337 }
338
339 pub fn with_top_k(mut self, top_k: usize) -> Self {
341 self.top_k = top_k;
342 self
343 }
344
345 pub fn with_filter(mut self, filter: FilterCondition) -> Self {
347 self.filter = Some(filter);
348 self
349 }
350
351 pub fn with_include_vectors(mut self, include: bool) -> Self {
353 self.include_vectors = include;
354 self
355 }
356
357 pub fn with_include_metadata(mut self, include: bool) -> Self {
359 self.include_metadata = include;
360 self
361 }
362
363 pub fn with_option(mut self, key: impl Into<String>, value: MetadataValue) -> Self {
365 self.options.insert(key.into(), value);
366 self
367 }
368}
369
370#[derive(Debug, Clone)]
372#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
373pub enum SearchQuery {
374 Vector(Vector),
376 Text(String),
378}
379
380#[derive(Debug, Clone)]
382#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
383pub struct SearchResult {
384 pub id: DocumentId,
386 pub score: f32,
388 pub vector: Option<Vector>,
390 pub metadata: Option<Metadata>,
392 pub content: Option<String>,
394}
395
396impl SearchResult {
397 pub fn new(id: impl Into<DocumentId>, score: f32) -> Self {
399 Self {
400 id: id.into(),
401 score,
402 vector: None,
403 metadata: None,
404 content: None,
405 }
406 }
407
408 pub fn with_vector(mut self, vector: Vector) -> Self {
410 self.vector = Some(vector);
411 self
412 }
413
414 pub fn with_metadata(mut self, metadata: Metadata) -> Self {
416 self.metadata = Some(metadata);
417 self
418 }
419
420 pub fn with_content(mut self, content: impl Into<String>) -> Self {
422 self.content = Some(content.into());
423 self
424 }
425}
426
427#[derive(Debug, Clone)]
429#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
430pub struct SearchResponse {
431 pub results: Vec<SearchResult>,
433 pub total_count: Option<usize>,
435 pub execution_time_ms: Option<u64>,
437 pub metadata: Metadata,
439}
440
441impl SearchResponse {
442 pub fn new(results: Vec<SearchResult>) -> Self {
444 Self {
445 results,
446 total_count: None,
447 execution_time_ms: None,
448 metadata: HashMap::new(),
449 }
450 }
451
452 pub fn with_total_count(mut self, count: usize) -> Self {
454 self.total_count = Some(count);
455 self
456 }
457
458 pub fn with_execution_time(mut self, time_ms: u64) -> Self {
460 self.execution_time_ms = Some(time_ms);
461 self
462 }
463}