use crate::namespace::{Namespace, NamespaceQuotas, NamespaceStatus};
use crate::store::{Metadata, Neighbor, Query};
use anyhow::Result;
use std::collections::HashMap;
pub mod pb {
include!("../generated/vecstore.rs");
}
pub fn pb_value_to_json(value: &pb::Value) -> Result<serde_json::Value> {
use pb::value::Kind;
match &value.kind {
Some(Kind::StringValue(s)) => Ok(serde_json::Value::String(s.clone())),
Some(Kind::NumberValue(n)) => Ok(serde_json::json!(n)),
Some(Kind::BoolValue(b)) => Ok(serde_json::Value::Bool(*b)),
Some(Kind::ArrayValue(arr)) => {
let values: Result<Vec<_>> = arr.values.iter().map(pb_value_to_json).collect();
Ok(serde_json::Value::Array(values?))
}
Some(Kind::ObjectValue(obj)) => {
let mut map = serde_json::Map::new();
for (k, v) in &obj.fields {
map.insert(k.clone(), pb_value_to_json(v)?);
}
Ok(serde_json::Value::Object(map))
}
Some(Kind::NullValue(_)) => Ok(serde_json::Value::Null),
None => Ok(serde_json::Value::Null),
}
}
pub fn json_to_pb_value(value: &serde_json::Value) -> pb::Value {
use pb::value::Kind;
let kind = match value {
serde_json::Value::String(s) => Some(Kind::StringValue(s.clone())),
serde_json::Value::Number(n) => Some(Kind::NumberValue(n.as_f64().unwrap_or(0.0))),
serde_json::Value::Bool(b) => Some(Kind::BoolValue(*b)),
serde_json::Value::Array(arr) => {
let values = arr.iter().map(json_to_pb_value).collect();
Some(Kind::ArrayValue(pb::ArrayValue { values }))
}
serde_json::Value::Object(obj) => {
let fields = obj
.iter()
.map(|(k, v)| (k.clone(), json_to_pb_value(v)))
.collect();
Some(Kind::ObjectValue(pb::ObjectValue { fields }))
}
serde_json::Value::Null => Some(Kind::NullValue(pb::NullValue::NullValue as i32)),
};
pb::Value { kind }
}
pub fn pb_metadata_to_metadata(pb_meta: &HashMap<String, pb::Value>) -> Result<Metadata> {
let mut fields = HashMap::new();
for (key, pb_value) in pb_meta {
fields.insert(key.clone(), pb_value_to_json(pb_value)?);
}
Ok(Metadata { fields })
}
pub fn metadata_to_pb_metadata(metadata: &Metadata) -> HashMap<String, pb::Value> {
metadata
.fields
.iter()
.map(|(k, v)| (k.clone(), json_to_pb_value(v)))
.collect()
}
pub fn neighbor_to_query_result(neighbor: &Neighbor) -> pb::QueryResult {
pb::QueryResult {
id: neighbor.id.clone(),
score: neighbor.score,
metadata: metadata_to_pb_metadata(&neighbor.metadata),
}
}
pub fn pb_query_to_query(req: &pb::QueryRequest) -> Result<Query> {
let filter = if let Some(ref filter_str) = req.filter {
Some(crate::store::parse_filter(filter_str)?)
} else {
None
};
Ok(Query {
vector: req.vector.clone(),
k: req.limit as usize,
filter,
})
}
pub fn namespace_info_to_proto(ns: &Namespace) -> pb::NamespaceInfo {
pb::NamespaceInfo {
id: ns.id.clone(),
name: ns.name.clone(),
description: ns.description.clone(),
quotas: Some(namespace_quotas_to_proto(&ns.quotas)),
status: namespace_status_to_proto(ns.status) as i32,
created_at: ns.created_at as i64,
updated_at: ns.updated_at as i64,
metadata: ns.metadata.clone(),
}
}
pub fn namespace_quotas_to_proto(quotas: &NamespaceQuotas) -> pb::NamespaceQuotas {
pb::NamespaceQuotas {
max_vectors: quotas.max_vectors.map(|v| v as i64),
max_storage_bytes: quotas.max_storage_bytes.map(|v| v as i64),
max_requests_per_second: quotas.max_requests_per_second,
max_concurrent_queries: quotas.max_concurrent_queries.map(|v| v as i32),
max_dimension: quotas.max_dimension.map(|v| v as i32),
max_results_per_query: quotas.max_results_per_query.map(|v| v as i32),
max_batch_size: quotas.max_batch_size.map(|v| v as i32),
}
}
pub fn namespace_quotas_from_proto(pb: pb::NamespaceQuotas) -> Result<NamespaceQuotas> {
Ok(NamespaceQuotas {
max_vectors: pb.max_vectors.map(|v| v as usize),
max_storage_bytes: pb.max_storage_bytes.map(|v| v as u64),
max_requests_per_second: pb.max_requests_per_second,
max_concurrent_queries: pb.max_concurrent_queries.map(|v| v as usize),
max_dimension: pb.max_dimension.map(|v| v as usize),
max_results_per_query: pb.max_results_per_query.map(|v| v as usize),
max_batch_size: pb.max_batch_size.map(|v| v as usize),
})
}
pub fn namespace_status_to_proto(status: NamespaceStatus) -> pb::NamespaceStatus {
match status {
NamespaceStatus::Active => pb::NamespaceStatus::NamespaceActive,
NamespaceStatus::Suspended => pb::NamespaceStatus::NamespaceSuspended,
NamespaceStatus::ReadOnly => pb::NamespaceStatus::NamespaceReadOnly,
NamespaceStatus::PendingDeletion => pb::NamespaceStatus::NamespacePendingDeletion,
}
}
pub fn namespace_status_from_proto(status: i32) -> Option<NamespaceStatus> {
match pb::NamespaceStatus::try_from(status).ok()? {
pb::NamespaceStatus::NamespaceActive => Some(NamespaceStatus::Active),
pb::NamespaceStatus::NamespaceSuspended => Some(NamespaceStatus::Suspended),
pb::NamespaceStatus::NamespaceReadOnly => Some(NamespaceStatus::ReadOnly),
pb::NamespaceStatus::NamespacePendingDeletion => Some(NamespaceStatus::PendingDeletion),
}
}