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, } impl SearchGrpc { pub fn new(channel: Channel) -> Self { Self { client: SearcherClient::new(channel), } } pub async fn search(&mut self, request: Request) -> Result { Ok(self.client.search(request).await?.into_inner()) } pub async fn get_filtered_row( &mut self, request: Request, ) -> Result { Ok(self.client.get_filtered_row(request).await?.into_inner()) } pub async fn batch_count( &mut self, request: Request, ) -> Result>> { 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) -> Result { Ok(self.client.count(request).await?.into_inner()) } } fn decode_batch_counts( response: common::proto::komp_ac::search::BatchCountResponse, expected: usize, ) -> Result>> { 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()); } }