Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions rust/types/src/execution/operator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use serde::{de::Error, Deserialize, Deserializer, Serialize};
use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use std::{
cmp::Ordering,
Expand Down Expand Up @@ -124,14 +124,57 @@ pub struct FetchLog {
/// # Parameters
/// - `query_ids`: The user provided ids, which specifies the domain of the filter if provided
/// - `where_clause`: The predicate on individual record
#[derive(Clone, Debug, Default, Serialize)]
#[derive(Clone, Debug, Default)]
pub struct Filter {
#[serde(default)]
pub query_ids: Option<Vec<String>>,
#[serde(default)]
pub where_clause: Option<Where>,
}

impl Serialize for Filter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// For the search API, serialize directly as the where clause (or empty object if None)
// If query_ids are present, they should be combined with the where_clause as Key::ID.is_in([...])

match (&self.query_ids, &self.where_clause) {
(None, None) => {
// No filter at all - serialize empty object
let map = serializer.serialize_map(Some(0))?;
map.end()
}
(None, Some(where_clause)) => {
// Only where clause - serialize it directly
where_clause.serialize(serializer)
}
(Some(ids), None) => {
// Only query_ids - create Where clause: Key::ID.is_in(ids)
let id_where = Where::Metadata(MetadataExpression {
key: "#id".to_string(),
comparison: MetadataComparison::Set(
SetOperator::In,
MetadataSetValue::Str(ids.clone()),
),
});
id_where.serialize(serializer)
}
(Some(ids), Some(where_clause)) => {
// Both present - combine with AND: Key::ID.is_in(ids) & where_clause
let id_where = Where::Metadata(MetadataExpression {
key: "#id".to_string(),
comparison: MetadataComparison::Set(
SetOperator::In,
MetadataSetValue::Str(ids.clone()),
),
});
let combined = Where::conjunction(vec![id_where, where_clause.clone()]);
combined.serialize(serializer)
}
}
}
}

impl<'de> Deserialize<'de> for Filter {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand Down
69 changes: 66 additions & 3 deletions rust/types/src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chroma_error::{ChromaError, ErrorCodes};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{Number, Value};
use sprs::CsVec;
use std::{
Expand Down Expand Up @@ -873,11 +873,74 @@ pub enum Where {
}

impl serde::Serialize for Where {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
todo!()
match self {
Where::Composite(composite) => {
let mut map = serializer.serialize_map(Some(1))?;
let op_key = match composite.operator {
BooleanOperator::And => "$and",
BooleanOperator::Or => "$or",
};
map.serialize_entry(op_key, &composite.children)?;
map.end()
}
Where::Document(doc) => {
let mut outer_map = serializer.serialize_map(Some(1))?;
let mut inner_map = serde_json::Map::new();
let op_key = match doc.operator {
DocumentOperator::Contains => "$contains",
DocumentOperator::NotContains => "$not_contains",
DocumentOperator::Regex => "$regex",
DocumentOperator::NotRegex => "$not_regex",
};
inner_map.insert(
op_key.to_string(),
serde_json::Value::String(doc.pattern.clone()),
);
outer_map.serialize_entry("#document", &inner_map)?;
outer_map.end()
}
Where::Metadata(meta) => {
let mut outer_map = serializer.serialize_map(Some(1))?;
let mut inner_map = serde_json::Map::new();

match &meta.comparison {
MetadataComparison::Primitive(op, value) => {
let op_key = match op {
PrimitiveOperator::Equal => "$eq",
PrimitiveOperator::NotEqual => "$ne",
PrimitiveOperator::GreaterThan => "$gt",
PrimitiveOperator::GreaterThanOrEqual => "$gte",
PrimitiveOperator::LessThan => "$lt",
PrimitiveOperator::LessThanOrEqual => "$lte",
};
let value_json =
serde_json::to_value(value).map_err(serde::ser::Error::custom)?;
inner_map.insert(op_key.to_string(), value_json);
}
MetadataComparison::Set(op, set_value) => {
let op_key = match op {
SetOperator::In => "$in",
SetOperator::NotIn => "$nin",
};
let values_json = match set_value {
MetadataSetValue::Bool(v) => serde_json::to_value(v),
MetadataSetValue::Int(v) => serde_json::to_value(v),
MetadataSetValue::Float(v) => serde_json::to_value(v),
MetadataSetValue::Str(v) => serde_json::to_value(v),
}
.map_err(serde::ser::Error::custom)?;
inner_map.insert(op_key.to_string(), values_json);
Comment on lines +929 to +936
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BestPractice]

This match statement can be simplified using serde's derive macros. If you add #[derive(Serialize)] and #[serde(untagged)] to the MetadataSetValue enum definition, you can serialize it directly, making the code more concise and idiomatic.

First, modify the MetadataSetValue enum definition:

#[derive(Clone, Debug, PartialEq, Serialize)]
#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
#[serde(untagged)]
pub enum MetadataSetValue {
    Bool(Vec<bool>),
    Int(Vec<i64>),
    Float(Vec<f64>),
    Str(Vec<String>),
}

Then you can simplify this block:

Suggested change
let values_json = match set_value {
MetadataSetValue::Bool(v) => serde_json::to_value(v),
MetadataSetValue::Int(v) => serde_json::to_value(v),
MetadataSetValue::Float(v) => serde_json::to_value(v),
MetadataSetValue::Str(v) => serde_json::to_value(v),
}
.map_err(serde::ser::Error::custom)?;
inner_map.insert(op_key.to_string(), values_json);
let values_json =
serde_json::to_value(set_value).map_err(serde::ser::Error::custom)?;

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
[**BestPractice**]

This `match` statement can be simplified using serde's derive macros. If you add `#[derive(Serialize)]` and `#[serde(untagged)]` to the `MetadataSetValue` enum definition, you can serialize it directly, making the code more concise and idiomatic.

First, modify the `MetadataSetValue` enum definition:
```rust
#[derive(Clone, Debug, PartialEq, Serialize)]
#[cfg_attr(feature = "testing", derive(proptest_derive::Arbitrary))]
#[serde(untagged)]
pub enum MetadataSetValue {
    Bool(Vec<bool>),
    Int(Vec<i64>),
    Float(Vec<f64>),
    Str(Vec<String>),
}
```

Then you can simplify this block:

```suggestion
                        let values_json =
                            serde_json::to_value(set_value).map_err(serde::ser::Error::custom)?;
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

File: rust/types/src/metadata.rs
Line: 936

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could work, but this is fine for now

}
}

outer_map.serialize_entry(&meta.key, &inner_map)?;
outer_map.end()
}
}
}
}

Expand Down
Loading