1use chroma_error::{ChromaError, ErrorCodes};
2use itertools::Itertools;
3use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
4use serde_json::{Number, Value};
5use sprs::CsVec;
6use std::{
7 cmp::Ordering,
8 collections::{HashMap, HashSet},
9 mem::size_of_val,
10 ops::{BitAnd, BitOr},
11};
12use thiserror::Error;
13
14use crate::chroma_proto;
15
16#[cfg(feature = "pyo3")]
17use pyo3::types::{PyAnyMethods, PyDictMethods};
18
19#[cfg(feature = "testing")]
20use proptest::prelude::*;
21
22#[derive(Serialize, Deserialize)]
23struct SparseVectorSerdeHelper {
24 #[serde(rename = "#type")]
25 type_tag: Option<String>,
26 indices: Vec<u32>,
27 values: Vec<f32>,
28 tokens: Option<Vec<String>>,
29}
30
31#[derive(Clone, Debug, PartialEq)]
38#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
39pub struct SparseVector {
40 pub indices: Vec<u32>,
42 pub values: Vec<f32>,
44 pub tokens: Option<Vec<String>>,
46}
47
48impl<'de> Deserialize<'de> for SparseVector {
50 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51 where
52 D: Deserializer<'de>,
53 {
54 let helper = SparseVectorSerdeHelper::deserialize(deserializer)?;
55
56 if let Some(type_tag) = &helper.type_tag {
58 if type_tag != "sparse_vector" {
59 return Err(serde::de::Error::custom(format!(
60 "Expected #type='sparse_vector', got '{}'",
61 type_tag
62 )));
63 }
64 }
65
66 Ok(SparseVector {
67 indices: helper.indices,
68 values: helper.values,
69 tokens: helper.tokens,
70 })
71 }
72}
73
74impl Serialize for SparseVector {
76 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
77 where
78 S: Serializer,
79 {
80 let helper = SparseVectorSerdeHelper {
81 type_tag: Some("sparse_vector".to_string()),
82 indices: self.indices.clone(),
83 values: self.values.clone(),
84 tokens: self.tokens.clone(),
85 };
86 helper.serialize(serializer)
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92pub struct SparseVectorLengthMismatch;
93
94impl std::fmt::Display for SparseVectorLengthMismatch {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 write!(
97 f,
98 "Sparse vector indices, values, and tokens (when present) must have the same length"
99 )
100 }
101}
102
103impl std::error::Error for SparseVectorLengthMismatch {}
104
105impl ChromaError for SparseVectorLengthMismatch {
106 fn code(&self) -> ErrorCodes {
107 ErrorCodes::InvalidArgument
108 }
109}
110
111impl SparseVector {
112 pub fn new(indices: Vec<u32>, values: Vec<f32>) -> Result<Self, SparseVectorLengthMismatch> {
114 if indices.len() != values.len() {
115 return Err(SparseVectorLengthMismatch);
116 }
117 Ok(Self {
118 indices,
119 values,
120 tokens: None,
121 })
122 }
123
124 pub fn new_with_tokens(
126 indices: Vec<u32>,
127 values: Vec<f32>,
128 tokens: Vec<String>,
129 ) -> Result<Self, SparseVectorLengthMismatch> {
130 if indices.len() != values.len() {
131 return Err(SparseVectorLengthMismatch);
132 }
133 if tokens.len() != indices.len() {
134 return Err(SparseVectorLengthMismatch);
135 }
136 Ok(Self {
137 indices,
138 values,
139 tokens: Some(tokens),
140 })
141 }
142
143 pub fn from_pairs(pairs: impl IntoIterator<Item = (u32, f32)>) -> Self {
145 let mut indices = vec![];
146 let mut values = vec![];
147 for (index, value) in pairs {
148 indices.push(index);
149 values.push(value);
150 }
151 let tokens = None;
152 Self {
153 indices,
154 values,
155 tokens,
156 }
157 }
158
159 pub fn from_triples(triples: impl IntoIterator<Item = (String, u32, f32)>) -> Self {
161 let mut tokens = vec![];
162 let mut indices = vec![];
163 let mut values = vec![];
164 for (token, index, value) in triples {
165 tokens.push(token);
166 indices.push(index);
167 values.push(value);
168 }
169 let tokens = Some(tokens);
170 Self {
171 indices,
172 values,
173 tokens,
174 }
175 }
176
177 pub fn iter(&self) -> impl Iterator<Item = (u32, f32)> + '_ {
179 self.indices
180 .iter()
181 .copied()
182 .zip(self.values.iter().copied())
183 }
184
185 pub fn validate(&self) -> Result<(), MetadataValueConversionError> {
187 if self.indices.len() != self.values.len() {
189 return Err(MetadataValueConversionError::SparseVectorLengthMismatch);
190 }
191
192 if let Some(tokens) = self.tokens.as_ref() {
194 if tokens.len() != self.indices.len() {
195 return Err(MetadataValueConversionError::SparseVectorLengthMismatch);
196 }
197 }
198
199 for i in 1..self.indices.len() {
201 if self.indices[i] <= self.indices[i - 1] {
202 return Err(MetadataValueConversionError::SparseVectorIndicesNotSorted);
203 }
204 }
205
206 Ok(())
207 }
208}
209
210impl Eq for SparseVector {}
211
212impl Ord for SparseVector {
213 fn cmp(&self, other: &Self) -> Ordering {
214 self.indices.cmp(&other.indices).then_with(|| {
215 for (a, b) in self.values.iter().zip(other.values.iter()) {
216 match a.total_cmp(b) {
217 Ordering::Equal => continue,
218 other => return other,
219 }
220 }
221 self.values.len().cmp(&other.values.len())
222 })
223 }
224}
225
226impl PartialOrd for SparseVector {
227 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
228 Some(self.cmp(other))
229 }
230}
231
232impl TryFrom<chroma_proto::SparseVector> for SparseVector {
233 type Error = SparseVectorLengthMismatch;
234
235 fn try_from(proto: chroma_proto::SparseVector) -> Result<Self, Self::Error> {
236 if proto.tokens.is_empty() {
237 SparseVector::new(proto.indices, proto.values)
238 } else {
239 SparseVector::new_with_tokens(proto.indices, proto.values, proto.tokens)
240 }
241 }
242}
243
244impl From<SparseVector> for chroma_proto::SparseVector {
245 fn from(sparse: SparseVector) -> Self {
246 chroma_proto::SparseVector {
247 indices: sparse.indices,
248 values: sparse.values,
249 tokens: sparse.tokens.unwrap_or_default(),
250 }
251 }
252}
253
254impl From<&SparseVector> for CsVec<f32> {
256 fn from(sparse: &SparseVector) -> Self {
257 let (indices, values) = sparse
258 .iter()
259 .map(|(index, value)| (index as usize, value))
260 .unzip();
261 CsVec::new(u32::MAX as usize, indices, values)
262 }
263}
264
265impl From<SparseVector> for CsVec<f32> {
266 fn from(sparse: SparseVector) -> Self {
267 (&sparse).into()
268 }
269}
270
271#[cfg(feature = "pyo3")]
272impl<'py> pyo3::IntoPyObject<'py> for SparseVector {
273 type Target = pyo3::PyAny;
274 type Output = pyo3::Bound<'py, Self::Target>;
275 type Error = pyo3::PyErr;
276
277 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
278 use pyo3::types::PyDict;
279
280 let dict = PyDict::new(py);
281 dict.set_item("indices", self.indices)?;
282 dict.set_item("values", self.values)?;
283 dict.set_item("tokens", self.tokens)?;
284 Ok(dict.into_any())
285 }
286}
287
288#[cfg(feature = "pyo3")]
289impl<'py> pyo3::FromPyObject<'py> for SparseVector {
290 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
291 use pyo3::types::PyDict;
292
293 let dict = ob.downcast::<PyDict>()?;
294 let indices_obj = dict.get_item("indices")?;
295 if indices_obj.is_none() {
296 return Err(pyo3::exceptions::PyKeyError::new_err(
297 "missing 'indices' key",
298 ));
299 }
300 let indices: Vec<u32> = indices_obj.unwrap().extract()?;
301
302 let values_obj = dict.get_item("values")?;
303 if values_obj.is_none() {
304 return Err(pyo3::exceptions::PyKeyError::new_err(
305 "missing 'values' key",
306 ));
307 }
308 let values: Vec<f32> = values_obj.unwrap().extract()?;
309
310 let tokens_obj = dict.get_item("tokens")?;
311 let tokens = match tokens_obj {
312 Some(obj) if obj.is_none() => None,
313 Some(obj) => Some(obj.extract::<Vec<String>>()?),
314 None => None,
315 };
316
317 let result = match tokens {
318 Some(tokens) => SparseVector::new_with_tokens(indices, values, tokens),
319 None => SparseVector::new(indices, values),
320 };
321
322 result.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
323 }
324}
325
326#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
327#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
328#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
329#[serde(untagged)]
330pub enum UpdateMetadataValue {
331 Bool(bool),
332 Int(i64),
333 #[cfg_attr(
334 feature = "testing",
335 proptest(
336 strategy = "(-1e6..=1e6f32).prop_map(|v| UpdateMetadataValue::Float(v as f64)).boxed()"
337 )
338 )]
339 Float(f64),
340 Str(String),
341 #[cfg_attr(feature = "testing", proptest(skip))]
342 SparseVector(SparseVector),
343 #[cfg_attr(feature = "testing", proptest(skip))]
346 BoolArray(Vec<bool>),
347 #[cfg_attr(feature = "testing", proptest(skip))]
348 IntArray(Vec<i64>),
349 #[cfg_attr(feature = "testing", proptest(skip))]
350 FloatArray(Vec<f64>),
351 #[cfg_attr(feature = "testing", proptest(skip))]
352 StringArray(Vec<String>),
353 None,
354}
355
356#[cfg(feature = "pyo3")]
357impl<'py> pyo3::FromPyObject<'py> for UpdateMetadataValue {
358 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
359 use pyo3::types::PyList;
360
361 if ob.is_none() {
362 Ok(UpdateMetadataValue::None)
363 } else if let Ok(value) = ob.extract::<bool>() {
364 Ok(UpdateMetadataValue::Bool(value))
365 } else if let Ok(value) = ob.extract::<i64>() {
366 Ok(UpdateMetadataValue::Int(value))
367 } else if let Ok(value) = ob.extract::<f64>() {
368 Ok(UpdateMetadataValue::Float(value))
369 } else if let Ok(value) = ob.extract::<String>() {
370 Ok(UpdateMetadataValue::Str(value))
371 } else if let Ok(value) = ob.extract::<SparseVector>() {
372 Ok(UpdateMetadataValue::SparseVector(value))
373 } else if let Ok(list) = ob.downcast::<PyList>() {
374 if list.is_empty()? {
376 return Err(pyo3::exceptions::PyValueError::new_err(
377 "Empty lists are not allowed as metadata values",
378 ));
379 }
380 if let Ok(arr) = list.extract::<Vec<bool>>() {
384 Ok(UpdateMetadataValue::BoolArray(arr))
385 } else if let Ok(arr) = list.extract::<Vec<i64>>() {
386 Ok(UpdateMetadataValue::IntArray(arr))
387 } else if let Ok(arr) = list.extract::<Vec<f64>>() {
388 Ok(UpdateMetadataValue::FloatArray(arr))
389 } else if let Ok(arr) = list.extract::<Vec<String>>() {
390 Ok(UpdateMetadataValue::StringArray(arr))
391 } else {
392 Err(pyo3::exceptions::PyTypeError::new_err(
393 "Cannot convert Python list to UpdateMetadataValue: mixed or unsupported element types",
394 ))
395 }
396 } else {
397 Err(pyo3::exceptions::PyTypeError::new_err(
398 "Cannot convert Python object to UpdateMetadataValue",
399 ))
400 }
401 }
402}
403
404impl From<bool> for UpdateMetadataValue {
405 fn from(b: bool) -> Self {
406 Self::Bool(b)
407 }
408}
409
410impl From<i64> for UpdateMetadataValue {
411 fn from(v: i64) -> Self {
412 Self::Int(v)
413 }
414}
415
416impl From<i32> for UpdateMetadataValue {
417 fn from(v: i32) -> Self {
418 Self::Int(v as i64)
419 }
420}
421
422impl From<f64> for UpdateMetadataValue {
423 fn from(v: f64) -> Self {
424 Self::Float(v)
425 }
426}
427
428impl From<f32> for UpdateMetadataValue {
429 fn from(v: f32) -> Self {
430 Self::Float(v as f64)
431 }
432}
433
434impl From<String> for UpdateMetadataValue {
435 fn from(v: String) -> Self {
436 Self::Str(v)
437 }
438}
439
440impl From<&str> for UpdateMetadataValue {
441 fn from(v: &str) -> Self {
442 Self::Str(v.to_string())
443 }
444}
445
446impl From<SparseVector> for UpdateMetadataValue {
447 fn from(v: SparseVector) -> Self {
448 Self::SparseVector(v)
449 }
450}
451
452impl From<Vec<bool>> for UpdateMetadataValue {
453 fn from(v: Vec<bool>) -> Self {
454 Self::BoolArray(v)
455 }
456}
457
458impl From<Vec<i64>> for UpdateMetadataValue {
459 fn from(v: Vec<i64>) -> Self {
460 Self::IntArray(v)
461 }
462}
463
464impl From<Vec<f64>> for UpdateMetadataValue {
465 fn from(v: Vec<f64>) -> Self {
466 Self::FloatArray(v)
467 }
468}
469
470impl From<Vec<String>> for UpdateMetadataValue {
471 fn from(v: Vec<String>) -> Self {
472 Self::StringArray(v)
473 }
474}
475
476#[derive(Error, Debug)]
477pub enum UpdateMetadataValueConversionError {
478 #[error("Invalid metadata value, valid values are: Int, Float, Str, Bool, None")]
479 InvalidValue,
480}
481
482impl ChromaError for UpdateMetadataValueConversionError {
483 fn code(&self) -> ErrorCodes {
484 match self {
485 UpdateMetadataValueConversionError::InvalidValue => ErrorCodes::InvalidArgument,
486 }
487 }
488}
489
490impl TryFrom<&chroma_proto::UpdateMetadataValue> for UpdateMetadataValue {
491 type Error = UpdateMetadataValueConversionError;
492
493 fn try_from(value: &chroma_proto::UpdateMetadataValue) -> Result<Self, Self::Error> {
494 match &value.value {
495 Some(chroma_proto::update_metadata_value::Value::BoolValue(value)) => {
496 Ok(UpdateMetadataValue::Bool(*value))
497 }
498 Some(chroma_proto::update_metadata_value::Value::IntValue(value)) => {
499 Ok(UpdateMetadataValue::Int(*value))
500 }
501 Some(chroma_proto::update_metadata_value::Value::FloatValue(value)) => {
502 if !value.is_finite() {
503 return Err(UpdateMetadataValueConversionError::InvalidValue);
504 }
505 Ok(UpdateMetadataValue::Float(*value))
506 }
507 Some(chroma_proto::update_metadata_value::Value::StringValue(value)) => {
508 Ok(UpdateMetadataValue::Str(value.clone()))
509 }
510 Some(chroma_proto::update_metadata_value::Value::SparseVectorValue(value)) => {
511 let sparse = value
512 .clone()
513 .try_into()
514 .map_err(|_| UpdateMetadataValueConversionError::InvalidValue)?;
515 Ok(UpdateMetadataValue::SparseVector(sparse))
516 }
517 Some(chroma_proto::update_metadata_value::Value::BoolListValue(value)) => {
518 Ok(UpdateMetadataValue::BoolArray(value.values.clone()))
519 }
520 Some(chroma_proto::update_metadata_value::Value::IntListValue(value)) => {
521 Ok(UpdateMetadataValue::IntArray(value.values.clone()))
522 }
523 Some(chroma_proto::update_metadata_value::Value::DoubleListValue(value)) => {
524 if value.values.iter().any(|v| !v.is_finite()) {
525 return Err(UpdateMetadataValueConversionError::InvalidValue);
526 }
527 Ok(UpdateMetadataValue::FloatArray(value.values.clone()))
528 }
529 Some(chroma_proto::update_metadata_value::Value::StringListValue(value)) => {
530 Ok(UpdateMetadataValue::StringArray(value.values.clone()))
531 }
532 None => Ok(UpdateMetadataValue::None),
534 }
535 }
536}
537
538impl From<UpdateMetadataValue> for chroma_proto::UpdateMetadataValue {
539 fn from(value: UpdateMetadataValue) -> Self {
540 match value {
541 UpdateMetadataValue::Bool(value) => chroma_proto::UpdateMetadataValue {
542 value: Some(chroma_proto::update_metadata_value::Value::BoolValue(value)),
543 },
544 UpdateMetadataValue::Int(value) => chroma_proto::UpdateMetadataValue {
545 value: Some(chroma_proto::update_metadata_value::Value::IntValue(value)),
546 },
547 UpdateMetadataValue::Float(value) => chroma_proto::UpdateMetadataValue {
548 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(
549 value,
550 )),
551 },
552 UpdateMetadataValue::Str(value) => chroma_proto::UpdateMetadataValue {
553 value: Some(chroma_proto::update_metadata_value::Value::StringValue(
554 value,
555 )),
556 },
557 UpdateMetadataValue::SparseVector(sparse_vec) => chroma_proto::UpdateMetadataValue {
558 value: Some(
559 chroma_proto::update_metadata_value::Value::SparseVectorValue(
560 sparse_vec.into(),
561 ),
562 ),
563 },
564 UpdateMetadataValue::BoolArray(values) => chroma_proto::UpdateMetadataValue {
565 value: Some(chroma_proto::update_metadata_value::Value::BoolListValue(
566 chroma_proto::BoolListValue { values },
567 )),
568 },
569 UpdateMetadataValue::IntArray(values) => chroma_proto::UpdateMetadataValue {
570 value: Some(chroma_proto::update_metadata_value::Value::IntListValue(
571 chroma_proto::IntListValue { values },
572 )),
573 },
574 UpdateMetadataValue::FloatArray(values) => chroma_proto::UpdateMetadataValue {
575 value: Some(chroma_proto::update_metadata_value::Value::DoubleListValue(
576 chroma_proto::DoubleListValue { values },
577 )),
578 },
579 UpdateMetadataValue::StringArray(values) => chroma_proto::UpdateMetadataValue {
580 value: Some(chroma_proto::update_metadata_value::Value::StringListValue(
581 chroma_proto::StringListValue { values },
582 )),
583 },
584 UpdateMetadataValue::None => chroma_proto::UpdateMetadataValue { value: None },
585 }
586 }
587}
588
589impl TryFrom<&UpdateMetadataValue> for MetadataValue {
590 type Error = MetadataValueConversionError;
591
592 fn try_from(value: &UpdateMetadataValue) -> Result<Self, Self::Error> {
593 match value {
594 UpdateMetadataValue::Bool(value) => Ok(MetadataValue::Bool(*value)),
595 UpdateMetadataValue::Int(value) => Ok(MetadataValue::Int(*value)),
596 UpdateMetadataValue::Float(value) => Ok(MetadataValue::Float(*value)),
597 UpdateMetadataValue::Str(value) => Ok(MetadataValue::Str(value.clone())),
598 UpdateMetadataValue::SparseVector(value) => {
599 Ok(MetadataValue::SparseVector(value.clone()))
600 }
601 UpdateMetadataValue::BoolArray(value) => Ok(MetadataValue::BoolArray(value.clone())),
602 UpdateMetadataValue::IntArray(value) => Ok(MetadataValue::IntArray(value.clone())),
603 UpdateMetadataValue::FloatArray(value) => Ok(MetadataValue::FloatArray(value.clone())),
604 UpdateMetadataValue::StringArray(value) => {
605 Ok(MetadataValue::StringArray(value.clone()))
606 }
607 UpdateMetadataValue::None => Err(MetadataValueConversionError::InvalidValue),
608 }
609 }
610}
611
612#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
619#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
620#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
621#[cfg_attr(feature = "pyo3", derive(pyo3::IntoPyObject))]
622#[serde(untagged)]
623pub enum MetadataValue {
624 Bool(bool),
625 Int(i64),
626 #[cfg_attr(
627 feature = "testing",
628 proptest(
629 strategy = "(-1e6..=1e6f32).prop_map(|v| MetadataValue::Float(v as f64)).boxed()"
630 )
631 )]
632 Float(f64),
633 Str(String),
634 #[cfg_attr(feature = "testing", proptest(skip))]
635 SparseVector(SparseVector),
636 #[cfg_attr(feature = "testing", proptest(skip))]
639 BoolArray(Vec<bool>),
640 #[cfg_attr(feature = "testing", proptest(skip))]
641 IntArray(Vec<i64>),
642 #[cfg_attr(feature = "testing", proptest(skip))]
643 FloatArray(Vec<f64>),
644 #[cfg_attr(feature = "testing", proptest(skip))]
645 StringArray(Vec<String>),
646}
647
648#[cfg(feature = "pyo3")]
649impl<'py> pyo3::FromPyObject<'py> for MetadataValue {
650 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
651 use pyo3::types::PyList;
652
653 if let Ok(value) = ob.extract::<bool>() {
654 Ok(MetadataValue::Bool(value))
655 } else if let Ok(value) = ob.extract::<i64>() {
656 Ok(MetadataValue::Int(value))
657 } else if let Ok(value) = ob.extract::<f64>() {
658 Ok(MetadataValue::Float(value))
659 } else if let Ok(value) = ob.extract::<String>() {
660 Ok(MetadataValue::Str(value))
661 } else if let Ok(value) = ob.extract::<SparseVector>() {
662 Ok(MetadataValue::SparseVector(value))
663 } else if let Ok(list) = ob.downcast::<PyList>() {
664 if list.is_empty()? {
666 return Err(pyo3::exceptions::PyValueError::new_err(
667 "Empty lists are not allowed as metadata values",
668 ));
669 }
670 if let Ok(arr) = list.extract::<Vec<bool>>() {
674 Ok(MetadataValue::BoolArray(arr))
675 } else if let Ok(arr) = list.extract::<Vec<i64>>() {
676 Ok(MetadataValue::IntArray(arr))
677 } else if let Ok(arr) = list.extract::<Vec<f64>>() {
678 Ok(MetadataValue::FloatArray(arr))
679 } else if let Ok(arr) = list.extract::<Vec<String>>() {
680 Ok(MetadataValue::StringArray(arr))
681 } else {
682 Err(pyo3::exceptions::PyTypeError::new_err(
683 "Cannot convert Python list to MetadataValue: mixed or unsupported element types",
684 ))
685 }
686 } else {
687 Err(pyo3::exceptions::PyTypeError::new_err(
688 "Cannot convert Python object to MetadataValue",
689 ))
690 }
691 }
692}
693
694impl std::fmt::Display for MetadataValue {
695 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
696 match self {
697 MetadataValue::Bool(v) => write!(f, "{}", v),
698 MetadataValue::Int(v) => write!(f, "{}", v),
699 MetadataValue::Float(v) => write!(f, "{}", v),
700 MetadataValue::Str(v) => write!(f, "\"{}\"", v),
701 MetadataValue::SparseVector(v) => write!(f, "SparseVector(len={})", v.values.len()),
702 MetadataValue::BoolArray(v) => write!(f, "BoolArray(len={})", v.len()),
703 MetadataValue::IntArray(v) => write!(f, "IntArray(len={})", v.len()),
704 MetadataValue::FloatArray(v) => write!(f, "FloatArray(len={})", v.len()),
705 MetadataValue::StringArray(v) => write!(f, "StringArray(len={})", v.len()),
706 }
707 }
708}
709
710impl Eq for MetadataValue {}
711
712#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
713pub enum MetadataValueType {
714 Bool,
715 Int,
716 Float,
717 Str,
718 SparseVector,
719 BoolArray,
720 IntArray,
721 FloatArray,
722 StringArray,
723}
724
725impl MetadataValue {
726 pub fn value_type(&self) -> MetadataValueType {
727 match self {
728 MetadataValue::Bool(_) => MetadataValueType::Bool,
729 MetadataValue::Int(_) => MetadataValueType::Int,
730 MetadataValue::Float(_) => MetadataValueType::Float,
731 MetadataValue::Str(_) => MetadataValueType::Str,
732 MetadataValue::SparseVector(_) => MetadataValueType::SparseVector,
733 MetadataValue::BoolArray(_) => MetadataValueType::BoolArray,
734 MetadataValue::IntArray(_) => MetadataValueType::IntArray,
735 MetadataValue::FloatArray(_) => MetadataValueType::FloatArray,
736 MetadataValue::StringArray(_) => MetadataValueType::StringArray,
737 }
738 }
739}
740
741impl From<&MetadataValue> for MetadataValueType {
742 fn from(value: &MetadataValue) -> Self {
743 value.value_type()
744 }
745}
746
747impl From<bool> for MetadataValue {
748 fn from(v: bool) -> Self {
749 MetadataValue::Bool(v)
750 }
751}
752
753impl From<i64> for MetadataValue {
754 fn from(v: i64) -> Self {
755 MetadataValue::Int(v)
756 }
757}
758
759impl From<i32> for MetadataValue {
760 fn from(v: i32) -> Self {
761 MetadataValue::Int(v as i64)
762 }
763}
764
765impl From<f64> for MetadataValue {
766 fn from(v: f64) -> Self {
767 MetadataValue::Float(v)
768 }
769}
770
771impl From<f32> for MetadataValue {
772 fn from(v: f32) -> Self {
773 MetadataValue::Float(v as f64)
774 }
775}
776
777impl From<String> for MetadataValue {
778 fn from(v: String) -> Self {
779 MetadataValue::Str(v)
780 }
781}
782
783impl From<&str> for MetadataValue {
784 fn from(v: &str) -> Self {
785 MetadataValue::Str(v.to_string())
786 }
787}
788
789impl From<SparseVector> for MetadataValue {
790 fn from(v: SparseVector) -> Self {
791 MetadataValue::SparseVector(v)
792 }
793}
794
795impl From<Vec<bool>> for MetadataValue {
796 fn from(v: Vec<bool>) -> Self {
797 MetadataValue::BoolArray(v)
798 }
799}
800
801impl From<Vec<i64>> for MetadataValue {
802 fn from(v: Vec<i64>) -> Self {
803 MetadataValue::IntArray(v)
804 }
805}
806
807impl From<Vec<i32>> for MetadataValue {
808 fn from(v: Vec<i32>) -> Self {
809 MetadataValue::IntArray(v.into_iter().map(|x| x as i64).collect())
810 }
811}
812
813impl From<Vec<f64>> for MetadataValue {
814 fn from(v: Vec<f64>) -> Self {
815 MetadataValue::FloatArray(v)
816 }
817}
818
819impl From<Vec<f32>> for MetadataValue {
820 fn from(v: Vec<f32>) -> Self {
821 MetadataValue::FloatArray(v.into_iter().map(|x| x as f64).collect())
822 }
823}
824
825impl From<Vec<String>> for MetadataValue {
826 fn from(v: Vec<String>) -> Self {
827 MetadataValue::StringArray(v)
828 }
829}
830
831impl From<Vec<&str>> for MetadataValue {
832 fn from(v: Vec<&str>) -> Self {
833 MetadataValue::StringArray(v.into_iter().map(|s| s.to_string()).collect())
834 }
835}
836
837#[allow(clippy::derive_ord_xor_partial_ord)]
842impl Ord for MetadataValue {
843 fn cmp(&self, other: &Self) -> Ordering {
844 fn type_order(val: &MetadataValue) -> u8 {
846 match val {
847 MetadataValue::Bool(_) => 0,
848 MetadataValue::Int(_) => 1,
849 MetadataValue::Float(_) => 2,
850 MetadataValue::Str(_) => 3,
851 MetadataValue::SparseVector(_) => 4,
852 MetadataValue::BoolArray(_) => 5,
853 MetadataValue::IntArray(_) => 6,
854 MetadataValue::FloatArray(_) => 7,
855 MetadataValue::StringArray(_) => 8,
856 }
857 }
858
859 type_order(self).cmp(&type_order(other)).then_with(|| {
861 match (self, other) {
862 (MetadataValue::Bool(left), MetadataValue::Bool(right)) => left.cmp(right),
863 (MetadataValue::Int(left), MetadataValue::Int(right)) => left.cmp(right),
864 (MetadataValue::Float(left), MetadataValue::Float(right)) => left.total_cmp(right),
865 (MetadataValue::Str(left), MetadataValue::Str(right)) => left.cmp(right),
866 (MetadataValue::SparseVector(left), MetadataValue::SparseVector(right)) => {
867 left.cmp(right)
868 }
869 (MetadataValue::BoolArray(left), MetadataValue::BoolArray(right)) => {
870 left.cmp(right)
871 }
872 (MetadataValue::IntArray(left), MetadataValue::IntArray(right)) => left.cmp(right),
873 (MetadataValue::FloatArray(left), MetadataValue::FloatArray(right)) => {
874 for (l, r) in left.iter().zip(right.iter()) {
876 match l.total_cmp(r) {
877 Ordering::Equal => continue,
878 other => return other,
879 }
880 }
881 left.len().cmp(&right.len())
882 }
883 (MetadataValue::StringArray(left), MetadataValue::StringArray(right)) => {
884 left.cmp(right)
885 }
886 _ => Ordering::Equal, }
888 })
889 }
890}
891
892impl PartialOrd for MetadataValue {
893 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
894 Some(self.cmp(other))
895 }
896}
897
898impl TryFrom<&MetadataValue> for bool {
899 type Error = MetadataValueConversionError;
900
901 fn try_from(value: &MetadataValue) -> Result<Self, Self::Error> {
902 match value {
903 MetadataValue::Bool(value) => Ok(*value),
904 _ => Err(MetadataValueConversionError::InvalidValue),
905 }
906 }
907}
908
909impl TryFrom<&MetadataValue> for i64 {
910 type Error = MetadataValueConversionError;
911
912 fn try_from(value: &MetadataValue) -> Result<Self, Self::Error> {
913 match value {
914 MetadataValue::Int(value) => Ok(*value),
915 _ => Err(MetadataValueConversionError::InvalidValue),
916 }
917 }
918}
919
920impl TryFrom<&MetadataValue> for f64 {
921 type Error = MetadataValueConversionError;
922
923 fn try_from(value: &MetadataValue) -> Result<Self, Self::Error> {
924 match value {
925 MetadataValue::Float(value) => Ok(*value),
926 _ => Err(MetadataValueConversionError::InvalidValue),
927 }
928 }
929}
930
931impl TryFrom<&MetadataValue> for String {
932 type Error = MetadataValueConversionError;
933
934 fn try_from(value: &MetadataValue) -> Result<Self, Self::Error> {
935 match value {
936 MetadataValue::Str(value) => Ok(value.clone()),
937 _ => Err(MetadataValueConversionError::InvalidValue),
938 }
939 }
940}
941
942impl From<MetadataValue> for UpdateMetadataValue {
943 fn from(value: MetadataValue) -> Self {
944 match value {
945 MetadataValue::Bool(v) => UpdateMetadataValue::Bool(v),
946 MetadataValue::Int(v) => UpdateMetadataValue::Int(v),
947 MetadataValue::Float(v) => UpdateMetadataValue::Float(v),
948 MetadataValue::Str(v) => UpdateMetadataValue::Str(v),
949 MetadataValue::SparseVector(v) => UpdateMetadataValue::SparseVector(v),
950 MetadataValue::BoolArray(v) => UpdateMetadataValue::BoolArray(v),
951 MetadataValue::IntArray(v) => UpdateMetadataValue::IntArray(v),
952 MetadataValue::FloatArray(v) => UpdateMetadataValue::FloatArray(v),
953 MetadataValue::StringArray(v) => UpdateMetadataValue::StringArray(v),
954 }
955 }
956}
957
958impl From<MetadataValue> for Value {
959 fn from(value: MetadataValue) -> Self {
960 match value {
961 MetadataValue::Bool(val) => Self::Bool(val),
962 MetadataValue::Int(val) => Self::Number(
963 Number::from_i128(val as i128).expect("i64 should be representable in JSON"),
964 ),
965 MetadataValue::Float(val) => Self::Number(
966 Number::from_f64(val).expect("Inf and NaN should not be present in MetadataValue"),
967 ),
968 MetadataValue::Str(val) => Self::String(val),
969 MetadataValue::SparseVector(val) => {
970 let mut map = serde_json::Map::new();
971 map.insert(
972 "indices".to_string(),
973 Value::Array(
974 val.indices
975 .iter()
976 .map(|&i| Value::Number(i.into()))
977 .collect(),
978 ),
979 );
980 map.insert(
981 "values".to_string(),
982 Value::Array(
983 val.values
984 .iter()
985 .map(|&v| {
986 Value::Number(
987 Number::from_f64(v as f64)
988 .expect("Float number should not be NaN or infinite"),
989 )
990 })
991 .collect(),
992 ),
993 );
994 Self::Object(map)
995 }
996 MetadataValue::BoolArray(vals) => {
997 Self::Array(vals.into_iter().map(Value::Bool).collect())
998 }
999 MetadataValue::IntArray(vals) => Self::Array(
1000 vals.into_iter()
1001 .map(|v| {
1002 Value::Number(
1003 Number::from_i128(v as i128)
1004 .expect("i64 should be representable in JSON"),
1005 )
1006 })
1007 .collect(),
1008 ),
1009 MetadataValue::FloatArray(vals) => Self::Array(
1010 vals.into_iter()
1011 .map(|v| {
1012 Value::Number(
1013 Number::from_f64(v)
1014 .expect("Inf and NaN should not be present in MetadataValue"),
1015 )
1016 })
1017 .collect(),
1018 ),
1019 MetadataValue::StringArray(vals) => {
1020 Self::Array(vals.into_iter().map(Value::String).collect())
1021 }
1022 }
1023 }
1024}
1025
1026#[derive(Error, Debug)]
1027pub enum MetadataValueConversionError {
1028 #[error("Invalid metadata value, valid values are: Int, Float, Str")]
1029 InvalidValue,
1030 #[error("Metadata key cannot start with '#' or '$': {0}")]
1031 InvalidKey(String),
1032 #[error("Sparse vector indices, values, and tokens (when present) must have the same length")]
1033 SparseVectorLengthMismatch,
1034 #[error("Sparse vector indices must be sorted in strictly ascending order (no duplicates)")]
1035 SparseVectorIndicesNotSorted,
1036}
1037
1038impl ChromaError for MetadataValueConversionError {
1039 fn code(&self) -> ErrorCodes {
1040 match self {
1041 MetadataValueConversionError::InvalidValue => ErrorCodes::InvalidArgument,
1042 MetadataValueConversionError::InvalidKey(_) => ErrorCodes::InvalidArgument,
1043 MetadataValueConversionError::SparseVectorLengthMismatch => ErrorCodes::InvalidArgument,
1044 MetadataValueConversionError::SparseVectorIndicesNotSorted => {
1045 ErrorCodes::InvalidArgument
1046 }
1047 }
1048 }
1049}
1050
1051impl TryFrom<&chroma_proto::UpdateMetadataValue> for MetadataValue {
1052 type Error = MetadataValueConversionError;
1053
1054 fn try_from(value: &chroma_proto::UpdateMetadataValue) -> Result<Self, Self::Error> {
1055 match &value.value {
1056 Some(chroma_proto::update_metadata_value::Value::BoolValue(value)) => {
1057 Ok(MetadataValue::Bool(*value))
1058 }
1059 Some(chroma_proto::update_metadata_value::Value::IntValue(value)) => {
1060 Ok(MetadataValue::Int(*value))
1061 }
1062 Some(chroma_proto::update_metadata_value::Value::FloatValue(value)) => {
1063 if !value.is_finite() {
1064 return Err(MetadataValueConversionError::InvalidValue);
1065 }
1066 Ok(MetadataValue::Float(*value))
1067 }
1068 Some(chroma_proto::update_metadata_value::Value::StringValue(value)) => {
1069 Ok(MetadataValue::Str(value.clone()))
1070 }
1071 Some(chroma_proto::update_metadata_value::Value::SparseVectorValue(value)) => {
1072 let sparse = value
1073 .clone()
1074 .try_into()
1075 .map_err(|_| MetadataValueConversionError::SparseVectorLengthMismatch)?;
1076 Ok(MetadataValue::SparseVector(sparse))
1077 }
1078 Some(chroma_proto::update_metadata_value::Value::BoolListValue(value)) => {
1079 Ok(MetadataValue::BoolArray(value.values.clone()))
1080 }
1081 Some(chroma_proto::update_metadata_value::Value::IntListValue(value)) => {
1082 Ok(MetadataValue::IntArray(value.values.clone()))
1083 }
1084 Some(chroma_proto::update_metadata_value::Value::DoubleListValue(value)) => {
1085 if value.values.iter().any(|v| !v.is_finite()) {
1086 return Err(MetadataValueConversionError::InvalidValue);
1087 }
1088 Ok(MetadataValue::FloatArray(value.values.clone()))
1089 }
1090 Some(chroma_proto::update_metadata_value::Value::StringListValue(value)) => {
1091 Ok(MetadataValue::StringArray(value.values.clone()))
1092 }
1093 _ => Err(MetadataValueConversionError::InvalidValue),
1094 }
1095 }
1096}
1097
1098impl From<MetadataValue> for chroma_proto::UpdateMetadataValue {
1099 fn from(value: MetadataValue) -> Self {
1100 match value {
1101 MetadataValue::Int(value) => chroma_proto::UpdateMetadataValue {
1102 value: Some(chroma_proto::update_metadata_value::Value::IntValue(value)),
1103 },
1104 MetadataValue::Float(value) => chroma_proto::UpdateMetadataValue {
1105 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(
1106 value,
1107 )),
1108 },
1109 MetadataValue::Str(value) => chroma_proto::UpdateMetadataValue {
1110 value: Some(chroma_proto::update_metadata_value::Value::StringValue(
1111 value,
1112 )),
1113 },
1114 MetadataValue::Bool(value) => chroma_proto::UpdateMetadataValue {
1115 value: Some(chroma_proto::update_metadata_value::Value::BoolValue(value)),
1116 },
1117 MetadataValue::SparseVector(sparse_vec) => chroma_proto::UpdateMetadataValue {
1118 value: Some(
1119 chroma_proto::update_metadata_value::Value::SparseVectorValue(
1120 sparse_vec.into(),
1121 ),
1122 ),
1123 },
1124 MetadataValue::BoolArray(values) => chroma_proto::UpdateMetadataValue {
1125 value: Some(chroma_proto::update_metadata_value::Value::BoolListValue(
1126 chroma_proto::BoolListValue { values },
1127 )),
1128 },
1129 MetadataValue::IntArray(values) => chroma_proto::UpdateMetadataValue {
1130 value: Some(chroma_proto::update_metadata_value::Value::IntListValue(
1131 chroma_proto::IntListValue { values },
1132 )),
1133 },
1134 MetadataValue::FloatArray(values) => chroma_proto::UpdateMetadataValue {
1135 value: Some(chroma_proto::update_metadata_value::Value::DoubleListValue(
1136 chroma_proto::DoubleListValue { values },
1137 )),
1138 },
1139 MetadataValue::StringArray(values) => chroma_proto::UpdateMetadataValue {
1140 value: Some(chroma_proto::update_metadata_value::Value::StringListValue(
1141 chroma_proto::StringListValue { values },
1142 )),
1143 },
1144 }
1145 }
1146}
1147
1148pub type UpdateMetadata = HashMap<String, UpdateMetadataValue>;
1154
1155pub fn are_update_metadatas_close_to_equal(
1159 metadata1: &UpdateMetadata,
1160 metadata2: &UpdateMetadata,
1161) -> bool {
1162 assert_eq!(metadata1.len(), metadata2.len());
1163
1164 for (key, value) in metadata1.iter() {
1165 if !metadata2.contains_key(key) {
1166 return false;
1167 }
1168 let other_value = metadata2.get(key).unwrap();
1169
1170 if let (UpdateMetadataValue::Float(value), UpdateMetadataValue::Float(other_value)) =
1171 (value, other_value)
1172 {
1173 if (value - other_value).abs() > 1e-6 {
1174 return false;
1175 }
1176 } else if value != other_value {
1177 return false;
1178 }
1179 }
1180
1181 true
1182}
1183
1184pub fn are_metadatas_close_to_equal(metadata1: &Metadata, metadata2: &Metadata) -> bool {
1185 assert_eq!(metadata1.len(), metadata2.len());
1186
1187 for (key, value) in metadata1.iter() {
1188 if !metadata2.contains_key(key) {
1189 return false;
1190 }
1191 let other_value = metadata2.get(key).unwrap();
1192
1193 if let (MetadataValue::Float(value), MetadataValue::Float(other_value)) =
1194 (value, other_value)
1195 {
1196 if (value - other_value).abs() > 1e-6 {
1197 return false;
1198 }
1199 } else if value != other_value {
1200 return false;
1201 }
1202 }
1203
1204 true
1205}
1206
1207impl TryFrom<chroma_proto::UpdateMetadata> for UpdateMetadata {
1208 type Error = UpdateMetadataValueConversionError;
1209
1210 fn try_from(proto_metadata: chroma_proto::UpdateMetadata) -> Result<Self, Self::Error> {
1211 let mut metadata = UpdateMetadata::with_capacity(proto_metadata.metadata.len());
1212 for (key, value) in proto_metadata.metadata.into_iter() {
1213 let value = match (&value).try_into() {
1214 Ok(value) => value,
1215 Err(_) => return Err(UpdateMetadataValueConversionError::InvalidValue),
1216 };
1217 metadata.insert(key, value);
1218 }
1219 Ok(metadata)
1220 }
1221}
1222
1223impl From<UpdateMetadata> for chroma_proto::UpdateMetadata {
1224 fn from(metadata: UpdateMetadata) -> Self {
1225 let mut proto_metadata = chroma_proto::UpdateMetadata {
1226 metadata: HashMap::with_capacity(metadata.len()),
1227 };
1228 for (key, value) in metadata.into_iter() {
1229 let proto_value = value.into();
1230 proto_metadata.metadata.insert(key, proto_value);
1231 }
1232 proto_metadata
1233 }
1234}
1235
1236pub type Metadata = HashMap<String, MetadataValue>;
1243pub type DeletedMetadata = HashSet<String>;
1244
1245pub fn logical_size_of_metadata(metadata: &Metadata) -> usize {
1246 metadata
1247 .iter()
1248 .map(|(k, v)| {
1249 k.len()
1250 + match v {
1251 MetadataValue::Bool(b) => size_of_val(b),
1252 MetadataValue::Int(i) => size_of_val(i),
1253 MetadataValue::Float(f) => size_of_val(f),
1254 MetadataValue::Str(s) => s.len(),
1255 MetadataValue::SparseVector(v) => {
1256 size_of_val(&v.indices[..]) + size_of_val(&v.values[..])
1257 }
1258 MetadataValue::BoolArray(arr) => size_of_val(&arr[..]),
1259 MetadataValue::IntArray(arr) => size_of_val(&arr[..]),
1260 MetadataValue::FloatArray(arr) => size_of_val(&arr[..]),
1261 MetadataValue::StringArray(arr) => arr.iter().map(|s| s.len()).sum::<usize>(),
1262 }
1263 })
1264 .sum()
1265}
1266
1267pub fn get_metadata_value_as<'a, T>(
1268 metadata: &'a Metadata,
1269 key: &str,
1270) -> Result<T, Box<MetadataValueConversionError>>
1271where
1272 T: TryFrom<&'a MetadataValue, Error = MetadataValueConversionError>,
1273{
1274 let res = match metadata.get(key) {
1275 Some(value) => T::try_from(value),
1276 None => return Err(Box::new(MetadataValueConversionError::InvalidValue)),
1277 };
1278 match res {
1279 Ok(value) => Ok(value),
1280 Err(_) => Err(Box::new(MetadataValueConversionError::InvalidValue)),
1281 }
1282}
1283
1284impl TryFrom<chroma_proto::UpdateMetadata> for Metadata {
1285 type Error = MetadataValueConversionError;
1286
1287 fn try_from(proto_metadata: chroma_proto::UpdateMetadata) -> Result<Self, Self::Error> {
1288 let mut metadata = Metadata::new();
1289 for (key, value) in proto_metadata.metadata.iter() {
1290 let maybe_value: Result<MetadataValue, Self::Error> = value.try_into();
1291 if maybe_value.is_err() {
1292 return Err(MetadataValueConversionError::InvalidValue);
1293 }
1294 let value = maybe_value.unwrap();
1295 metadata.insert(key.clone(), value);
1296 }
1297 Ok(metadata)
1298 }
1299}
1300
1301impl From<Metadata> for chroma_proto::UpdateMetadata {
1302 fn from(metadata: Metadata) -> Self {
1303 let mut metadata = metadata;
1304 let mut proto_metadata = chroma_proto::UpdateMetadata {
1305 metadata: HashMap::new(),
1306 };
1307 for (key, value) in metadata.drain() {
1308 let proto_value = value.into();
1309 proto_metadata.metadata.insert(key.clone(), proto_value);
1310 }
1311 proto_metadata
1312 }
1313}
1314
1315#[derive(Debug, Default)]
1316pub struct MetadataDelta<'referred_data> {
1317 pub metadata_to_update: HashMap<
1318 &'referred_data str,
1319 (&'referred_data MetadataValue, &'referred_data MetadataValue),
1320 >,
1321 pub metadata_to_delete: HashMap<&'referred_data str, &'referred_data MetadataValue>,
1322 pub metadata_to_insert: HashMap<&'referred_data str, &'referred_data MetadataValue>,
1323}
1324
1325impl MetadataDelta<'_> {
1326 pub fn new() -> Self {
1327 Self::default()
1328 }
1329}
1330
1331#[derive(Clone, Debug, Error, PartialEq)]
1338pub enum WhereConversionError {
1339 #[error("Error: {0}")]
1340 Cause(String),
1341 #[error("{0} -> {1}")]
1342 Trace(String, Box<Self>),
1343}
1344
1345impl WhereConversionError {
1346 pub fn cause(msg: impl ToString) -> Self {
1347 Self::Cause(msg.to_string())
1348 }
1349
1350 pub fn trace(self, context: impl ToString) -> Self {
1351 Self::Trace(context.to_string(), Box::new(self))
1352 }
1353}
1354
1355#[derive(Clone, Debug, PartialEq)]
1363#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1364pub enum Where {
1365 Composite(CompositeExpression),
1366 Document(DocumentExpression),
1367 Metadata(MetadataExpression),
1368}
1369
1370impl std::fmt::Display for Where {
1371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1372 match self {
1373 Where::Composite(composite) => {
1374 let fragment = composite
1375 .children
1376 .iter()
1377 .map(|child| format!("{}", child))
1378 .collect::<Vec<_>>()
1379 .join(match composite.operator {
1380 BooleanOperator::And => " & ",
1381 BooleanOperator::Or => " | ",
1382 });
1383 write!(f, "({})", fragment)
1384 }
1385 Where::Metadata(expr) => write!(f, "{}", expr),
1386 Where::Document(expr) => write!(f, "{}", expr),
1387 }
1388 }
1389}
1390
1391impl serde::Serialize for Where {
1392 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1393 where
1394 S: Serializer,
1395 {
1396 match self {
1397 Where::Composite(composite) => {
1398 let mut map = serializer.serialize_map(Some(1))?;
1399 let op_key = match composite.operator {
1400 BooleanOperator::And => "$and",
1401 BooleanOperator::Or => "$or",
1402 };
1403 map.serialize_entry(op_key, &composite.children)?;
1404 map.end()
1405 }
1406 Where::Document(doc) => {
1407 let mut outer_map = serializer.serialize_map(Some(1))?;
1408 let mut inner_map = serde_json::Map::new();
1409 let op_key = match doc.operator {
1410 DocumentOperator::Contains => "$contains",
1411 DocumentOperator::NotContains => "$not_contains",
1412 DocumentOperator::Regex => "$regex",
1413 DocumentOperator::NotRegex => "$not_regex",
1414 };
1415 inner_map.insert(
1416 op_key.to_string(),
1417 serde_json::Value::String(doc.pattern.clone()),
1418 );
1419 outer_map.serialize_entry("#document", &inner_map)?;
1420 outer_map.end()
1421 }
1422 Where::Metadata(meta) => {
1423 let mut outer_map = serializer.serialize_map(Some(1))?;
1424 let mut inner_map = serde_json::Map::new();
1425
1426 match &meta.comparison {
1427 MetadataComparison::Primitive(op, value) => {
1428 let op_key = match op {
1429 PrimitiveOperator::Equal => "$eq",
1430 PrimitiveOperator::NotEqual => "$ne",
1431 PrimitiveOperator::GreaterThan => "$gt",
1432 PrimitiveOperator::GreaterThanOrEqual => "$gte",
1433 PrimitiveOperator::LessThan => "$lt",
1434 PrimitiveOperator::LessThanOrEqual => "$lte",
1435 };
1436 let value_json =
1437 serde_json::to_value(value).map_err(serde::ser::Error::custom)?;
1438 inner_map.insert(op_key.to_string(), value_json);
1439 }
1440 MetadataComparison::Set(op, set_value) => {
1441 let op_key = match op {
1442 SetOperator::In => "$in",
1443 SetOperator::NotIn => "$nin",
1444 };
1445 let values_json = match set_value {
1446 MetadataSetValue::Bool(v) => serde_json::to_value(v),
1447 MetadataSetValue::Int(v) => serde_json::to_value(v),
1448 MetadataSetValue::Float(v) => serde_json::to_value(v),
1449 MetadataSetValue::Str(v) => serde_json::to_value(v),
1450 }
1451 .map_err(serde::ser::Error::custom)?;
1452 inner_map.insert(op_key.to_string(), values_json);
1453 }
1454 MetadataComparison::ArrayContains(op, value) => {
1455 let op_key = match op {
1456 ContainsOperator::Contains => "$contains",
1457 ContainsOperator::NotContains => "$not_contains",
1458 };
1459 let value_json =
1460 serde_json::to_value(value).map_err(serde::ser::Error::custom)?;
1461 inner_map.insert(op_key.to_string(), value_json);
1462 }
1463 }
1464
1465 outer_map.serialize_entry(&meta.key, &inner_map)?;
1466 outer_map.end()
1467 }
1468 }
1469 }
1470}
1471
1472impl From<bool> for Where {
1473 fn from(value: bool) -> Self {
1474 if value {
1475 Where::conjunction(vec![])
1476 } else {
1477 Where::disjunction(vec![])
1478 }
1479 }
1480}
1481
1482impl Where {
1483 pub fn conjunction(children: impl IntoIterator<Item = Where>) -> Self {
1484 let mut children: Vec<_> = children
1489 .into_iter()
1490 .flat_map(|expr| {
1491 if let Where::Composite(CompositeExpression {
1492 operator: BooleanOperator::And,
1493 children,
1494 }) = expr
1495 {
1496 return children;
1497 }
1498 vec![expr]
1499 })
1500 .dedup()
1501 .collect();
1502
1503 if children.len() == 1 {
1504 return children.pop().expect("just checked len is 1");
1505 }
1506
1507 Self::Composite(CompositeExpression {
1508 operator: BooleanOperator::And,
1509 children,
1510 })
1511 }
1512 pub fn disjunction(children: impl IntoIterator<Item = Where>) -> Self {
1513 let mut children: Vec<_> = children
1518 .into_iter()
1519 .flat_map(|expr| {
1520 if let Where::Composite(CompositeExpression {
1521 operator: BooleanOperator::Or,
1522 children,
1523 }) = expr
1524 {
1525 return children;
1526 }
1527 vec![expr]
1528 })
1529 .dedup()
1530 .collect();
1531
1532 if children.len() == 1 {
1533 return children.pop().expect("just checked len is 1");
1534 }
1535
1536 Self::Composite(CompositeExpression {
1537 operator: BooleanOperator::Or,
1538 children,
1539 })
1540 }
1541
1542 pub fn fts_query_length(&self) -> u64 {
1543 match self {
1544 Where::Composite(composite_expression) => composite_expression
1545 .children
1546 .iter()
1547 .map(Where::fts_query_length)
1548 .sum(),
1549 Where::Document(document_expression) => {
1551 document_expression.pattern.len().max(3) as u64 - 2
1552 }
1553 Where::Metadata(_) => 0,
1554 }
1555 }
1556
1557 pub fn metadata_predicate_count(&self) -> u64 {
1558 match self {
1559 Where::Composite(composite_expression) => composite_expression
1560 .children
1561 .iter()
1562 .map(Where::metadata_predicate_count)
1563 .sum(),
1564 Where::Document(_) => 0,
1565 Where::Metadata(metadata_expression) => match &metadata_expression.comparison {
1566 MetadataComparison::Primitive(_, _) => 1,
1567 MetadataComparison::Set(_, metadata_set_value) => match metadata_set_value {
1568 MetadataSetValue::Bool(items) => items.len() as u64,
1569 MetadataSetValue::Int(items) => items.len() as u64,
1570 MetadataSetValue::Float(items) => items.len() as u64,
1571 MetadataSetValue::Str(items) => items.len() as u64,
1572 },
1573 MetadataComparison::ArrayContains(_, _) => 1,
1574 },
1575 }
1576 }
1577}
1578
1579impl BitAnd for Where {
1580 type Output = Where;
1581
1582 fn bitand(self, rhs: Self) -> Self::Output {
1583 Self::conjunction([self, rhs])
1584 }
1585}
1586
1587impl BitOr for Where {
1588 type Output = Where;
1589
1590 fn bitor(self, rhs: Self) -> Self::Output {
1591 Self::disjunction([self, rhs])
1592 }
1593}
1594
1595impl TryFrom<chroma_proto::Where> for Where {
1596 type Error = WhereConversionError;
1597
1598 fn try_from(proto_where: chroma_proto::Where) -> Result<Self, Self::Error> {
1599 let where_inner = proto_where
1600 .r#where
1601 .ok_or(WhereConversionError::cause("Invalid Where"))?;
1602 Ok(match where_inner {
1603 chroma_proto::r#where::Where::DirectComparison(direct_comparison) => {
1604 Self::Metadata(direct_comparison.try_into()?)
1605 }
1606 chroma_proto::r#where::Where::Children(where_children) => {
1607 Self::Composite(where_children.try_into()?)
1608 }
1609 chroma_proto::r#where::Where::DirectDocumentComparison(direct_where_document) => {
1610 Self::Document(direct_where_document.into())
1611 }
1612 })
1613 }
1614}
1615
1616impl TryFrom<Where> for chroma_proto::Where {
1617 type Error = WhereConversionError;
1618
1619 fn try_from(value: Where) -> Result<Self, Self::Error> {
1620 let proto_where = match value {
1621 Where::Composite(composite_expression) => {
1622 chroma_proto::r#where::Where::Children(composite_expression.try_into()?)
1623 }
1624 Where::Document(document_expression) => {
1625 chroma_proto::r#where::Where::DirectDocumentComparison(document_expression.into())
1626 }
1627 Where::Metadata(metadata_expression) => chroma_proto::r#where::Where::DirectComparison(
1628 chroma_proto::DirectComparison::try_from(metadata_expression)
1629 .map_err(|err| err.trace("MetadataExpression"))?,
1630 ),
1631 };
1632 Ok(Self {
1633 r#where: Some(proto_where),
1634 })
1635 }
1636}
1637
1638#[derive(Clone, Debug, PartialEq)]
1639#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1640pub struct CompositeExpression {
1641 pub operator: BooleanOperator,
1642 pub children: Vec<Where>,
1643}
1644
1645impl TryFrom<chroma_proto::WhereChildren> for CompositeExpression {
1646 type Error = WhereConversionError;
1647
1648 fn try_from(proto_children: chroma_proto::WhereChildren) -> Result<Self, Self::Error> {
1649 let operator = proto_children.operator().into();
1650 let children = proto_children
1651 .children
1652 .into_iter()
1653 .map(Where::try_from)
1654 .collect::<Result<Vec<_>, _>>()
1655 .map_err(|err| err.trace("Child Where of CompositeExpression"))?;
1656 Ok(Self { operator, children })
1657 }
1658}
1659
1660impl TryFrom<CompositeExpression> for chroma_proto::WhereChildren {
1661 type Error = WhereConversionError;
1662
1663 fn try_from(value: CompositeExpression) -> Result<Self, Self::Error> {
1664 Ok(Self {
1665 operator: chroma_proto::BooleanOperator::from(value.operator) as i32,
1666 children: value
1667 .children
1668 .into_iter()
1669 .map(chroma_proto::Where::try_from)
1670 .collect::<Result<_, _>>()?,
1671 })
1672 }
1673}
1674
1675#[derive(Clone, Debug, PartialEq)]
1676#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1677pub enum BooleanOperator {
1678 And,
1679 Or,
1680}
1681
1682impl From<chroma_proto::BooleanOperator> for BooleanOperator {
1683 fn from(value: chroma_proto::BooleanOperator) -> Self {
1684 match value {
1685 chroma_proto::BooleanOperator::And => Self::And,
1686 chroma_proto::BooleanOperator::Or => Self::Or,
1687 }
1688 }
1689}
1690
1691impl From<BooleanOperator> for chroma_proto::BooleanOperator {
1692 fn from(value: BooleanOperator) -> Self {
1693 match value {
1694 BooleanOperator::And => Self::And,
1695 BooleanOperator::Or => Self::Or,
1696 }
1697 }
1698}
1699
1700#[derive(Clone, Debug, PartialEq)]
1701#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1702pub struct DocumentExpression {
1703 pub operator: DocumentOperator,
1704 pub pattern: String,
1705}
1706
1707impl std::fmt::Display for DocumentExpression {
1708 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1709 let op_str = match self.operator {
1710 DocumentOperator::Contains => "CONTAINS",
1711 DocumentOperator::NotContains => "NOT CONTAINS",
1712 DocumentOperator::Regex => "REGEX",
1713 DocumentOperator::NotRegex => "NOT REGEX",
1714 };
1715 write!(f, "#document {} \"{}\"", op_str, self.pattern)
1716 }
1717}
1718
1719impl From<chroma_proto::DirectWhereDocument> for DocumentExpression {
1720 fn from(value: chroma_proto::DirectWhereDocument) -> Self {
1721 Self {
1722 operator: value.operator().into(),
1723 pattern: value.pattern,
1724 }
1725 }
1726}
1727
1728impl From<DocumentExpression> for chroma_proto::DirectWhereDocument {
1729 fn from(value: DocumentExpression) -> Self {
1730 Self {
1731 pattern: value.pattern,
1732 operator: chroma_proto::WhereDocumentOperator::from(value.operator) as i32,
1733 }
1734 }
1735}
1736
1737#[derive(Clone, Debug, PartialEq)]
1738#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1739pub enum DocumentOperator {
1740 Contains,
1741 NotContains,
1742 Regex,
1743 NotRegex,
1744}
1745impl From<chroma_proto::WhereDocumentOperator> for DocumentOperator {
1746 fn from(value: chroma_proto::WhereDocumentOperator) -> Self {
1747 match value {
1748 chroma_proto::WhereDocumentOperator::Contains => Self::Contains,
1749 chroma_proto::WhereDocumentOperator::NotContains => Self::NotContains,
1750 chroma_proto::WhereDocumentOperator::Regex => Self::Regex,
1751 chroma_proto::WhereDocumentOperator::NotRegex => Self::NotRegex,
1752 }
1753 }
1754}
1755
1756impl From<DocumentOperator> for chroma_proto::WhereDocumentOperator {
1757 fn from(value: DocumentOperator) -> Self {
1758 match value {
1759 DocumentOperator::Contains => Self::Contains,
1760 DocumentOperator::NotContains => Self::NotContains,
1761 DocumentOperator::Regex => Self::Regex,
1762 DocumentOperator::NotRegex => Self::NotRegex,
1763 }
1764 }
1765}
1766
1767#[derive(Clone, Debug, PartialEq)]
1768#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1769pub struct MetadataExpression {
1770 pub key: String,
1771 pub comparison: MetadataComparison,
1772}
1773
1774impl std::fmt::Display for MetadataExpression {
1775 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1776 match &self.comparison {
1777 MetadataComparison::Primitive(op, value) => {
1778 write!(f, "{} {} {}", self.key, op, value)
1779 }
1780 MetadataComparison::Set(op, set_value) => {
1781 write!(f, "{} {} {}", self.key, op, set_value)
1782 }
1783 MetadataComparison::ArrayContains(op, value) => {
1784 write!(f, "{} {} {}", self.key, op, value)
1785 }
1786 }
1787 }
1788}
1789
1790fn generic_comparator_to_metadata_comparison(
1794 comparator: chroma_proto::GenericComparator,
1795 value: MetadataValue,
1796) -> MetadataComparison {
1797 match comparator {
1798 chroma_proto::GenericComparator::Eq | chroma_proto::GenericComparator::Ne => {
1799 MetadataComparison::Primitive(comparator.try_into().unwrap(), value)
1802 }
1803 chroma_proto::GenericComparator::ArrayContains => {
1804 MetadataComparison::ArrayContains(ContainsOperator::Contains, value)
1805 }
1806 chroma_proto::GenericComparator::ArrayNotContains => {
1807 MetadataComparison::ArrayContains(ContainsOperator::NotContains, value)
1808 }
1809 }
1810}
1811
1812impl TryFrom<chroma_proto::DirectComparison> for MetadataExpression {
1813 type Error = WhereConversionError;
1814
1815 fn try_from(value: chroma_proto::DirectComparison) -> Result<Self, Self::Error> {
1816 let proto_comparison = value
1817 .comparison
1818 .ok_or(WhereConversionError::cause("Invalid MetadataExpression"))?;
1819 let comparison = match proto_comparison {
1820 chroma_proto::direct_comparison::Comparison::SingleStringOperand(
1821 single_string_comparison,
1822 ) => generic_comparator_to_metadata_comparison(
1823 single_string_comparison.comparator(),
1824 MetadataValue::Str(single_string_comparison.value),
1825 ),
1826 chroma_proto::direct_comparison::Comparison::StringListOperand(
1827 string_list_comparison,
1828 ) => MetadataComparison::Set(
1829 string_list_comparison.list_operator().into(),
1830 MetadataSetValue::Str(string_list_comparison.values),
1831 ),
1832 chroma_proto::direct_comparison::Comparison::SingleIntOperand(
1833 single_int_comparison,
1834 ) => {
1835 let comparator =
1836 single_int_comparison
1837 .comparator
1838 .ok_or(WhereConversionError::cause(
1839 "Invalid scalar integer operator",
1840 ))?;
1841 let value = MetadataValue::Int(single_int_comparison.value);
1842 match comparator {
1843 chroma_proto::single_int_comparison::Comparator::GenericComparator(op) => {
1844 let generic = chroma_proto::GenericComparator::try_from(op)
1845 .map_err(WhereConversionError::cause)?;
1846 generic_comparator_to_metadata_comparison(generic, value)
1847 }
1848 chroma_proto::single_int_comparison::Comparator::NumberComparator(op) => {
1849 MetadataComparison::Primitive(
1850 chroma_proto::NumberComparator::try_from(op)
1851 .map_err(WhereConversionError::cause)?
1852 .into(),
1853 value,
1854 )
1855 }
1856 }
1857 }
1858 chroma_proto::direct_comparison::Comparison::IntListOperand(int_list_comparison) => {
1859 MetadataComparison::Set(
1860 int_list_comparison.list_operator().into(),
1861 MetadataSetValue::Int(int_list_comparison.values),
1862 )
1863 }
1864 chroma_proto::direct_comparison::Comparison::SingleDoubleOperand(
1865 single_double_comparison,
1866 ) => {
1867 let comparator = single_double_comparison
1868 .comparator
1869 .ok_or(WhereConversionError::cause("Invalid scalar float operator"))?;
1870 let value = MetadataValue::Float(single_double_comparison.value);
1871 match comparator {
1872 chroma_proto::single_double_comparison::Comparator::GenericComparator(op) => {
1873 let generic = chroma_proto::GenericComparator::try_from(op)
1874 .map_err(WhereConversionError::cause)?;
1875 generic_comparator_to_metadata_comparison(generic, value)
1876 }
1877 chroma_proto::single_double_comparison::Comparator::NumberComparator(op) => {
1878 MetadataComparison::Primitive(
1879 chroma_proto::NumberComparator::try_from(op)
1880 .map_err(WhereConversionError::cause)?
1881 .into(),
1882 value,
1883 )
1884 }
1885 }
1886 }
1887 chroma_proto::direct_comparison::Comparison::DoubleListOperand(
1888 double_list_comparison,
1889 ) => MetadataComparison::Set(
1890 double_list_comparison.list_operator().into(),
1891 MetadataSetValue::Float(double_list_comparison.values),
1892 ),
1893 chroma_proto::direct_comparison::Comparison::BoolListOperand(bool_list_comparison) => {
1894 MetadataComparison::Set(
1895 bool_list_comparison.list_operator().into(),
1896 MetadataSetValue::Bool(bool_list_comparison.values),
1897 )
1898 }
1899 chroma_proto::direct_comparison::Comparison::SingleBoolOperand(
1900 single_bool_comparison,
1901 ) => generic_comparator_to_metadata_comparison(
1902 single_bool_comparison.comparator(),
1903 MetadataValue::Bool(single_bool_comparison.value),
1904 ),
1905 };
1906 Ok(Self {
1907 key: value.key,
1908 comparison,
1909 })
1910 }
1911}
1912
1913impl TryFrom<MetadataExpression> for chroma_proto::DirectComparison {
1914 type Error = WhereConversionError;
1915
1916 fn try_from(value: MetadataExpression) -> Result<Self, Self::Error> {
1917 let comparison = match value.comparison {
1918 MetadataComparison::Primitive(primitive_operator, metadata_value) => match metadata_value {
1919 MetadataValue::Bool(value) => chroma_proto::direct_comparison::Comparison::SingleBoolOperand(chroma_proto::SingleBoolComparison { value, comparator: chroma_proto::GenericComparator::try_from(primitive_operator)? as i32 }),
1920 MetadataValue::Int(value) => chroma_proto::direct_comparison::Comparison::SingleIntOperand(chroma_proto::SingleIntComparison { value, comparator: Some(match primitive_operator {
1921 generic_operator @ PrimitiveOperator::Equal | generic_operator @ PrimitiveOperator::NotEqual => chroma_proto::single_int_comparison::Comparator::GenericComparator(chroma_proto::GenericComparator::try_from(generic_operator)? as i32),
1922 numeric => chroma_proto::single_int_comparison::Comparator::NumberComparator(chroma_proto::NumberComparator::try_from(numeric)? as i32) }),
1923 }),
1924 MetadataValue::Float(value) => chroma_proto::direct_comparison::Comparison::SingleDoubleOperand(chroma_proto::SingleDoubleComparison { value, comparator: Some(match primitive_operator {
1925 generic_operator @ PrimitiveOperator::Equal | generic_operator @ PrimitiveOperator::NotEqual => chroma_proto::single_double_comparison::Comparator::GenericComparator(chroma_proto::GenericComparator::try_from(generic_operator)? as i32),
1926 numeric => chroma_proto::single_double_comparison::Comparator::NumberComparator(chroma_proto::NumberComparator::try_from(numeric)? as i32) }),
1927 }),
1928 MetadataValue::Str(value) => chroma_proto::direct_comparison::Comparison::SingleStringOperand(chroma_proto::SingleStringComparison { value, comparator: chroma_proto::GenericComparator::try_from(primitive_operator)? as i32 }),
1929 MetadataValue::SparseVector(_) => return Err(WhereConversionError::Cause("Comparison with sparse vector is not supported".to_string())),
1930 MetadataValue::BoolArray(_) | MetadataValue::IntArray(_) | MetadataValue::FloatArray(_) | MetadataValue::StringArray(_) => {
1931 return Err(WhereConversionError::Cause("Primitive comparison with array metadata values is not supported".to_string()))
1932 }
1933 },
1934 MetadataComparison::Set(set_operator, metadata_set_value) => match metadata_set_value {
1935 MetadataSetValue::Bool(vec) => chroma_proto::direct_comparison::Comparison::BoolListOperand(chroma_proto::BoolListComparison { values: vec, list_operator: chroma_proto::ListOperator::from(set_operator) as i32 }),
1936 MetadataSetValue::Int(vec) => chroma_proto::direct_comparison::Comparison::IntListOperand(chroma_proto::IntListComparison { values: vec, list_operator: chroma_proto::ListOperator::from(set_operator) as i32 }),
1937 MetadataSetValue::Float(vec) => chroma_proto::direct_comparison::Comparison::DoubleListOperand(chroma_proto::DoubleListComparison { values: vec, list_operator: chroma_proto::ListOperator::from(set_operator) as i32 }),
1938 MetadataSetValue::Str(vec) => chroma_proto::direct_comparison::Comparison::StringListOperand(chroma_proto::StringListComparison { values: vec, list_operator: chroma_proto::ListOperator::from(set_operator) as i32 }),
1939 },
1940 MetadataComparison::ArrayContains(contains_operator, metadata_value) => {
1941 let comparator = chroma_proto::GenericComparator::from(contains_operator) as i32;
1942 match metadata_value {
1943 MetadataValue::Bool(value) => chroma_proto::direct_comparison::Comparison::SingleBoolOperand(chroma_proto::SingleBoolComparison { value, comparator }),
1944 MetadataValue::Int(value) => chroma_proto::direct_comparison::Comparison::SingleIntOperand(chroma_proto::SingleIntComparison { value, comparator: Some(chroma_proto::single_int_comparison::Comparator::GenericComparator(comparator)) }),
1945 MetadataValue::Float(value) => chroma_proto::direct_comparison::Comparison::SingleDoubleOperand(chroma_proto::SingleDoubleComparison { value, comparator: Some(chroma_proto::single_double_comparison::Comparator::GenericComparator(comparator)) }),
1946 MetadataValue::Str(value) => chroma_proto::direct_comparison::Comparison::SingleStringOperand(chroma_proto::SingleStringComparison { value, comparator }),
1947 MetadataValue::SparseVector(_) => return Err(WhereConversionError::Cause("Contains comparison with sparse vector is not supported".to_string())),
1948 MetadataValue::BoolArray(_) | MetadataValue::IntArray(_) | MetadataValue::FloatArray(_) | MetadataValue::StringArray(_) => {
1949 return Err(WhereConversionError::Cause("Contains comparison value must be a scalar, not an array".to_string()))
1950 }
1951 }
1952 },
1953 };
1954 Ok(Self {
1955 key: value.key,
1956 comparison: Some(comparison),
1957 })
1958 }
1959}
1960
1961#[derive(Clone, Debug, PartialEq)]
1962#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
1963pub enum MetadataComparison {
1964 Primitive(PrimitiveOperator, MetadataValue),
1965 Set(SetOperator, MetadataSetValue),
1966 ArrayContains(ContainsOperator, MetadataValue),
1969}
1970
1971impl std::fmt::Display for MetadataComparison {
1972 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1973 match self {
1974 MetadataComparison::Primitive(op, val) => {
1975 let type_name = match val {
1976 MetadataValue::Bool(_) => "Bool",
1977 MetadataValue::Int(_) => "Int",
1978 MetadataValue::Float(_) => "Float",
1979 MetadataValue::Str(_) => "Str",
1980 MetadataValue::SparseVector(_) => "SparseVector",
1981 MetadataValue::BoolArray(_) => "BoolArray",
1982 MetadataValue::IntArray(_) => "IntArray",
1983 MetadataValue::FloatArray(_) => "FloatArray",
1984 MetadataValue::StringArray(_) => "StringArray",
1985 };
1986 write!(f, "Primitive({}, {})", op, type_name)
1987 }
1988 MetadataComparison::Set(op, val) => {
1989 let type_name = match val {
1990 MetadataSetValue::Bool(_) => "Bool",
1991 MetadataSetValue::Int(_) => "Int",
1992 MetadataSetValue::Float(_) => "Float",
1993 MetadataSetValue::Str(_) => "Str",
1994 };
1995 write!(f, "Set({}, {})", op, type_name)
1996 }
1997 MetadataComparison::ArrayContains(op, val) => {
1998 let type_name = match val {
1999 MetadataValue::Bool(_) => "Bool",
2000 MetadataValue::Int(_) => "Int",
2001 MetadataValue::Float(_) => "Float",
2002 MetadataValue::Str(_) => "Str",
2003 MetadataValue::SparseVector(_) => "SparseVector",
2004 MetadataValue::BoolArray(_) => "BoolArray",
2005 MetadataValue::IntArray(_) => "IntArray",
2006 MetadataValue::FloatArray(_) => "FloatArray",
2007 MetadataValue::StringArray(_) => "StringArray",
2008 };
2009 write!(f, "ArrayContains({}, {})", op, type_name)
2010 }
2011 }
2012 }
2013}
2014
2015#[derive(Clone, Debug, PartialEq)]
2016#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
2017pub enum PrimitiveOperator {
2018 Equal,
2019 NotEqual,
2020 GreaterThan,
2021 GreaterThanOrEqual,
2022 LessThan,
2023 LessThanOrEqual,
2024}
2025
2026impl std::fmt::Display for PrimitiveOperator {
2027 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2028 let op_str = match self {
2029 PrimitiveOperator::Equal => "=",
2030 PrimitiveOperator::NotEqual => "≠",
2031 PrimitiveOperator::GreaterThan => ">",
2032 PrimitiveOperator::GreaterThanOrEqual => "≥",
2033 PrimitiveOperator::LessThan => "<",
2034 PrimitiveOperator::LessThanOrEqual => "≤",
2035 };
2036 write!(f, "{}", op_str)
2037 }
2038}
2039
2040impl TryFrom<chroma_proto::GenericComparator> for PrimitiveOperator {
2041 type Error = WhereConversionError;
2042
2043 fn try_from(value: chroma_proto::GenericComparator) -> Result<Self, Self::Error> {
2044 match value {
2045 chroma_proto::GenericComparator::Eq => Ok(Self::Equal),
2046 chroma_proto::GenericComparator::Ne => Ok(Self::NotEqual),
2047 chroma_proto::GenericComparator::ArrayContains
2048 | chroma_proto::GenericComparator::ArrayNotContains => {
2049 Err(WhereConversionError::cause(
2050 "ArrayContains/ArrayNotContains cannot be converted to PrimitiveOperator",
2051 ))
2052 }
2053 }
2054 }
2055}
2056
2057impl TryFrom<PrimitiveOperator> for chroma_proto::GenericComparator {
2058 type Error = WhereConversionError;
2059
2060 fn try_from(value: PrimitiveOperator) -> Result<Self, Self::Error> {
2061 match value {
2062 PrimitiveOperator::Equal => Ok(Self::Eq),
2063 PrimitiveOperator::NotEqual => Ok(Self::Ne),
2064 op => Err(WhereConversionError::cause(format!("{op:?} ∉ [=, ≠]"))),
2065 }
2066 }
2067}
2068
2069impl From<chroma_proto::NumberComparator> for PrimitiveOperator {
2070 fn from(value: chroma_proto::NumberComparator) -> Self {
2071 match value {
2072 chroma_proto::NumberComparator::Gt => Self::GreaterThan,
2073 chroma_proto::NumberComparator::Gte => Self::GreaterThanOrEqual,
2074 chroma_proto::NumberComparator::Lt => Self::LessThan,
2075 chroma_proto::NumberComparator::Lte => Self::LessThanOrEqual,
2076 }
2077 }
2078}
2079
2080impl TryFrom<PrimitiveOperator> for chroma_proto::NumberComparator {
2081 type Error = WhereConversionError;
2082
2083 fn try_from(value: PrimitiveOperator) -> Result<Self, Self::Error> {
2084 match value {
2085 PrimitiveOperator::GreaterThan => Ok(Self::Gt),
2086 PrimitiveOperator::GreaterThanOrEqual => Ok(Self::Gte),
2087 PrimitiveOperator::LessThan => Ok(Self::Lt),
2088 PrimitiveOperator::LessThanOrEqual => Ok(Self::Lte),
2089 op => Err(WhereConversionError::cause(format!(
2090 "{op:?} ∉ [≤, <, >, ≥]"
2091 ))),
2092 }
2093 }
2094}
2095
2096#[derive(Clone, Debug, PartialEq, Eq)]
2097#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
2098pub enum SetOperator {
2099 In,
2100 NotIn,
2101}
2102
2103impl std::fmt::Display for SetOperator {
2104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2105 let op_str = match self {
2106 SetOperator::In => "∈",
2107 SetOperator::NotIn => "∉",
2108 };
2109 write!(f, "{}", op_str)
2110 }
2111}
2112
2113impl From<chroma_proto::ListOperator> for SetOperator {
2114 fn from(value: chroma_proto::ListOperator) -> Self {
2115 match value {
2116 chroma_proto::ListOperator::In => Self::In,
2117 chroma_proto::ListOperator::Nin => Self::NotIn,
2118 }
2119 }
2120}
2121
2122impl From<SetOperator> for chroma_proto::ListOperator {
2123 fn from(value: SetOperator) -> Self {
2124 match value {
2125 SetOperator::In => Self::In,
2126 SetOperator::NotIn => Self::Nin,
2127 }
2128 }
2129}
2130
2131#[derive(Clone, Debug, PartialEq, Eq)]
2132#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
2133pub enum ContainsOperator {
2134 Contains,
2135 NotContains,
2136}
2137
2138impl std::fmt::Display for ContainsOperator {
2139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2140 let op_str = match self {
2141 ContainsOperator::Contains => "contains",
2142 ContainsOperator::NotContains => "not_contains",
2143 };
2144 write!(f, "{}", op_str)
2145 }
2146}
2147
2148impl From<ContainsOperator> for chroma_proto::GenericComparator {
2149 fn from(value: ContainsOperator) -> Self {
2150 match value {
2151 ContainsOperator::Contains => Self::ArrayContains,
2152 ContainsOperator::NotContains => Self::ArrayNotContains,
2153 }
2154 }
2155}
2156
2157#[derive(Clone, Debug, PartialEq)]
2158#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
2159pub enum MetadataSetValue {
2160 Bool(Vec<bool>),
2161 Int(Vec<i64>),
2162 Float(Vec<f64>),
2163 Str(Vec<String>),
2164}
2165
2166impl std::fmt::Display for MetadataSetValue {
2167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2168 match self {
2169 MetadataSetValue::Bool(values) => {
2170 let values_str = values
2171 .iter()
2172 .map(|v| format!("\"{}\"", v))
2173 .collect::<Vec<_>>()
2174 .join(", ");
2175 write!(f, "[{}]", values_str)
2176 }
2177 MetadataSetValue::Int(values) => {
2178 let values_str = values
2179 .iter()
2180 .map(|v| v.to_string())
2181 .collect::<Vec<_>>()
2182 .join(", ");
2183 write!(f, "[{}]", values_str)
2184 }
2185 MetadataSetValue::Float(values) => {
2186 let values_str = values
2187 .iter()
2188 .map(|v| v.to_string())
2189 .collect::<Vec<_>>()
2190 .join(", ");
2191 write!(f, "[{}]", values_str)
2192 }
2193 MetadataSetValue::Str(values) => {
2194 let values_str = values
2195 .iter()
2196 .map(|v| format!("\"{}\"", v))
2197 .collect::<Vec<_>>()
2198 .join(", ");
2199 write!(f, "[{}]", values_str)
2200 }
2201 }
2202 }
2203}
2204
2205impl MetadataSetValue {
2206 pub fn value_type(&self) -> MetadataValueType {
2207 match self {
2208 MetadataSetValue::Bool(_) => MetadataValueType::Bool,
2209 MetadataSetValue::Int(_) => MetadataValueType::Int,
2210 MetadataSetValue::Float(_) => MetadataValueType::Float,
2211 MetadataSetValue::Str(_) => MetadataValueType::Str,
2212 }
2213 }
2214}
2215
2216impl From<Vec<bool>> for MetadataSetValue {
2217 fn from(values: Vec<bool>) -> Self {
2218 MetadataSetValue::Bool(values)
2219 }
2220}
2221
2222impl From<Vec<i64>> for MetadataSetValue {
2223 fn from(values: Vec<i64>) -> Self {
2224 MetadataSetValue::Int(values)
2225 }
2226}
2227
2228impl From<Vec<i32>> for MetadataSetValue {
2229 fn from(values: Vec<i32>) -> Self {
2230 MetadataSetValue::Int(values.into_iter().map(|v| v as i64).collect())
2231 }
2232}
2233
2234impl From<Vec<f64>> for MetadataSetValue {
2235 fn from(values: Vec<f64>) -> Self {
2236 MetadataSetValue::Float(values)
2237 }
2238}
2239
2240impl From<Vec<f32>> for MetadataSetValue {
2241 fn from(values: Vec<f32>) -> Self {
2242 MetadataSetValue::Float(values.into_iter().map(|v| v as f64).collect())
2243 }
2244}
2245
2246impl From<Vec<String>> for MetadataSetValue {
2247 fn from(values: Vec<String>) -> Self {
2248 MetadataSetValue::Str(values)
2249 }
2250}
2251
2252impl From<Vec<&str>> for MetadataSetValue {
2253 fn from(values: Vec<&str>) -> Self {
2254 MetadataSetValue::Str(values.into_iter().map(|s| s.to_string()).collect())
2255 }
2256}
2257
2258impl TryFrom<chroma_proto::WhereDocument> for Where {
2260 type Error = WhereConversionError;
2261
2262 fn try_from(proto_document: chroma_proto::WhereDocument) -> Result<Self, Self::Error> {
2263 match proto_document.r#where_document {
2264 Some(chroma_proto::where_document::WhereDocument::Direct(proto_comparison)) => {
2265 let operator = match TryInto::<chroma_proto::WhereDocumentOperator>::try_into(
2266 proto_comparison.operator,
2267 ) {
2268 Ok(operator) => operator,
2269 Err(_) => {
2270 return Err(WhereConversionError::cause(
2271 "[Deprecated] Invalid where document operator",
2272 ))
2273 }
2274 };
2275 let comparison = DocumentExpression {
2276 pattern: proto_comparison.pattern,
2277 operator: operator.into(),
2278 };
2279 Ok(Where::Document(comparison))
2280 }
2281 Some(chroma_proto::where_document::WhereDocument::Children(proto_children)) => {
2282 let operator = match TryInto::<chroma_proto::BooleanOperator>::try_into(
2283 proto_children.operator,
2284 ) {
2285 Ok(operator) => operator,
2286 Err(_) => {
2287 return Err(WhereConversionError::cause(
2288 "[Deprecated] Invalid boolean operator",
2289 ))
2290 }
2291 };
2292 let children = CompositeExpression {
2293 children: proto_children
2294 .children
2295 .into_iter()
2296 .map(|child| child.try_into())
2297 .collect::<Result<_, _>>()?,
2298 operator: operator.into(),
2299 };
2300 Ok(Where::Composite(children))
2301 }
2302 None => Err(WhereConversionError::cause("[Deprecated] Invalid where")),
2303 }
2304 }
2305}
2306
2307#[cfg(test)]
2308mod tests {
2309 use crate::operator::Key;
2310
2311 use super::*;
2312
2313 #[cfg(feature = "pyo3")]
2315 fn ensure_python_interpreter() {
2316 static PYTHON_INIT: std::sync::Once = std::sync::Once::new();
2317 PYTHON_INIT.call_once(|| {
2318 pyo3::prepare_freethreaded_python();
2319 });
2320 }
2321
2322 #[test]
2323 fn test_update_metadata_try_from() {
2324 let mut proto_metadata = chroma_proto::UpdateMetadata {
2325 metadata: HashMap::new(),
2326 };
2327 proto_metadata.metadata.insert(
2328 "foo".to_string(),
2329 chroma_proto::UpdateMetadataValue {
2330 value: Some(chroma_proto::update_metadata_value::Value::IntValue(42)),
2331 },
2332 );
2333 proto_metadata.metadata.insert(
2334 "bar".to_string(),
2335 chroma_proto::UpdateMetadataValue {
2336 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(42.0)),
2337 },
2338 );
2339 proto_metadata.metadata.insert(
2340 "baz".to_string(),
2341 chroma_proto::UpdateMetadataValue {
2342 value: Some(chroma_proto::update_metadata_value::Value::StringValue(
2343 "42".to_string(),
2344 )),
2345 },
2346 );
2347 proto_metadata.metadata.insert(
2349 "sparse".to_string(),
2350 chroma_proto::UpdateMetadataValue {
2351 value: Some(
2352 chroma_proto::update_metadata_value::Value::SparseVectorValue(
2353 chroma_proto::SparseVector {
2354 indices: vec![0, 5, 10],
2355 values: vec![0.1, 0.5, 0.9],
2356 tokens: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
2357 },
2358 ),
2359 ),
2360 },
2361 );
2362 let converted_metadata: UpdateMetadata = proto_metadata.try_into().unwrap();
2363 assert_eq!(converted_metadata.len(), 4);
2364 assert_eq!(
2365 converted_metadata.get("foo").unwrap(),
2366 &UpdateMetadataValue::Int(42)
2367 );
2368 assert_eq!(
2369 converted_metadata.get("bar").unwrap(),
2370 &UpdateMetadataValue::Float(42.0)
2371 );
2372 assert_eq!(
2373 converted_metadata.get("baz").unwrap(),
2374 &UpdateMetadataValue::Str("42".to_string())
2375 );
2376 assert_eq!(
2377 converted_metadata.get("sparse").unwrap(),
2378 &UpdateMetadataValue::SparseVector(
2379 SparseVector::new_with_tokens(
2380 vec![0, 5, 10],
2381 vec![0.1, 0.5, 0.9],
2382 vec!["foo".to_string(), "bar".to_string(), "baz".to_string(),],
2383 )
2384 .unwrap()
2385 )
2386 );
2387 }
2388
2389 #[test]
2390 fn test_metadata_try_from() {
2391 let mut proto_metadata = chroma_proto::UpdateMetadata {
2392 metadata: HashMap::new(),
2393 };
2394 proto_metadata.metadata.insert(
2395 "foo".to_string(),
2396 chroma_proto::UpdateMetadataValue {
2397 value: Some(chroma_proto::update_metadata_value::Value::IntValue(42)),
2398 },
2399 );
2400 proto_metadata.metadata.insert(
2401 "bar".to_string(),
2402 chroma_proto::UpdateMetadataValue {
2403 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(42.0)),
2404 },
2405 );
2406 proto_metadata.metadata.insert(
2407 "baz".to_string(),
2408 chroma_proto::UpdateMetadataValue {
2409 value: Some(chroma_proto::update_metadata_value::Value::StringValue(
2410 "42".to_string(),
2411 )),
2412 },
2413 );
2414 proto_metadata.metadata.insert(
2416 "sparse".to_string(),
2417 chroma_proto::UpdateMetadataValue {
2418 value: Some(
2419 chroma_proto::update_metadata_value::Value::SparseVectorValue(
2420 chroma_proto::SparseVector {
2421 indices: vec![1, 10, 100],
2422 values: vec![0.2, 0.4, 0.6],
2423 tokens: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
2424 },
2425 ),
2426 ),
2427 },
2428 );
2429 let converted_metadata: Metadata = proto_metadata.try_into().unwrap();
2430 assert_eq!(converted_metadata.len(), 4);
2431 assert_eq!(
2432 converted_metadata.get("foo").unwrap(),
2433 &MetadataValue::Int(42)
2434 );
2435 assert_eq!(
2436 converted_metadata.get("bar").unwrap(),
2437 &MetadataValue::Float(42.0)
2438 );
2439 assert_eq!(
2440 converted_metadata.get("baz").unwrap(),
2441 &MetadataValue::Str("42".to_string())
2442 );
2443 assert_eq!(
2444 converted_metadata.get("sparse").unwrap(),
2445 &MetadataValue::SparseVector(
2446 SparseVector::new_with_tokens(
2447 vec![1, 10, 100],
2448 vec![0.2, 0.4, 0.6],
2449 vec!["foo".to_string(), "bar".to_string(), "baz".to_string(),],
2450 )
2451 .unwrap()
2452 )
2453 );
2454 }
2455
2456 #[test]
2457 fn test_where_clause_simple_from() {
2458 let proto_where = chroma_proto::Where {
2459 r#where: Some(chroma_proto::r#where::Where::DirectComparison(
2460 chroma_proto::DirectComparison {
2461 key: "foo".to_string(),
2462 comparison: Some(
2463 chroma_proto::direct_comparison::Comparison::SingleIntOperand(
2464 chroma_proto::SingleIntComparison {
2465 value: 42,
2466 comparator: Some(chroma_proto::single_int_comparison::Comparator::GenericComparator(chroma_proto::GenericComparator::Eq as i32)),
2467 },
2468 ),
2469 ),
2470 },
2471 )),
2472 };
2473 let where_clause: Where = proto_where.try_into().unwrap();
2474 match where_clause {
2475 Where::Metadata(comparison) => {
2476 assert_eq!(comparison.key, "foo");
2477 match comparison.comparison {
2478 MetadataComparison::Primitive(_, value) => {
2479 assert_eq!(value, MetadataValue::Int(42));
2480 }
2481 _ => panic!("Invalid comparison type"),
2482 }
2483 }
2484 _ => panic!("Invalid where type"),
2485 }
2486 }
2487
2488 #[test]
2489 fn test_where_clause_with_children() {
2490 let proto_where = chroma_proto::Where {
2491 r#where: Some(chroma_proto::r#where::Where::Children(
2492 chroma_proto::WhereChildren {
2493 children: vec![
2494 chroma_proto::Where {
2495 r#where: Some(chroma_proto::r#where::Where::DirectComparison(
2496 chroma_proto::DirectComparison {
2497 key: "foo".to_string(),
2498 comparison: Some(
2499 chroma_proto::direct_comparison::Comparison::SingleIntOperand(
2500 chroma_proto::SingleIntComparison {
2501 value: 42,
2502 comparator: Some(chroma_proto::single_int_comparison::Comparator::GenericComparator(chroma_proto::GenericComparator::Eq as i32)),
2503 },
2504 ),
2505 ),
2506 },
2507 )),
2508 },
2509 chroma_proto::Where {
2510 r#where: Some(chroma_proto::r#where::Where::DirectComparison(
2511 chroma_proto::DirectComparison {
2512 key: "bar".to_string(),
2513 comparison: Some(
2514 chroma_proto::direct_comparison::Comparison::SingleIntOperand(
2515 chroma_proto::SingleIntComparison {
2516 value: 42,
2517 comparator: Some(chroma_proto::single_int_comparison::Comparator::GenericComparator(chroma_proto::GenericComparator::Eq as i32)),
2518 },
2519 ),
2520 ),
2521 },
2522 )),
2523 },
2524 ],
2525 operator: chroma_proto::BooleanOperator::And.into(),
2526 },
2527 )),
2528 };
2529 let where_clause: Where = proto_where.try_into().unwrap();
2530 match where_clause {
2531 Where::Composite(children) => {
2532 assert_eq!(children.children.len(), 2);
2533 assert_eq!(children.operator, BooleanOperator::And);
2534 }
2535 _ => panic!("Invalid where type"),
2536 }
2537 }
2538
2539 #[test]
2540 fn test_where_document_simple() {
2541 let proto_where = chroma_proto::WhereDocument {
2542 r#where_document: Some(chroma_proto::where_document::WhereDocument::Direct(
2543 chroma_proto::DirectWhereDocument {
2544 pattern: "foo".to_string(),
2545 operator: chroma_proto::WhereDocumentOperator::Contains.into(),
2546 },
2547 )),
2548 };
2549 let where_document: Where = proto_where.try_into().unwrap();
2550 match where_document {
2551 Where::Document(comparison) => {
2552 assert_eq!(comparison.pattern, "foo");
2553 assert_eq!(comparison.operator, DocumentOperator::Contains);
2554 }
2555 _ => panic!("Invalid where document type"),
2556 }
2557 }
2558
2559 #[test]
2560 fn test_where_document_with_children() {
2561 let proto_where = chroma_proto::WhereDocument {
2562 r#where_document: Some(chroma_proto::where_document::WhereDocument::Children(
2563 chroma_proto::WhereDocumentChildren {
2564 children: vec![
2565 chroma_proto::WhereDocument {
2566 r#where_document: Some(
2567 chroma_proto::where_document::WhereDocument::Direct(
2568 chroma_proto::DirectWhereDocument {
2569 pattern: "foo".to_string(),
2570 operator: chroma_proto::WhereDocumentOperator::Contains
2571 .into(),
2572 },
2573 ),
2574 ),
2575 },
2576 chroma_proto::WhereDocument {
2577 r#where_document: Some(
2578 chroma_proto::where_document::WhereDocument::Direct(
2579 chroma_proto::DirectWhereDocument {
2580 pattern: "bar".to_string(),
2581 operator: chroma_proto::WhereDocumentOperator::Contains
2582 .into(),
2583 },
2584 ),
2585 ),
2586 },
2587 ],
2588 operator: chroma_proto::BooleanOperator::And.into(),
2589 },
2590 )),
2591 };
2592 let where_document: Where = proto_where.try_into().unwrap();
2593 match where_document {
2594 Where::Composite(children) => {
2595 assert_eq!(children.children.len(), 2);
2596 assert_eq!(children.operator, BooleanOperator::And);
2597 }
2598 _ => panic!("Invalid where document type"),
2599 }
2600 }
2601
2602 #[test]
2603 fn test_sparse_vector_new() {
2604 let indices = vec![0, 5, 10];
2605 let values = vec![0.1, 0.5, 0.9];
2606 let sparse = SparseVector::new(indices.clone(), values.clone()).unwrap();
2607 assert_eq!(sparse.indices, indices);
2608 assert_eq!(sparse.values, values);
2609 }
2610
2611 #[test]
2612 fn test_sparse_vector_from_pairs() {
2613 let pairs = vec![(0, 0.1), (5, 0.5), (10, 0.9)];
2614 let sparse = SparseVector::from_pairs(pairs.clone());
2615 assert_eq!(sparse.indices, vec![0, 5, 10]);
2616 assert_eq!(sparse.values, vec![0.1, 0.5, 0.9]);
2617 }
2618
2619 #[test]
2620 fn test_sparse_vector_from_triples() {
2621 let triples = vec![
2622 ("foo".to_string(), 0, 0.1),
2623 ("bar".to_string(), 5, 0.5),
2624 ("baz".to_string(), 10, 0.9),
2625 ];
2626 let sparse = SparseVector::from_triples(triples.clone());
2627 assert_eq!(sparse.indices, vec![0, 5, 10]);
2628 assert_eq!(sparse.values, vec![0.1, 0.5, 0.9]);
2629 }
2630
2631 #[test]
2632 fn test_sparse_vector_iter() {
2633 let sparse = SparseVector::new(vec![0, 5, 10], vec![0.1, 0.5, 0.9]).unwrap();
2634 let collected: Vec<(u32, f32)> = sparse.iter().collect();
2635 assert_eq!(collected, vec![(0, 0.1), (5, 0.5), (10, 0.9)]);
2636 }
2637
2638 #[test]
2639 fn test_sparse_vector_ordering() {
2640 let sparse1 = SparseVector::new(vec![0, 5], vec![0.1, 0.5]).unwrap();
2641 let sparse2 = SparseVector::new(vec![0, 5], vec![0.1, 0.5]).unwrap();
2642 let sparse3 = SparseVector::new(vec![0, 6], vec![0.1, 0.5]).unwrap();
2643 let sparse4 = SparseVector::new(vec![0, 5], vec![0.1, 0.6]).unwrap();
2644
2645 assert_eq!(sparse1, sparse2);
2646 assert!(sparse1 < sparse3);
2647 assert!(sparse1 < sparse4);
2648 }
2649
2650 #[test]
2651 fn test_sparse_vector_proto_conversion() {
2652 let tokens = vec![
2653 "token1".to_string(),
2654 "token2".to_string(),
2655 "token3".to_string(),
2656 ];
2657 let sparse =
2658 SparseVector::new_with_tokens(vec![1, 10, 100], vec![0.2, 0.4, 0.6], tokens.clone())
2659 .unwrap();
2660 let proto: chroma_proto::SparseVector = sparse.clone().into();
2661 assert_eq!(proto.indices, vec![1, 10, 100]);
2662 assert_eq!(proto.values, vec![0.2, 0.4, 0.6]);
2663 assert_eq!(proto.tokens, tokens.clone());
2664
2665 let converted: SparseVector = proto.try_into().unwrap();
2666 assert_eq!(converted, sparse);
2667 assert_eq!(converted.tokens, Some(tokens));
2668 }
2669
2670 #[test]
2671 fn test_sparse_vector_proto_conversion_empty_tokens() {
2672 let sparse = SparseVector::new(vec![0, 5, 10], vec![0.1, 0.5, 0.9]).unwrap();
2673 let proto: chroma_proto::SparseVector = sparse.clone().into();
2674 assert_eq!(proto.indices, vec![0, 5, 10]);
2675 assert_eq!(proto.values, vec![0.1, 0.5, 0.9]);
2676 assert_eq!(proto.tokens, Vec::<String>::new());
2677
2678 let converted: SparseVector = proto.try_into().unwrap();
2679 assert_eq!(converted, sparse);
2680 assert_eq!(converted.tokens, None);
2681 }
2682
2683 #[test]
2684 fn test_sparse_vector_logical_size() {
2685 let metadata = Metadata::from([(
2686 "sparse".to_string(),
2687 MetadataValue::SparseVector(
2688 SparseVector::new(vec![0, 1, 2, 3, 4], vec![0.1, 0.2, 0.3, 0.4, 0.5]).unwrap(),
2689 ),
2690 )]);
2691
2692 let size = logical_size_of_metadata(&metadata);
2693 assert_eq!(size, 46);
2696 }
2697
2698 #[test]
2699 fn test_sparse_vector_validation() {
2700 let sparse = SparseVector::new(vec![1, 2, 3], vec![0.1, 0.2, 0.3]).unwrap();
2702 assert!(sparse.validate().is_ok());
2703
2704 let sparse = SparseVector::new(vec![1, 2, 3], vec![0.1, 0.2]);
2706 assert!(sparse.is_err());
2707 let result = SparseVector::new(vec![1, 2, 3], vec![0.1, 0.2, 0.3])
2708 .unwrap()
2709 .validate();
2710 assert!(result.is_ok());
2711
2712 let sparse = SparseVector::new_with_tokens(
2714 vec![1, 2, 3],
2715 vec![0.1, 0.2, 0.3],
2716 vec!["a".to_string(), "b".to_string()],
2717 );
2718 assert!(sparse.is_err());
2719
2720 let sparse = SparseVector::new(vec![3, 1, 2], vec![0.3, 0.1, 0.2]).unwrap();
2722 let result = sparse.validate();
2723 assert!(result.is_err());
2724 assert!(matches!(
2725 result.unwrap_err(),
2726 MetadataValueConversionError::SparseVectorIndicesNotSorted
2727 ));
2728
2729 let sparse = SparseVector::new(vec![1, 2, 2, 3], vec![0.1, 0.2, 0.3, 0.4]).unwrap();
2731 let result = sparse.validate();
2732 assert!(result.is_err());
2733 assert!(matches!(
2734 result.unwrap_err(),
2735 MetadataValueConversionError::SparseVectorIndicesNotSorted
2736 ));
2737
2738 let sparse = SparseVector::new(vec![1, 3, 2], vec![0.1, 0.3, 0.2]).unwrap();
2740 let result = sparse.validate();
2741 assert!(result.is_err());
2742 assert!(matches!(
2743 result.unwrap_err(),
2744 MetadataValueConversionError::SparseVectorIndicesNotSorted
2745 ));
2746 }
2747
2748 #[test]
2749 fn test_sparse_vector_deserialize_old_format() {
2750 let json = r#"{"indices": [0, 1, 2], "values": [1.0, 2.0, 3.0]}"#;
2752 let sv: SparseVector = serde_json::from_str(json).unwrap();
2753 assert_eq!(sv.indices, vec![0, 1, 2]);
2754 assert_eq!(sv.values, vec![1.0, 2.0, 3.0]);
2755 }
2756
2757 #[test]
2758 fn test_sparse_vector_deserialize_new_format() {
2759 let json =
2761 "{\"#type\": \"sparse_vector\", \"indices\": [0, 1, 2], \"values\": [1.0, 2.0, 3.0]}";
2762 let sv: SparseVector = serde_json::from_str(json).unwrap();
2763 assert_eq!(sv.indices, vec![0, 1, 2]);
2764 assert_eq!(sv.values, vec![1.0, 2.0, 3.0]);
2765 }
2766
2767 #[test]
2768 fn test_sparse_vector_deserialize_new_format_field_order() {
2769 let json = "{\"indices\": [5, 10], \"#type\": \"sparse_vector\", \"values\": [0.5, 1.0]}";
2771 let sv: SparseVector = serde_json::from_str(json).unwrap();
2772 assert_eq!(sv.indices, vec![5, 10]);
2773 assert_eq!(sv.values, vec![0.5, 1.0]);
2774 }
2775
2776 #[test]
2777 fn test_sparse_vector_deserialize_wrong_type_tag() {
2778 let json = "{\"#type\": \"dense_vector\", \"indices\": [0, 1], \"values\": [1.0, 2.0]}";
2780 let result: Result<SparseVector, _> = serde_json::from_str(json);
2781 assert!(result.is_err());
2782 let err_msg = result.unwrap_err().to_string();
2783 assert!(err_msg.contains("sparse_vector"));
2784 }
2785
2786 #[test]
2787 fn test_sparse_vector_serialize_always_has_type() {
2788 let sv = SparseVector::new(vec![0, 1, 2], vec![1.0, 2.0, 3.0]).unwrap();
2790 let json = serde_json::to_value(&sv).unwrap();
2791
2792 assert_eq!(json["#type"], "sparse_vector");
2793 assert_eq!(json["indices"], serde_json::json!([0, 1, 2]));
2794 assert_eq!(json["values"], serde_json::json!([1.0, 2.0, 3.0]));
2795 }
2796
2797 #[test]
2798 fn test_sparse_vector_roundtrip_with_type() {
2799 let original = SparseVector::new(vec![0, 5, 10, 15], vec![0.1, 0.5, 1.0, 1.5]).unwrap();
2801 let json = serde_json::to_string(&original).unwrap();
2802
2803 assert!(json.contains("\"#type\":\"sparse_vector\""));
2805
2806 let deserialized: SparseVector = serde_json::from_str(&json).unwrap();
2807 assert_eq!(original, deserialized);
2808 }
2809
2810 #[test]
2811 fn test_sparse_vector_in_metadata_old_format() {
2812 let json = r#"{"key": "value", "sparse": {"indices": [0, 1], "values": [1.0, 2.0]}}"#;
2814 let map: HashMap<String, serde_json::Value> = serde_json::from_str(json).unwrap();
2815
2816 let sparse_value = &map["sparse"];
2817 let sv: SparseVector = serde_json::from_value(sparse_value.clone()).unwrap();
2818 assert_eq!(sv.indices, vec![0, 1]);
2819 assert_eq!(sv.values, vec![1.0, 2.0]);
2820 }
2821
2822 #[test]
2823 fn test_sparse_vector_in_metadata_new_format() {
2824 let json = "{\"key\": \"value\", \"sparse\": {\"#type\": \"sparse_vector\", \"indices\": [0, 1], \"values\": [1.0, 2.0]}}";
2826 let map: HashMap<String, serde_json::Value> = serde_json::from_str(json).unwrap();
2827
2828 let sparse_value = &map["sparse"];
2829 let sv: SparseVector = serde_json::from_value(sparse_value.clone()).unwrap();
2830 assert_eq!(sv.indices, vec![0, 1]);
2831 assert_eq!(sv.values, vec![1.0, 2.0]);
2832 }
2833
2834 #[test]
2835 fn test_sparse_vector_tokens_roundtrip_old_to_new() {
2836 let json = r#"{"indices": [0, 1, 2], "values": [1.0, 2.0, 3.0]}"#;
2838 let sv: SparseVector = serde_json::from_str(json).unwrap();
2839 assert_eq!(sv.indices, vec![0, 1, 2]);
2840 assert_eq!(sv.values, vec![1.0, 2.0, 3.0]);
2841 assert_eq!(sv.tokens, None);
2842
2843 let serialized = serde_json::to_value(&sv).unwrap();
2845 assert_eq!(serialized["#type"], "sparse_vector");
2846 assert_eq!(serialized["indices"], serde_json::json!([0, 1, 2]));
2847 assert_eq!(serialized["values"], serde_json::json!([1.0, 2.0, 3.0]));
2848 assert_eq!(serialized["tokens"], serde_json::Value::Null);
2849 }
2850
2851 #[test]
2852 fn test_sparse_vector_tokens_roundtrip_new_to_new() {
2853 let sv_with_tokens = SparseVector::new_with_tokens(
2855 vec![0, 1, 2],
2856 vec![1.0, 2.0, 3.0],
2857 vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
2858 )
2859 .unwrap();
2860
2861 let serialized = serde_json::to_string(&sv_with_tokens).unwrap();
2863 assert!(serialized.contains("\"#type\":\"sparse_vector\""));
2864 assert!(serialized.contains("\"tokens\""));
2865
2866 let deserialized: SparseVector = serde_json::from_str(&serialized).unwrap();
2868 assert_eq!(deserialized.indices, vec![0, 1, 2]);
2869 assert_eq!(deserialized.values, vec![1.0, 2.0, 3.0]);
2870 assert_eq!(
2871 deserialized.tokens,
2872 Some(vec![
2873 "foo".to_string(),
2874 "bar".to_string(),
2875 "baz".to_string()
2876 ])
2877 );
2878 }
2879
2880 #[test]
2881 fn test_sparse_vector_tokens_deserialize_with_tokens_field() {
2882 let json = r##"{"#type": "sparse_vector", "indices": [5, 10], "values": [0.5, 1.0], "tokens": ["token1", "token2"]}"##;
2884 let sv: SparseVector = serde_json::from_str(json).unwrap();
2885 assert_eq!(sv.indices, vec![5, 10]);
2886 assert_eq!(sv.values, vec![0.5, 1.0]);
2887 assert_eq!(
2888 sv.tokens,
2889 Some(vec!["token1".to_string(), "token2".to_string()])
2890 );
2891 }
2892
2893 #[test]
2894 fn test_sparse_vector_tokens_backward_compatibility() {
2895 let old_json = r#"{"indices": [1, 2], "values": [0.1, 0.2]}"#;
2897 let old_sv: SparseVector = serde_json::from_str(old_json).unwrap();
2898
2899 let new_json = r##"{"#type": "sparse_vector", "indices": [1, 2], "values": [0.1, 0.2], "tokens": ["a", "b"]}"##;
2901 let new_sv: SparseVector = serde_json::from_str(new_json).unwrap();
2902
2903 assert_eq!(old_sv.indices, new_sv.indices);
2905 assert_eq!(old_sv.values, new_sv.values);
2906
2907 assert_eq!(old_sv.tokens, None);
2909 assert_eq!(new_sv.tokens, Some(vec!["a".to_string(), "b".to_string()]));
2910 }
2911
2912 #[test]
2913 fn test_sparse_vector_from_triples_preserves_tokens() {
2914 let triples = vec![
2915 ("apple".to_string(), 10, 0.5),
2916 ("banana".to_string(), 20, 0.7),
2917 ("cherry".to_string(), 30, 0.9),
2918 ];
2919 let sv = SparseVector::from_triples(triples.clone());
2920
2921 assert_eq!(sv.indices, vec![10, 20, 30]);
2922 assert_eq!(sv.values, vec![0.5, 0.7, 0.9]);
2923 assert_eq!(
2924 sv.tokens,
2925 Some(vec![
2926 "apple".to_string(),
2927 "banana".to_string(),
2928 "cherry".to_string()
2929 ])
2930 );
2931
2932 let serialized = serde_json::to_string(&sv).unwrap();
2934 let deserialized: SparseVector = serde_json::from_str(&serialized).unwrap();
2935
2936 assert_eq!(deserialized.indices, sv.indices);
2937 assert_eq!(deserialized.values, sv.values);
2938 assert_eq!(deserialized.tokens, sv.tokens);
2939 }
2940
2941 #[cfg(feature = "pyo3")]
2942 #[test]
2943 fn test_sparse_vector_pyo3_roundtrip_with_tokens() {
2944 ensure_python_interpreter();
2945
2946 pyo3::Python::with_gil(|py| {
2947 use pyo3::types::PyDict;
2948 use pyo3::IntoPyObject;
2949
2950 let dict_in = PyDict::new(py);
2951 dict_in.set_item("indices", vec![0u32, 1, 2]).unwrap();
2952 dict_in
2953 .set_item("values", vec![0.1f32, 0.2f32, 0.3f32])
2954 .unwrap();
2955 dict_in
2956 .set_item("tokens", vec!["foo", "bar", "baz"])
2957 .unwrap();
2958
2959 let sparse: SparseVector = dict_in.clone().into_any().extract().unwrap();
2960 assert_eq!(sparse.indices, vec![0, 1, 2]);
2961 assert_eq!(sparse.values, vec![0.1, 0.2, 0.3]);
2962 assert_eq!(
2963 sparse.tokens,
2964 Some(vec![
2965 "foo".to_string(),
2966 "bar".to_string(),
2967 "baz".to_string()
2968 ])
2969 );
2970
2971 let py_obj = sparse.clone().into_pyobject(py).unwrap();
2972 let dict_out = py_obj.downcast::<PyDict>().unwrap();
2973 let tokens_obj = dict_out.get_item("tokens").unwrap();
2974 let tokens: Vec<String> = tokens_obj
2975 .expect("expected tokens key in Python dict")
2976 .extract()
2977 .unwrap();
2978 assert_eq!(
2979 tokens,
2980 vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]
2981 );
2982 });
2983 }
2984
2985 #[cfg(feature = "pyo3")]
2986 #[test]
2987 fn test_sparse_vector_pyo3_roundtrip_without_tokens() {
2988 ensure_python_interpreter();
2989
2990 pyo3::Python::with_gil(|py| {
2991 use pyo3::types::PyDict;
2992 use pyo3::IntoPyObject;
2993
2994 let dict_in = PyDict::new(py);
2995 dict_in.set_item("indices", vec![5u32]).unwrap();
2996 dict_in.set_item("values", vec![1.5f32]).unwrap();
2997
2998 let sparse: SparseVector = dict_in.clone().into_any().extract().unwrap();
2999 assert_eq!(sparse.indices, vec![5]);
3000 assert_eq!(sparse.values, vec![1.5]);
3001 assert!(sparse.tokens.is_none());
3002
3003 let py_obj = sparse.into_pyobject(py).unwrap();
3004 let dict_out = py_obj.downcast::<PyDict>().unwrap();
3005 let tokens_obj = dict_out.get_item("tokens").unwrap();
3006 let tokens_value = tokens_obj.expect("expected tokens key in Python dict");
3007 assert!(
3008 tokens_value.is_none(),
3009 "expected tokens value in Python dict to be None"
3010 );
3011 });
3012 }
3013
3014 #[test]
3015 fn test_simplifies_identities() {
3016 let all: Where = true.into();
3017 assert_eq!(all.clone() & all.clone(), true.into());
3018 assert_eq!(all.clone() | all.clone(), true.into());
3019
3020 let foo = Key::field("foo").eq("bar");
3021 assert_eq!(foo.clone() & all.clone(), foo.clone());
3022 assert_eq!(all.clone() & foo.clone(), foo.clone());
3023
3024 let none: Where = false.into();
3025 assert_eq!(foo.clone() | none.clone(), foo.clone());
3026 assert_eq!(none | foo.clone(), foo);
3027 }
3028
3029 #[test]
3030 fn test_flattens() {
3031 let foo = Key::field("foo").eq("bar");
3032 let baz = Key::field("baz").eq("quux");
3033
3034 let and_nested = foo.clone() & (baz.clone() & foo.clone());
3035 assert_eq!(
3036 and_nested,
3037 Where::Composite(CompositeExpression {
3038 operator: BooleanOperator::And,
3039 children: vec![foo.clone(), baz.clone(), foo.clone()]
3040 })
3041 );
3042
3043 let or_nested = foo.clone() | (baz.clone() | foo.clone());
3044 assert_eq!(
3045 or_nested,
3046 Where::Composite(CompositeExpression {
3047 operator: BooleanOperator::Or,
3048 children: vec![foo.clone(), baz.clone(), foo.clone()]
3049 })
3050 );
3051 }
3052
3053 #[test]
3054 fn test_reject_nan_metadata_float_via_grpc() {
3055 for bad_value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
3056 let proto = chroma_proto::UpdateMetadataValue {
3057 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(
3058 bad_value,
3059 )),
3060 };
3061
3062 let result = UpdateMetadataValue::try_from(&proto);
3063 assert!(
3064 result.is_err(),
3065 "should reject {bad_value} in UpdateMetadataValue"
3066 );
3067
3068 let result = MetadataValue::try_from(&proto);
3069 assert!(
3070 result.is_err(),
3071 "should reject {bad_value} in MetadataValue"
3072 );
3073 }
3074
3075 let proto = chroma_proto::UpdateMetadataValue {
3077 value: Some(chroma_proto::update_metadata_value::Value::FloatValue(1.5)),
3078 };
3079 assert!(UpdateMetadataValue::try_from(&proto).is_ok());
3080 assert!(MetadataValue::try_from(&proto).is_ok());
3081 }
3082
3083 #[test]
3084 fn test_reject_nan_metadata_float_array_via_grpc() {
3085 for bad_value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
3086 let proto = chroma_proto::UpdateMetadataValue {
3087 value: Some(chroma_proto::update_metadata_value::Value::DoubleListValue(
3088 chroma_proto::DoubleListValue {
3089 values: vec![1.0, bad_value, 3.0],
3090 },
3091 )),
3092 };
3093
3094 let result = UpdateMetadataValue::try_from(&proto);
3095 assert!(
3096 result.is_err(),
3097 "should reject {bad_value} in UpdateMetadataValue float array"
3098 );
3099
3100 let result = MetadataValue::try_from(&proto);
3101 assert!(
3102 result.is_err(),
3103 "should reject {bad_value} in MetadataValue float array"
3104 );
3105 }
3106
3107 let proto = chroma_proto::UpdateMetadataValue {
3109 value: Some(chroma_proto::update_metadata_value::Value::DoubleListValue(
3110 chroma_proto::DoubleListValue {
3111 values: vec![1.0, 2.0, 3.0],
3112 },
3113 )),
3114 };
3115 assert!(UpdateMetadataValue::try_from(&proto).is_ok());
3116 assert!(MetadataValue::try_from(&proto).is_ok());
3117 }
3118}