Repository: qdrant/qdrant
File: lib/segment/src/types.rs (Rust)

Code before:
    {
        if deserializer.is_human_readable() {
            let value = serde_json::Value::deserialize(deserializer)?;
            let Some(obj) = value.as_object() else {
                return serde_json::from_value::<ConditionUntagged>(value)
                    .map(Condition::from)
                    .map_err(serde::de::Error::custom);
            };

            // IMPORTANT: avoid untagged swallowing datetime parse error
            if obj.contains_key("key") {
                return serde_json::from_value::<FieldCondition>(value)
                    .map(Condition::Field)
                    .map_err(serde::de::Error::custom);
            }

            if obj.contains_key("is_empty") {
                return serde_json::from_value::<IsEmptyCondition>(value)
                    .map(Condition::IsEmpty)
                    .map_err(serde::de::Error::custom);
            }

            if obj.contains_key("is_null") {
                return serde_json::from_value::<IsNullCondition>(value)
                    .map(Condition::IsNull)
                    .map_err(serde::de::Error::custom);
            }

            if obj.contains_key("has_id") {
                return serde_json::from_value::<HasIdCondition>(value)
                    .map(Condition::HasId)
                    .map_err(serde::de::Error::custom);
            }

            if obj.contains_key("has_vector") {
                return serde_json::from_value::<HasVectorCondition>(value)
                    .map(Condition::HasVector)
                    .map_err(serde::de::Error::custom);
            }

            if obj.contains_key("nested") {
                return serde_json::from_value::<NestedCondition>(value)
                    .map(Condition::Nested)
                    .map_err(serde::de::Error::custom);
            }

            serde_json::from_value::<ConditionUntagged>(value)
                .map(Condition::from)
                .map_err(serde::de::Error::custom)
        } else {
            ConditionUntagged::deserialize(deserializer).map(Condition::from)

Review comment (suggestion):
Do you think there's any way to eliminate this part?

It seems to contain a lot of boiler plate. It's also easy to forget changes here when more conditions are added because the compiler won't tell us so.

Code after:
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        if deserializer.is_human_readable() {
            let value = serde_json::Value::deserialize(deserializer)?;

            // Special case: FieldCondition first to surface datetime parse errors.
            // Untagged enum would swallow these errors with generic message.
            if let Some(obj) = value.as_object()
                && obj.contains_key("key")
            {
                return serde_json::from_value::<FieldCondition>(value)
                    .map(Condition::Field)
                    .map_err(serde::de::Error::custom);
            }

            // All other variants handled by ConditionUntagged (compiler-safe)
            serde_json::from_value::<ConditionUntagged>(value)
                .map(Condition::from)
                .map_err(serde::de::Error::custom)
        } else {
            ConditionUntagged::deserialize(deserializer).map(Condition::from)
        }
    }
}

impl Condition {
    pub fn new_custom(checker: Arc<dyn CustomIdCheckerCondition + Send + Sync + 'static>) -> Self {
        Condition::CustomIdChecker(CustomIdChecker(checker))
    }
}

#[derive(Debug, Clone)]
pub struct CustomIdChecker(pub Arc<dyn CustomIdCheckerCondition + Send + Sync + 'static>);

impl Hash for CustomIdChecker {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        // We cannot hash the inner function
        // This means that two different CustomIdChecker conditions will have the same hash,
        // but that's acceptable since we cannot do better, and only expected to be used
        // for logging and profiling purposes.
        std::ptr::hash(Arc::as_ptr(&self.0), state);
    }
}

impl PartialEq for CustomIdChecker {
    fn eq(&self, other: &Self) -> bool {
        // We cannot compare the inner function
        // This means that two different CustomIdChecker conditions will never be equal,
        // but that's acceptable since we cannot do better, and only expected to be used