use serde::Deserialize;
pub const SUMMARY_HEADER: &str = "x-clickhouse-summary";
fn deserialize_string_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse::<u64>().map_err(serde::de::Error::custom)
}
#[derive(Debug, Deserialize)]
pub struct ClickHouseSummary {
#[serde(deserialize_with = "deserialize_string_u64")]
pub read_rows: u64,
#[serde(deserialize_with = "deserialize_string_u64")]
pub written_rows: u64,
#[serde(deserialize_with = "deserialize_string_u64")]
pub written_bytes: u64,
#[serde(deserialize_with = "deserialize_string_u64")]
pub elapsed_ns: u64,
}
pub fn parse_summary(header_value: &str) -> Option<ClickHouseSummary> {
serde_json::from_str(header_value).ok()
}
pub fn verify_written_rows(summary: &ClickHouseSummary, expected: u64) -> bool {
if summary.written_rows == expected {
true
} else {
tracing::warn!(
expected = expected,
actual = summary.written_rows,
"ClickHouse written_rows mismatch: expected {}, got {}",
expected,
summary.written_rows,
);
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_summary_valid() {
let json = r#"{"read_rows":"0","written_rows":"500","written_bytes":"12345","elapsed_ns":"1000000"}"#;
let summary = parse_summary(json).expect("should parse valid JSON");
assert_eq!(summary.read_rows, 0);
assert_eq!(summary.written_rows, 500);
assert_eq!(summary.written_bytes, 12345);
assert_eq!(summary.elapsed_ns, 1_000_000);
}
#[test]
fn test_parse_summary_invalid() {
assert!(parse_summary("not json at all").is_none());
assert!(parse_summary("{}").is_none()); assert!(parse_summary("").is_none());
}
#[test]
fn test_verify_written_rows_match() {
let summary = ClickHouseSummary {
read_rows: 0,
written_rows: 500,
written_bytes: 12345,
elapsed_ns: 1_000_000,
};
assert!(verify_written_rows(&summary, 500));
}
#[test]
fn test_verify_written_rows_mismatch() {
let summary = ClickHouseSummary {
read_rows: 0,
written_rows: 499,
written_bytes: 12345,
elapsed_ns: 1_000_000,
};
assert!(!verify_written_rows(&summary, 500));
}
}