use super::client::{Result, RpcClient, RpcClientError};
use super::types::VectorizerValue;
#[derive(Debug, Clone)]
pub struct CollectionInfo {
pub name: String,
pub vector_count: i64,
pub document_count: i64,
pub dimension: i64,
pub metric: String,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone)]
pub struct SearchHit {
pub id: String,
pub score: f64,
pub payload: Option<String>,
}
impl RpcClient {
pub async fn list_collections(&self) -> Result<Vec<String>> {
let v = self.call("collections.list", vec![]).await?;
let arr = v
.as_array()
.ok_or_else(|| RpcClientError::Server("collections.list: expected Array".into()))?;
Ok(arr
.iter()
.filter_map(|v| v.as_str().map(str::to_owned))
.collect())
}
pub async fn get_collection_info(&self, name: &str) -> Result<CollectionInfo> {
let v = self
.call(
"collections.get_info",
vec![VectorizerValue::Str(name.to_owned())],
)
.await?;
let need_str = |key: &str| -> Result<String> {
v.map_get(key)
.and_then(|x| x.as_str().map(str::to_owned))
.ok_or_else(|| {
RpcClientError::Server(format!(
"collections.get_info: missing string field '{key}'"
))
})
};
let need_int = |key: &str| -> Result<i64> {
v.map_get(key).and_then(|x| x.as_int()).ok_or_else(|| {
RpcClientError::Server(format!("collections.get_info: missing int field '{key}'"))
})
};
Ok(CollectionInfo {
name: need_str("name")?,
vector_count: need_int("vector_count")?,
document_count: need_int("document_count")?,
dimension: need_int("dimension")?,
metric: need_str("metric")?,
created_at: need_str("created_at")?,
updated_at: need_str("updated_at")?,
})
}
pub async fn get_vector(&self, collection: &str, vector_id: &str) -> Result<VectorizerValue> {
self.call(
"vectors.get",
vec![
VectorizerValue::Str(collection.to_owned()),
VectorizerValue::Str(vector_id.to_owned()),
],
)
.await
}
pub async fn search_basic(
&self,
collection: &str,
query: &str,
limit: usize,
) -> Result<Vec<SearchHit>> {
let args = vec![
VectorizerValue::Str(collection.to_owned()),
VectorizerValue::Str(query.to_owned()),
VectorizerValue::Int(limit as i64),
];
let v = self.call("search.basic", args).await?;
let arr = v
.as_array()
.ok_or_else(|| RpcClientError::Server("search.basic: expected Array".into()))?;
let mut hits = Vec::with_capacity(arr.len());
for entry in arr {
let id = entry
.map_get("id")
.and_then(|v| v.as_str())
.map(str::to_owned)
.ok_or_else(|| RpcClientError::Server("search.basic: hit missing 'id'".into()))?;
let score = entry
.map_get("score")
.and_then(|v| v.as_float())
.ok_or_else(|| {
RpcClientError::Server("search.basic: hit missing 'score'".into())
})?;
let payload = entry
.map_get("payload")
.and_then(|v| v.as_str())
.map(str::to_owned);
hits.push(SearchHit { id, score, payload });
}
Ok(hits)
}
}