Skip to content

Commit 6d8b783

Browse files
committed
Normalize query HTTP response shapes
1 parent 78bc91a commit 6d8b783

1 file changed

Lines changed: 95 additions & 1 deletion

File tree

  • crates/morpheus-http-client/src

crates/morpheus-http-client/src/lib.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ impl MorpheusHttpClient {
397397
.send()
398398
.await
399399
.map_err(ClientError::http)?;
400-
parse_json(res).await
400+
parse_query_result_json(res).await
401401
}
402402

403403
pub async fn query_explain(
@@ -554,6 +554,100 @@ async fn parse_json<T: serde::de::DeserializeOwned>(
554554
}))
555555
}
556556

557+
async fn parse_query_result_json(
558+
res: reqwest::Response,
559+
) -> Result<ApiResponse<QueryResult>, ClientError> {
560+
let status = res.status();
561+
if status.is_success() {
562+
let body = res
563+
.json::<serde_json::Value>()
564+
.await
565+
.map_err(ClientError::http)?;
566+
return normalize_query_result_response(body);
567+
}
568+
569+
let body = match res.json::<ApiErrorBody>().await {
570+
Ok(body) => body,
571+
Err(_) => ApiErrorBody {
572+
code: "http_error".to_string(),
573+
message: format!("HTTP {status}"),
574+
},
575+
};
576+
Err(ClientError::api(ApiError {
577+
status: status.as_u16(),
578+
body,
579+
}))
580+
}
581+
582+
fn normalize_query_result_response(
583+
body: serde_json::Value,
584+
) -> Result<ApiResponse<QueryResult>, ClientError> {
585+
if let Ok(parsed) = serde_json::from_value::<ApiResponse<QueryResult>>(body.clone()) {
586+
return Ok(parsed);
587+
}
588+
589+
#[derive(serde::Deserialize)]
590+
struct LegacyQueryResponse {
591+
data: Vec<CellDto>,
592+
}
593+
594+
if let Ok(parsed) = serde_json::from_value::<LegacyQueryResponse>(body) {
595+
return Ok(ApiResponse {
596+
data: QueryResult {
597+
cells: parsed.data,
598+
hit_table: Default::default(),
599+
},
600+
});
601+
}
602+
603+
Err(ClientError::invalid_argument(
604+
"query response body did not match expected formats",
605+
))
606+
}
607+
608+
#[cfg(test)]
609+
mod tests {
610+
use super::*;
611+
use serde_json::json;
612+
613+
#[test]
614+
fn normalize_query_result_response_accepts_structured_shape() {
615+
let parsed = normalize_query_result_response(json!({
616+
"data": {
617+
"cells": [{
618+
"id": "JEFLHiLiF34zS6AVQMKYQy",
619+
"header": {},
620+
"data": {"content": "x"}
621+
}],
622+
"hit_table": {
623+
"JEFLHiLiF34zS6AVQMKYQy": {
624+
"1:bm25": 0.5
625+
}
626+
}
627+
}
628+
}))
629+
.expect("structured response should parse");
630+
631+
assert_eq!(parsed.data.cells.len(), 1);
632+
assert_eq!(parsed.data.hit_table.len(), 1);
633+
}
634+
635+
#[test]
636+
fn normalize_query_result_response_accepts_legacy_array_shape() {
637+
let parsed = normalize_query_result_response(json!({
638+
"data": [{
639+
"id": "JEFLHiLiF34zS6AVQMKYQy",
640+
"header": {},
641+
"data": {"content": "x"}
642+
}]
643+
}))
644+
.expect("legacy response should parse");
645+
646+
assert_eq!(parsed.data.cells.len(), 1);
647+
assert!(parsed.data.hit_table.is_empty());
648+
}
649+
}
650+
557651
pub fn validate_base58_id(s: &str) -> Result<(), ClientError> {
558652
let bytes = bs58::decode(s)
559653
.into_vec()

0 commit comments

Comments
 (0)