Files
komp_ac/komp-app/src/search.rs
2026-09-05 09:16:27 +02:00

82 lines
3.0 KiB
Rust

use anyhow::Result;
use common::proto::komp_ac::search::{
SearchCountResponse, SearchRequest, SearchResponse, searcher_client::SearcherClient,
};
use tonic::transport::Channel;
use tonic::Request;
#[derive(Clone)]
pub struct SearchGrpc {
client: SearcherClient<Channel>,
}
impl SearchGrpc {
pub fn new(channel: Channel) -> Self {
Self {
client: SearcherClient::new(channel),
}
}
pub async fn search(&mut self, request: Request<SearchRequest>) -> Result<SearchResponse> {
Ok(self.client.search(request).await?.into_inner())
}
pub async fn get_filtered_row(
&mut self,
request: Request<SearchRequest>,
) -> Result<common::proto::komp_ac::tables_data::GetTableDataResponse> {
Ok(self.client.get_filtered_row(request).await?.into_inner())
}
pub async fn batch_count(
&mut self,
request: Request<common::proto::komp_ac::search::BatchCountRequest>,
) -> Result<Vec<std::result::Result<u64, String>>> {
let expected = request.get_ref().requests.len();
let response = self.client.batch_count(request).await?.into_inner();
decode_batch_counts(response, expected)
}
pub async fn count(&mut self, request: Request<SearchRequest>) -> Result<SearchCountResponse> {
Ok(self.client.count(request).await?.into_inner())
}
}
fn decode_batch_counts(
response: common::proto::komp_ac::search::BatchCountResponse,
expected: usize,
) -> Result<Vec<std::result::Result<u64, String>>> {
use common::proto::komp_ac::search::batch_count_result::Outcome;
anyhow::ensure!(response.results.len() == expected, "Server returned an incomplete count batch");
Ok(response.results.into_iter().map(|result| match result.outcome {
Some(Outcome::Count(count)) => Ok(count),
Some(Outcome::Error(error)) => Err(error),
None => Err("Server omitted a count result".to_string()),
}).collect())
}
#[cfg(test)]
mod batch_count_tests {
use super::*;
use common::proto::komp_ac::search::{BatchCountResponse, BatchCountResult, batch_count_result::Outcome};
#[test]
fn batch_counts_preserve_zero_errors_and_missing_results() {
let response = BatchCountResponse { results: vec![
BatchCountResult { outcome: Some(Outcome::Count(0)) },
BatchCountResult { outcome: Some(Outcome::Error("denied".into())) },
BatchCountResult { outcome: None },
BatchCountResult { outcome: Some(Outcome::Count(7)) },
] };
let counts = decode_batch_counts(response, 4).unwrap();
assert_eq!(counts[0], Ok(0));
assert_eq!(counts[1], Err("denied".into()));
assert!(counts[2].is_err());
assert_eq!(counts[3], Ok(7));
assert!(decode_batch_counts(BatchCountResponse { results: Vec::new() }, 1).is_err());
assert!(decode_batch_counts(BatchCountResponse { results: vec![
BatchCountResult { outcome: Some(Outcome::Count(0)) },
] }, 0).is_err());
}
}