Skip to main content

clickhouse/
query_summary.rs

1use std::collections::HashMap;
2
3/// Parsed representation of the `X-ClickHouse-Summary` HTTP response header.
4///
5/// Provides typed getters for known fields and a generic [`get`](Self::get)
6/// fallback for forward-compatibility with future ClickHouse versions.
7///
8/// All getters return `Option<u64>`: `None` if the field is absent or cannot
9/// be parsed. This ensures deserialization never fails, even if ClickHouse
10/// renames, removes, or adds fields.
11///
12/// Note: the summary values may be incomplete unless the query was executed
13/// with `wait_end_of_query=1`, because ClickHouse sends this header before
14/// the response body and the values reflect progress at that point.
15#[derive(Debug, Clone)]
16pub struct QuerySummary {
17    fields: HashMap<String, String>,
18}
19
20impl QuerySummary {
21    /// Returns the raw string value for the given key, if present.
22    ///
23    /// Use this to access fields that are not yet covered by typed getters,
24    /// e.g. fields added in newer ClickHouse versions.
25    pub fn get(&self, key: &str) -> Option<&str> {
26        self.fields.get(key).map(String::as_str)
27    }
28
29    pub fn read_rows(&self) -> Option<u64> {
30        self.get_u64("read_rows")
31    }
32
33    pub fn read_bytes(&self) -> Option<u64> {
34        self.get_u64("read_bytes")
35    }
36
37    pub fn written_rows(&self) -> Option<u64> {
38        self.get_u64("written_rows")
39    }
40
41    pub fn written_bytes(&self) -> Option<u64> {
42        self.get_u64("written_bytes")
43    }
44
45    pub fn total_rows_to_read(&self) -> Option<u64> {
46        self.get_u64("total_rows_to_read")
47    }
48
49    pub fn result_rows(&self) -> Option<u64> {
50        self.get_u64("result_rows")
51    }
52
53    pub fn result_bytes(&self) -> Option<u64> {
54        self.get_u64("result_bytes")
55    }
56
57    pub fn elapsed_ns(&self) -> Option<u64> {
58        self.get_u64("elapsed_ns")
59    }
60
61    pub fn memory_usage(&self) -> Option<u64> {
62        self.get_u64("memory_usage")
63    }
64
65    fn get_u64(&self, key: &str) -> Option<u64> {
66        self.fields.get(key)?.parse().ok()
67    }
68
69    /// Parses the raw header value into a `QuerySummary`.
70    ///
71    /// Returns `None` if the value is not valid JSON or not an object with
72    /// string values. This matches ClickHouse's encoding, where all values
73    /// are JSON strings (e.g. `"1000"` instead of `1000`).
74    pub(crate) fn from_header(raw: &str) -> Option<Self> {
75        let fields: HashMap<String, String> = serde_json::from_str(raw).ok()?;
76        Some(Self { fields })
77    }
78}