promql_parser/label/
mod.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Label matchers and Well-known label names used by Prometheus components.
16
17use std::collections::HashSet;
18use std::fmt;
19
20mod matcher;
21pub use matcher::{MatchOp, Matcher, Matchers};
22
23/// "__name__"
24pub const METRIC_NAME: &str = "__name__";
25/// "alertname"
26pub const ALERT_NAME: &str = "alertname";
27/// "le"
28pub const BUCKET_LABEL: &str = "le";
29/// "instance"
30pub const INSTANCE_NAME: &str = "instance";
31
32pub type Label = String;
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Labels {
36    pub labels: Vec<Label>,
37}
38
39impl Labels {
40    pub fn append(mut self, l: Label) -> Self {
41        self.labels.push(l);
42        self
43    }
44
45    pub fn new(ls: Vec<&str>) -> Self {
46        let labels = ls.iter().map(|s| s.to_string()).collect();
47        Self { labels }
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.labels.is_empty()
52    }
53
54    pub fn is_joint(&self, ls: &Labels) -> bool {
55        let s1: HashSet<&String> = self.labels.iter().collect();
56        let s2: HashSet<&String> = ls.labels.iter().collect();
57
58        !s1.is_disjoint(&s2)
59    }
60
61    pub fn intersect(&self, ls: &Labels) -> Labels {
62        let s1: HashSet<&String> = self.labels.iter().collect();
63        let s2: HashSet<&String> = ls.labels.iter().collect();
64        let labels = s1.intersection(&s2).map(|s| s.to_string()).collect();
65
66        Self { labels }
67    }
68}
69
70impl fmt::Display for Labels {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        write!(f, "{}", self.labels.join(", "))
73    }
74}
75
76#[cfg(feature = "ser")]
77impl serde::Serialize for Labels {
78    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79    where
80        S: serde::Serializer,
81    {
82        use serde::ser::SerializeSeq;
83        let mut seq = serializer.serialize_seq(Some(self.labels.len()))?;
84
85        for l in &self.labels {
86            seq.serialize_element(&l)?;
87        }
88
89        seq.end()
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_to_string() {
99        let cases = vec![
100            (vec![], ""),
101            (vec!["foo"], "foo"),
102            (vec!["foo", "bar"], "foo, bar"),
103            (vec!["foo", "foo", "bar"], "foo, foo, bar"),
104        ];
105
106        for (ls, expect) in cases {
107            let lb = Labels::new(ls);
108            assert_eq!(expect, lb.to_string())
109        }
110    }
111
112    #[test]
113    fn test_is_joint() {
114        let cases = vec![
115            (vec!["foo"], vec!["bar"], false),
116            (vec!["foo"], vec!["foo", "bar"], true),
117            (vec!["foo"], vec!["foo"], true),
118        ];
119
120        for (lb1, lb2, is) in cases {
121            let lb1 = Labels::new(lb1);
122            let lb2 = Labels::new(lb2);
123            assert_eq!(is, lb1.is_joint(&lb2), "{lb1:?} and {lb2:?}")
124        }
125    }
126
127    #[test]
128    fn test_intersect() {
129        let cases = vec![
130            (vec!["foo"], vec!["bar"], vec![]),
131            (vec!["foo"], vec!["foo", "bar"], vec!["foo"]),
132            (vec!["foo"], vec!["foo"], vec!["foo"]),
133            (vec!["foo", "bar"], vec!["bar", "foo"], vec!["foo", "bar"]),
134        ];
135
136        for (lb1, lb2, common) in cases {
137            let lb1 = Labels::new(lb1);
138            let lb2 = Labels::new(lb2);
139            let intersection: HashSet<_> = lb1.intersect(&lb2).labels.into_iter().collect();
140            let expect: HashSet<_> = common.iter().map(|s| s.to_string()).collect();
141            assert_eq!(expect, intersection)
142        }
143    }
144}