scout_rs 0.95.95

A Rust client for the synchornizing state with the Scout database
Documentation
// Serde helpers for model fields that may come from the API in multiple formats.

use serde::de::Error as _;
use serde::{Deserialize, Deserializer, Serialize};

/// Sorted, comma-separated JSON object keys after serialization (groups PostgREST bulk rows that share the same columns).
pub fn serialized_object_key_set<T: Serialize>(value: &T) -> Result<String, serde_json::Error> {
    let v = serde_json::to_value(value)?;
    let obj = v.as_object().ok_or_else(|| {
        serde_json::Error::custom("serialized_object_key_set: expected a JSON object")
    })?;
    let mut keys: Vec<&str> = obj.keys().map(String::as_str).collect();
    keys.sort_unstable();
    Ok(keys.join(","))
}

/// Deserializes an optional embedding from either a JSON array of floats or a pgvector-style string "[0.1, 0.2, ...]".
pub fn deserialize_embedding<'de, D>(deserializer: D) -> Result<Option<Vec<f32>>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum EmbeddingFormat {
        Array(Vec<f32>),
        String(String),
    }

    let value = Option::<EmbeddingFormat>::deserialize(deserializer)?;
    match value {
        None => Ok(None),
        Some(EmbeddingFormat::Array(v)) => Ok(Some(v)),
        Some(EmbeddingFormat::String(s)) => {
            let s = s.trim();
            if s.is_empty() || s == "[]" {
                return Ok(None);
            }
            let s = s.trim_start_matches('[').trim_end_matches(']');
            let vec: Result<Vec<f32>, _> = s.split(',').map(|x| x.trim().parse::<f32>()).collect();
            vec.map(Some).map_err(serde::de::Error::custom)
        }
    }
}

/// Deserializes a required embedding from either a JSON array of floats or a pgvector-style string "[0.1, 0.2, ...]".
pub fn deserialize_embedding_required<'de, D>(deserializer: D) -> Result<Vec<f32>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum EmbeddingFormat {
        Array(Vec<f32>),
        String(String),
    }

    let value = EmbeddingFormat::deserialize(deserializer)?;
    match value {
        EmbeddingFormat::Array(v) => Ok(v),
        EmbeddingFormat::String(s) => {
            let s = s.trim();
            if s.is_empty() || s == "[]" {
                return Ok(Vec::new());
            }
            let s = s.trim_start_matches('[').trim_end_matches(']');
            s.split(',')
                .map(|x| x.trim().parse::<f32>().map_err(serde::de::Error::custom))
                .collect()
        }
    }
}