Skip to main content

ic_query/
report.rs

1//! Shared report provenance classifications.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6///
7/// ReportDataSource
8///
9/// Origin of the data exposed by a report.
10///
11
12#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub enum ReportDataSource {
15    /// Rows were collected from live IC query calls.
16    Live,
17    /// Rows were read from a complete local snapshot.
18    Cache,
19}
20
21impl ReportDataSource {
22    /// Return the stable JSON and text label.
23    #[must_use]
24    pub const fn as_str(self) -> &'static str {
25        match self {
26            Self::Live => "live",
27            Self::Cache => "cache",
28        }
29    }
30}
31
32impl fmt::Display for ReportDataSource {
33    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34        formatter.write_str(self.as_str())
35    }
36}
37
38///
39/// ReportResultScope
40///
41/// Completeness boundary represented by a report view.
42///
43
44#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
45#[serde(rename_all = "kebab-case")]
46pub enum ReportResultScope {
47    /// A bounded page or detail view collected live.
48    BoundedLive,
49    /// A view derived from an API-exhausted complete cache.
50    CompleteCache,
51}
52
53impl ReportResultScope {
54    /// Return the stable JSON and text label.
55    #[must_use]
56    pub const fn as_str(self) -> &'static str {
57        match self {
58            Self::BoundedLive => "bounded-live",
59            Self::CompleteCache => "complete-cache",
60        }
61    }
62}
63
64impl fmt::Display for ReportResultScope {
65    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
66        formatter.write_str(self.as_str())
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::{ReportDataSource, ReportResultScope};
73
74    #[test]
75    fn report_provenance_labels_round_trip() {
76        for (source, label) in [
77            (ReportDataSource::Live, "live"),
78            (ReportDataSource::Cache, "cache"),
79        ] {
80            assert_eq!(source.as_str(), label);
81            assert_eq!(source.to_string(), label);
82            assert_eq!(
83                serde_json::to_string(&source).expect("serialize report data source"),
84                format!("\"{label}\"")
85            );
86            assert_eq!(
87                serde_json::from_str::<ReportDataSource>(&format!("\"{label}\""))
88                    .expect("deserialize report data source"),
89                source
90            );
91        }
92        for (scope, label) in [
93            (ReportResultScope::BoundedLive, "bounded-live"),
94            (ReportResultScope::CompleteCache, "complete-cache"),
95        ] {
96            assert_eq!(scope.as_str(), label);
97            assert_eq!(scope.to_string(), label);
98            assert_eq!(
99                serde_json::to_string(&scope).expect("serialize report result scope"),
100                format!("\"{label}\"")
101            );
102            assert_eq!(
103                serde_json::from_str::<ReportResultScope>(&format!("\"{label}\""))
104                    .expect("deserialize report result scope"),
105                scope
106            );
107        }
108        assert!(serde_json::from_str::<ReportDataSource>("\"api\"").is_err());
109        assert!(serde_json::from_str::<ReportResultScope>("\"partial\"").is_err());
110    }
111}