dsp_cli/client/sparql.rs
1//! The [`SparqlResponse`] relay type for [`crate::client::DspClient::sparql_query`].
2//!
3//! Deliberately not in `src/model/` — every `src/model/` type is a
4//! *translated domain* type per dsp-cli/ADR-0008's layer-4 contract, and this is
5//! transport-shaped (an HTTP status and a MIME string), not a parsed model.
6//! See dsp-cli/ADR-0016.
7
8/// One relayed SPARQL response: the triplestore's own status, media type and bytes.
9///
10/// Deliberately not a parsed model — dsp-cli/ADR-0016. The body is whatever the store
11/// serialized, in whatever format it negotiated, and dsp-cli does not interpret it.
12#[derive(Clone)]
13pub struct SparqlResponse {
14 /// The triplestore's HTTP status, relayed by DSP-API.
15 pub status: u16,
16 /// The triplestore's `Content-Type`, if it sent one. Never written to stdout —
17 /// it feeds the `-v` disclosure and the classifier's body-parse decision.
18 pub content_type: Option<String>,
19 /// The response body, byte-exact.
20 pub body: Vec<u8>,
21}
22
23/// Hand-written: a derived `Debug` on a struct holding up to 64 MiB of
24/// store-authored bytes would mean the first `tracing::debug!(?resp)` or the
25/// codebase's standard `assert!(…, "{result:?}")` test idiom dumps
26/// unsanitised store output into stderr or CI logs. Prints the body length
27/// instead of its bytes, and caps `content_type` defensively.
28impl std::fmt::Debug for SparqlResponse {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 let content_type = self.content_type.as_deref().map(|ct| {
31 let capped: String = ct.chars().take(200).collect();
32 if capped.len() < ct.len() {
33 format!("{capped}…")
34 } else {
35 capped
36 }
37 });
38 f.debug_struct("SparqlResponse")
39 .field("status", &self.status)
40 .field("content_type", &content_type)
41 .field("body", &format!("<{} bytes>", self.body.len()))
42 .finish()
43 }
44}