linkrs_query/optimizer/stats/
view.rs1use super::manager::StatisticsManager;
8use super::{EdgeTypeStatistics, TagStatistics};
9
10#[derive(Debug)]
12pub struct StatsView<'a> {
13 manager: &'a StatisticsManager,
14 space: Option<&'a str>,
15}
16
17impl<'a> StatsView<'a> {
18 pub fn new(manager: &'a StatisticsManager, space: Option<&'a str>) -> Self {
20 Self { manager, space }
21 }
22
23 pub fn space(&self) -> Option<&'a str> {
25 self.space
26 }
27
28 pub fn vertex_count(&self, tag_name: &str) -> u64 {
30 match self.space {
31 Some(space) => self.manager.get_vertex_count(space, tag_name),
32 None => 0,
33 }
34 }
35
36 pub fn edge_count(&self, edge_type: &str) -> u64 {
38 match self.space {
39 Some(space) => self.manager.get_edge_count(space, edge_type),
40 None => 0,
41 }
42 }
43
44 pub fn tag_stats(&self, tag_name: &str) -> Option<TagStatistics> {
46 match self.space {
47 Some(space) => self.manager.get_tag_stats(space, tag_name),
48 None => None,
49 }
50 }
51
52 pub fn edge_stats(&self, edge_type: &str) -> Option<EdgeTypeStatistics> {
54 match self.space {
55 Some(space) => self.manager.get_edge_stats(space, edge_type),
56 None => None,
57 }
58 }
59
60 pub fn property_stats(
62 &self,
63 tag_name: Option<&str>,
64 property: &str,
65 ) -> Option<crate::optimizer::stats::PropertyStatistics> {
66 match self.space {
67 Some(space) => self.manager.get_property_stats(space, tag_name, property),
68 None => None,
69 }
70 }
71
72 pub fn property_ndv(&self, tag_name: Option<&str>, property: &str) -> Option<u64> {
74 self.property_stats(tag_name, property)
75 .map(|s| s.distinct_values)
76 .filter(|&n| n > 0)
77 }
78
79 pub fn combined_cardinality(
81 &self,
82 tag_name: Option<&str>,
83 properties: &[String],
84 ) -> Option<u64> {
85 match self.space {
86 Some(space) => self
87 .manager
88 .get_combined_cardinality(space, tag_name, properties),
89 None => None,
90 }
91 }
92
93 pub fn manager(&self) -> &StatisticsManager {
95 self.manager
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::optimizer::stats::TagStatistics;
103
104 #[test]
105 fn test_view_without_space_returns_no_stats() {
106 let manager = StatisticsManager::new();
107 let view = StatsView::new(&manager, None);
108 assert_eq!(view.space(), None);
109 assert_eq!(view.vertex_count("person"), 0);
110 assert_eq!(view.edge_count("follows"), 0);
111 assert!(view.tag_stats("person").is_none());
112 assert!(view.edge_stats("follows").is_none());
113 }
114
115 #[test]
116 fn test_view_with_space_reads_scoped_stats() {
117 let manager = StatisticsManager::new();
118 let mut tag = TagStatistics::new("person".to_string());
119 tag.vertex_count = 1000;
120 manager.update_tag_stats("basketball", tag);
121
122 let view = StatsView::new(&manager, Some("basketball"));
123 assert_eq!(view.vertex_count("person"), 1000);
124 assert_eq!(view.edge_count("follows"), 0);
125 assert_eq!(view.tag_stats("person").map(|s| s.vertex_count), Some(1000));
126
127 let other = StatsView::new(&manager, Some("tennis"));
128 assert_eq!(other.vertex_count("person"), 0);
129 }
130}