1use nom::{
61 IResult, Parser,
62 branch::alt,
63 bytes::complete::tag,
64 character::complete::char,
65 combinator::{map, opt, success},
66 multi::separated_list1,
67 sequence::{delimited, terminated},
68};
69
70use crate::lexer::{
71 duration::{Duration, duration, signed_duration},
72 identifier::{label_name, metric_name},
73 number::number,
74 string::string_literal,
75 whitespace::ws_opt,
76};
77
78#[derive(Debug, Clone, PartialEq)]
89pub enum AtModifier {
90 Timestamp(i64),
92 Start,
94 End,
96}
97
98impl std::fmt::Display for AtModifier {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 AtModifier::Timestamp(ts) => {
102 let secs = *ts as f64 / 1000.0;
104 write!(f, "@ {:.3}", secs)
105 }
106 AtModifier::Start => write!(f, "@ start()"),
107 AtModifier::End => write!(f, "@ end()"),
108 }
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub enum LabelMatchOp {
117 Equal,
119 NotEqual,
121 RegexMatch,
123 RegexNotMatch,
125}
126
127impl LabelMatchOp {
128 pub fn as_str(&self) -> &'static str {
130 match self {
131 LabelMatchOp::Equal => "=",
132 LabelMatchOp::NotEqual => "!=",
133 LabelMatchOp::RegexMatch => "=~",
134 LabelMatchOp::RegexNotMatch => "!~",
135 }
136 }
137
138 pub fn is_negative(&self) -> bool {
140 matches!(self, LabelMatchOp::NotEqual | LabelMatchOp::RegexNotMatch)
141 }
142
143 pub fn is_regex(&self) -> bool {
145 matches!(self, LabelMatchOp::RegexMatch | LabelMatchOp::RegexNotMatch)
146 }
147}
148
149impl std::fmt::Display for LabelMatchOp {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(f, "{}", self.as_str())
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct LabelMatcher {
169 pub name: String,
171 pub op: LabelMatchOp,
173 pub value: String,
175}
176
177impl LabelMatcher {
178 pub fn new(name: impl Into<String>, op: LabelMatchOp, value: impl Into<String>) -> Self {
180 Self {
181 name: name.into(),
182 op,
183 value: value.into(),
184 }
185 }
186
187 pub fn matches_empty(&self) -> bool {
189 match self.op {
190 LabelMatchOp::Equal => self.value.is_empty(),
191 LabelMatchOp::NotEqual => !self.value.is_empty(),
192 LabelMatchOp::RegexMatch => {
193 self.value.is_empty()
196 || self.value == ".*"
197 || self.value == "^$"
198 || self.value == "^.*$"
199 }
200 LabelMatchOp::RegexNotMatch => {
201 self.value == ".+"
204 }
205 }
206 }
207}
208
209impl std::fmt::Display for LabelMatcher {
210 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 write!(
212 f,
213 "{}{}\"{}\"",
214 self.name,
215 self.op,
216 self.value.escape_default()
217 )
218 }
219}
220
221#[derive(Debug, Clone, PartialEq)]
236pub struct VectorSelector {
237 pub name: Option<String>,
239 pub matchers: Vec<LabelMatcher>,
241 pub offset: Option<Duration>,
243 pub at: Option<AtModifier>,
245}
246
247impl VectorSelector {
248 pub fn new(name: impl Into<String>) -> Self {
250 Self {
251 name: Some(name.into()),
252 matchers: Vec::new(),
253 offset: None,
254 at: None,
255 }
256 }
257
258 pub fn with_matchers(matchers: Vec<LabelMatcher>) -> Self {
260 Self {
261 name: None,
262 matchers,
263 offset: None,
264 at: None,
265 }
266 }
267
268 pub fn add_matcher(&mut self, matcher: LabelMatcher) {
270 self.matchers.push(matcher);
271 }
272
273 pub fn all_matchers(&self) -> Vec<LabelMatcher> {
275 let mut result = self.matchers.clone();
276 if let Some(ref name) = self.name {
277 result.push(LabelMatcher::new(
278 "__name__",
279 LabelMatchOp::Equal,
280 name.clone(),
281 ));
282 }
283 result
284 }
285
286 pub fn has_non_empty_matcher(&self) -> bool {
289 if self.name.is_some() {
291 return true;
292 }
293
294 self.matchers.iter().any(|m| !m.matches_empty())
296 }
297}
298
299impl std::fmt::Display for VectorSelector {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 if let Some(ref name) = self.name {
302 write!(f, "{}", name)?;
303 }
304 if !self.matchers.is_empty() {
305 write!(f, "{{")?;
306 for (i, m) in self.matchers.iter().enumerate() {
307 if i > 0 {
308 write!(f, ", ")?;
309 }
310 write!(f, "{}", m)?;
311 }
312 write!(f, "}}")?;
313 }
314 if let Some(ref at) = self.at {
316 write!(f, " {}", at)?;
317 }
318 if let Some(ref offset) = self.offset {
319 write!(f, " offset {}", offset)?;
320 }
321 Ok(())
322 }
323}
324
325#[derive(Debug, Clone, PartialEq)]
340pub struct MatrixSelector {
341 pub selector: VectorSelector,
343 pub range: Duration,
345}
346
347impl MatrixSelector {
348 pub fn new(selector: VectorSelector, range: Duration) -> Self {
350 Self { selector, range }
351 }
352
353 pub fn with_name(name: impl Into<String>, range: Duration) -> Self {
355 Self {
356 selector: VectorSelector::new(name),
357 range,
358 }
359 }
360
361 pub fn name(&self) -> Option<&str> {
363 self.selector.name.as_deref()
364 }
365
366 pub fn matchers(&self) -> &[LabelMatcher] {
368 &self.selector.matchers
369 }
370
371 pub fn range_millis(&self) -> i64 {
373 self.range.as_millis()
374 }
375
376 pub fn offset(&self) -> Option<&Duration> {
378 self.selector.offset.as_ref()
379 }
380
381 pub fn offset_millis(&self) -> Option<i64> {
383 self.selector.offset.map(|d| d.as_millis())
384 }
385
386 pub fn at(&self) -> Option<&AtModifier> {
388 self.selector.at.as_ref()
389 }
390}
391
392impl std::fmt::Display for MatrixSelector {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 if let Some(ref name) = self.selector.name {
396 write!(f, "{}", name)?;
397 }
398 if !self.selector.matchers.is_empty() {
399 write!(f, "{{")?;
400 for (i, m) in self.selector.matchers.iter().enumerate() {
401 if i > 0 {
402 write!(f, ", ")?;
403 }
404 write!(f, "{}", m)?;
405 }
406 write!(f, "}}")?;
407 }
408 write!(f, "[{}]", self.range)?;
410 if let Some(ref at) = self.selector.at {
412 write!(f, " {}", at)?;
413 }
414 if let Some(ref offset) = self.selector.offset {
416 write!(f, " offset {}", offset)?;
417 }
418 Ok(())
419 }
420}
421
422fn range_duration(input: &str) -> IResult<&str, Duration> {
424 delimited(char('['), duration, char(']')).parse(input)
425}
426
427fn offset_keyword(input: &str) -> IResult<&str, &str> {
429 alt((tag("offset"), tag("OFFSET"), tag("Offset"))).parse(input)
430}
431
432pub fn offset_modifier(input: &str) -> IResult<&str, Duration> {
455 let (rest, _) = ws_opt(input)?;
456 let (rest, _) = offset_keyword(rest)?;
457 let (rest, _) = ws_opt(rest)?;
458 signed_duration(rest)
459}
460
461pub fn at_modifier(input: &str) -> IResult<&str, AtModifier> {
484 let (rest, _) = ws_opt(input)?;
485 let (rest, _) = char('@')(rest)?;
486 let (rest, _) = ws_opt(rest)?;
487
488 if let Ok((rest, _)) = tag::<&str, &str, nom::error::Error<&str>>("start()")(rest) {
490 return Ok((rest, AtModifier::Start));
491 }
492 if let Ok((rest, _)) = tag::<&str, &str, nom::error::Error<&str>>("end()")(rest) {
493 return Ok((rest, AtModifier::End));
494 }
495
496 let (rest, ts) = number(rest)?;
498
499 if ts.is_infinite() || ts.is_nan() {
501 return Err(nom::Err::Error(nom::error::Error::new(
502 input,
503 nom::error::ErrorKind::Verify,
504 )));
505 }
506
507 let ts_ms = (ts * 1000.0).round() as i64;
509 Ok((rest, AtModifier::Timestamp(ts_ms)))
510}
511
512pub fn matrix_selector(input: &str) -> IResult<&str, MatrixSelector> {
534 map(
535 (base_vector_selector, range_duration, parse_modifiers),
536 |(mut selector, range, (at, offset))| {
537 selector.at = at;
538 selector.offset = offset;
539 MatrixSelector::new(selector, range)
540 },
541 )
542 .parse(input)
543}
544
545pub(crate) fn parse_modifiers(
548 input: &str,
549) -> IResult<&str, (Option<AtModifier>, Option<Duration>)> {
550 let mut rest = input;
551 let mut at = None;
552 let mut offset = None;
553
554 loop {
555 if let Ok((next, parsed_at)) = at_modifier(rest) {
556 if at.is_some() {
557 return Err(nom::Err::Error(nom::error::Error::new(
558 rest,
559 nom::error::ErrorKind::Verify,
560 )));
561 }
562 at = Some(parsed_at);
563 rest = next;
564 continue;
565 }
566
567 if let Ok((next, parsed_offset)) = offset_modifier(rest) {
568 if offset.is_some() {
569 return Err(nom::Err::Error(nom::error::Error::new(
570 rest,
571 nom::error::ErrorKind::Verify,
572 )));
573 }
574 offset = Some(parsed_offset);
575 rest = next;
576 continue;
577 }
578
579 break;
580 }
581
582 Ok((rest, (at, offset)))
583}
584
585fn label_match_op(input: &str) -> IResult<&str, LabelMatchOp> {
587 alt((
588 map(tag("!="), |_| LabelMatchOp::NotEqual),
589 map(tag("!~"), |_| LabelMatchOp::RegexNotMatch),
590 map(tag("=~"), |_| LabelMatchOp::RegexMatch),
591 map(tag("="), |_| LabelMatchOp::Equal),
592 ))
593 .parse(input)
594}
595
596fn label_matcher(input: &str) -> IResult<&str, LabelMatcher> {
598 map(
599 (
600 ws_opt,
601 label_name,
602 ws_opt,
603 label_match_op,
604 ws_opt,
605 string_literal,
606 ),
607 |(_, name, _, op, _, value)| LabelMatcher::new(name.to_string(), op, value),
608 )
609 .parse(input)
610}
611
612fn quoted_metric_matcher(input: &str) -> IResult<&str, LabelMatcher> {
614 map((ws_opt, string_literal), |(_, name)| {
615 LabelMatcher::new("__name__", LabelMatchOp::Equal, name)
616 })
617 .parse(input)
618}
619
620fn matcher_item(input: &str) -> IResult<&str, LabelMatcher> {
622 alt((label_matcher, quoted_metric_matcher)).parse(input)
623}
624
625pub fn label_matchers(input: &str) -> IResult<&str, Vec<LabelMatcher>> {
627 delimited(
628 (char('{'), ws_opt),
629 alt((
630 terminated(
631 separated_list1(delimited(ws_opt, char(','), ws_opt), matcher_item),
632 opt((ws_opt, char(','))),
633 ),
634 success(Vec::new()),
635 )),
636 (ws_opt, char('}')),
637 )
638 .parse(input)
639}
640
641pub fn vector_selector(input: &str) -> IResult<&str, VectorSelector> {
662 map(
663 (base_vector_selector, parse_modifiers),
664 |(mut selector, (at, offset))| {
665 selector.at = at;
666 selector.offset = offset;
667 selector
668 },
669 )
670 .parse(input)
671}
672
673pub fn base_vector_selector(input: &str) -> IResult<&str, VectorSelector> {
676 let name_result = metric_name(input);
678
679 match name_result {
680 Ok((rest, name)) => {
681 let (rest, matchers) = opt(label_matchers).parse(rest)?;
683 Ok((
684 rest,
685 VectorSelector {
686 name: Some(name.to_string()),
687 matchers: matchers.unwrap_or_default(),
688 offset: None,
689 at: None,
690 },
691 ))
692 }
693 Err(_) => {
694 let (rest, matchers) = label_matchers(input)?;
696
697 let name = matchers
699 .iter()
700 .find(|m| m.name == "__name__" && m.op == LabelMatchOp::Equal)
701 .map(|m| m.value.clone());
702
703 let other_matchers: Vec<_> = if name.is_some() {
705 matchers
706 .into_iter()
707 .filter(|m| !(m.name == "__name__" && m.op == LabelMatchOp::Equal))
708 .collect()
709 } else {
710 matchers
711 };
712
713 Ok((
714 rest,
715 VectorSelector {
716 name,
717 matchers: other_matchers,
718 offset: None,
719 at: None,
720 },
721 ))
722 }
723 }
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729
730 #[test]
732 fn test_label_match_op_parse() {
733 assert_eq!(label_match_op("=").unwrap().1, LabelMatchOp::Equal);
734 assert_eq!(label_match_op("!=").unwrap().1, LabelMatchOp::NotEqual);
735 assert_eq!(label_match_op("=~").unwrap().1, LabelMatchOp::RegexMatch);
736 assert_eq!(label_match_op("!~").unwrap().1, LabelMatchOp::RegexNotMatch);
737 }
738
739 #[test]
740 fn test_label_match_op_display() {
741 assert_eq!(LabelMatchOp::Equal.to_string(), "=");
742 assert_eq!(LabelMatchOp::NotEqual.to_string(), "!=");
743 assert_eq!(LabelMatchOp::RegexMatch.to_string(), "=~");
744 assert_eq!(LabelMatchOp::RegexNotMatch.to_string(), "!~");
745 }
746
747 #[test]
748 fn test_label_match_op_properties() {
749 assert!(!LabelMatchOp::Equal.is_negative());
750 assert!(LabelMatchOp::NotEqual.is_negative());
751 assert!(!LabelMatchOp::RegexMatch.is_negative());
752 assert!(LabelMatchOp::RegexNotMatch.is_negative());
753
754 assert!(!LabelMatchOp::Equal.is_regex());
755 assert!(!LabelMatchOp::NotEqual.is_regex());
756 assert!(LabelMatchOp::RegexMatch.is_regex());
757 assert!(LabelMatchOp::RegexNotMatch.is_regex());
758 }
759
760 #[test]
762 fn test_label_matcher_parse() {
763 let (rest, m) = label_matcher(r#"job="prometheus""#).unwrap();
764 assert!(rest.is_empty());
765 assert_eq!(m.name, "job");
766 assert_eq!(m.op, LabelMatchOp::Equal);
767 assert_eq!(m.value, "prometheus");
768 }
769
770 #[test]
771 fn test_label_matcher_parse_with_spaces() {
772 let (rest, m) = label_matcher(r#" job = "prometheus" "#).unwrap();
773 assert_eq!(rest, " "); assert_eq!(m.name, "job");
775 assert_eq!(m.value, "prometheus");
776 }
777
778 #[test]
779 fn test_label_matcher_not_equal() {
780 let (_, m) = label_matcher(r#"env!="prod""#).unwrap();
781 assert_eq!(m.op, LabelMatchOp::NotEqual);
782 }
783
784 #[test]
785 fn test_label_matcher_regex() {
786 let (_, m) = label_matcher(r#"path=~"/api/.*""#).unwrap();
787 assert_eq!(m.op, LabelMatchOp::RegexMatch);
788 assert_eq!(m.value, "/api/.*");
789 }
790
791 #[test]
792 fn test_label_matcher_regex_not() {
793 let (_, m) = label_matcher(r#"status!~"5..""#).unwrap();
794 assert_eq!(m.op, LabelMatchOp::RegexNotMatch);
795 }
796
797 #[test]
798 fn test_label_matcher_matches_empty() {
799 assert!(LabelMatcher::new("a", LabelMatchOp::Equal, "").matches_empty());
801 assert!(!LabelMatcher::new("a", LabelMatchOp::Equal, "foo").matches_empty());
803 assert!(!LabelMatcher::new("a", LabelMatchOp::NotEqual, "").matches_empty());
805 assert!(LabelMatcher::new("a", LabelMatchOp::NotEqual, "foo").matches_empty());
807 assert!(LabelMatcher::new("a", LabelMatchOp::RegexMatch, ".*").matches_empty());
809 assert!(!LabelMatcher::new("a", LabelMatchOp::RegexMatch, ".+").matches_empty());
811 assert!(LabelMatcher::new("a", LabelMatchOp::RegexNotMatch, ".+").matches_empty());
813 }
814
815 #[test]
817 fn test_vector_selector_simple_name() {
818 let (rest, sel) = vector_selector("foo").unwrap();
819 assert!(rest.is_empty());
820 assert_eq!(sel.name, Some("foo".to_string()));
821 assert!(sel.matchers.is_empty());
822 }
823
824 #[test]
825 fn test_vector_selector_with_underscore() {
826 let (rest, sel) = vector_selector("http_requests_total").unwrap();
827 assert!(rest.is_empty());
828 assert_eq!(sel.name, Some("http_requests_total".to_string()));
829 }
830
831 #[test]
832 fn test_vector_selector_with_colon() {
833 let (rest, sel) = vector_selector("foo:bar:baz").unwrap();
834 assert!(rest.is_empty());
835 assert_eq!(sel.name, Some("foo:bar:baz".to_string()));
836 }
837
838 #[test]
839 fn test_vector_selector_with_label() {
840 let (rest, sel) = vector_selector(r#"foo{bar="baz"}"#).unwrap();
841 assert!(rest.is_empty());
842 assert_eq!(sel.name, Some("foo".to_string()));
843 assert_eq!(sel.matchers.len(), 1);
844 assert_eq!(sel.matchers[0].name, "bar");
845 assert_eq!(sel.matchers[0].value, "baz");
846 }
847
848 #[test]
849 fn test_vector_selector_multiple_labels() {
850 let (rest, sel) = vector_selector(r#"foo{a="b", c="d"}"#).unwrap();
851 assert!(rest.is_empty());
852 assert_eq!(sel.name, Some("foo".to_string()));
853 assert_eq!(sel.matchers.len(), 2);
854 assert_eq!(sel.matchers[0].name, "a");
855 assert_eq!(sel.matchers[1].name, "c");
856 }
857
858 #[test]
859 fn test_vector_selector_trailing_comma() {
860 let (rest, sel) = vector_selector(r#"foo{a="b",}"#).unwrap();
861 assert!(rest.is_empty());
862 assert_eq!(sel.matchers.len(), 1);
863 }
864
865 #[test]
866 fn test_vector_selector_labels_only() {
867 let (rest, sel) = vector_selector(r#"{job="prometheus"}"#).unwrap();
868 assert!(rest.is_empty());
869 assert!(sel.name.is_none());
870 assert_eq!(sel.matchers.len(), 1);
871 assert_eq!(sel.matchers[0].name, "job");
872 }
873
874 #[test]
875 fn test_vector_selector_quoted_metric_name() {
876 let (rest, sel) = vector_selector(r#"{"foo"}"#).unwrap();
877 assert!(rest.is_empty());
878 assert_eq!(sel.name, Some("foo".to_string()));
879 assert!(sel.matchers.is_empty());
880 }
881
882 #[test]
883 fn test_vector_selector_quoted_metric_with_labels() {
884 let (rest, sel) = vector_selector(r#"{"foo", bar="baz"}"#).unwrap();
885 assert!(rest.is_empty());
886 assert_eq!(sel.name, Some("foo".to_string()));
887 assert_eq!(sel.matchers.len(), 1);
888 }
889
890 #[test]
891 fn test_vector_selector_all_operators() {
892 let (rest, sel) = vector_selector(r#"foo{a="b", c!="d", e=~"f", g!~"h"}"#).unwrap();
893 assert!(rest.is_empty());
894 assert_eq!(sel.matchers.len(), 4);
895 assert_eq!(sel.matchers[0].op, LabelMatchOp::Equal);
896 assert_eq!(sel.matchers[1].op, LabelMatchOp::NotEqual);
897 assert_eq!(sel.matchers[2].op, LabelMatchOp::RegexMatch);
898 assert_eq!(sel.matchers[3].op, LabelMatchOp::RegexNotMatch);
899 }
900
901 #[test]
902 fn test_vector_selector_has_non_empty_matcher() {
903 let sel = VectorSelector::new("foo");
905 assert!(sel.has_non_empty_matcher());
906
907 let mut sel = VectorSelector::with_matchers(vec![]);
909 sel.add_matcher(LabelMatcher::new("job", LabelMatchOp::Equal, "test"));
910 assert!(sel.has_non_empty_matcher());
911
912 let sel =
914 VectorSelector::with_matchers(vec![LabelMatcher::new("x", LabelMatchOp::Equal, "")]);
915 assert!(!sel.has_non_empty_matcher());
916 }
917
918 #[test]
919 fn test_vector_selector_display() {
920 let mut sel = VectorSelector::new("foo");
921 assert_eq!(sel.to_string(), "foo");
922
923 sel.add_matcher(LabelMatcher::new("bar", LabelMatchOp::Equal, "baz"));
924 assert_eq!(sel.to_string(), r#"foo{bar="baz"}"#);
925 }
926
927 #[test]
928 fn test_vector_selector_single_quoted() {
929 let (rest, sel) = vector_selector(r#"foo{bar='baz'}"#).unwrap();
930 assert!(rest.is_empty());
931 assert_eq!(sel.matchers[0].value, "baz");
932 }
933
934 #[test]
935 fn test_vector_selector_backtick() {
936 let (rest, sel) = vector_selector(r#"foo{bar=`baz`}"#).unwrap();
937 assert!(rest.is_empty());
938 assert_eq!(sel.matchers[0].value, "baz");
939 }
940
941 #[test]
942 fn test_vector_selector_keyword_as_metric() {
943 for keyword in [
945 "sum", "min", "max", "avg", "count", "offset", "by", "without",
946 ] {
947 let result = vector_selector(keyword);
948 assert!(
949 result.is_ok(),
950 "Failed to parse keyword as metric: {}",
951 keyword
952 );
953 let (_, sel) = result.unwrap();
954 assert_eq!(sel.name, Some(keyword.to_string()));
955 }
956 }
957
958 #[test]
959 fn test_vector_selector_empty_braces() {
960 let (rest, sel) = vector_selector("{}").unwrap();
962 assert!(rest.is_empty());
963 assert!(sel.name.is_none());
964 assert!(sel.matchers.is_empty());
965 }
967
968 #[test]
970 fn test_matrix_selector_simple() {
971 let (rest, sel) = matrix_selector("foo[5m]").unwrap();
972 assert!(rest.is_empty());
973 assert_eq!(sel.name(), Some("foo"));
974 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
975 }
976
977 #[test]
978 fn test_matrix_selector_with_labels() {
979 let (rest, sel) = matrix_selector(r#"foo{bar="baz"}[5m]"#).unwrap();
980 assert!(rest.is_empty());
981 assert_eq!(sel.name(), Some("foo"));
982 assert_eq!(sel.matchers().len(), 1);
983 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
984 }
985
986 #[test]
987 fn test_matrix_selector_various_durations() {
988 let (_, sel) = matrix_selector("foo[30s]").unwrap();
990 assert_eq!(sel.range_millis(), 30 * 1000);
991
992 let (_, sel) = matrix_selector("foo[5m]").unwrap();
994 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
995
996 let (_, sel) = matrix_selector("foo[1h]").unwrap();
998 assert_eq!(sel.range_millis(), 60 * 60 * 1000);
999
1000 let (_, sel) = matrix_selector("foo[1d]").unwrap();
1002 assert_eq!(sel.range_millis(), 24 * 60 * 60 * 1000);
1003
1004 let (_, sel) = matrix_selector("foo[1w]").unwrap();
1006 assert_eq!(sel.range_millis(), 7 * 24 * 60 * 60 * 1000);
1007
1008 let (_, sel) = matrix_selector("foo[100ms]").unwrap();
1010 assert_eq!(sel.range_millis(), 100);
1011 }
1012
1013 #[test]
1014 fn test_matrix_selector_compound_duration() {
1015 let (rest, sel) = matrix_selector("foo[1h30m]").unwrap();
1017 assert!(rest.is_empty());
1018 assert_eq!(sel.range_millis(), (60 + 30) * 60 * 1000);
1019 }
1020
1021 #[test]
1022 fn test_matrix_selector_labels_only() {
1023 let (rest, sel) = matrix_selector(r#"{job="prometheus"}[5m]"#).unwrap();
1024 assert!(rest.is_empty());
1025 assert!(sel.name().is_none());
1026 assert_eq!(sel.matchers().len(), 1);
1027 }
1028
1029 #[test]
1030 fn test_matrix_selector_display() {
1031 let sel = MatrixSelector::with_name("foo", Duration::from_secs(300));
1032 assert_eq!(sel.to_string(), "foo[5m]");
1033 }
1034
1035 #[test]
1036 fn test_matrix_selector_display_with_labels() {
1037 let mut vs = VectorSelector::new("foo");
1038 vs.add_matcher(LabelMatcher::new("bar", LabelMatchOp::Equal, "baz"));
1039 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1040 assert_eq!(sel.to_string(), r#"foo{bar="baz"}[5m]"#);
1041 }
1042
1043 #[test]
1044 fn test_matrix_selector_no_range_fails() {
1045 let result = matrix_selector("foo");
1047 assert!(result.is_err());
1048 }
1049
1050 #[test]
1051 fn test_matrix_selector_empty_range_fails() {
1052 let result = matrix_selector("foo[]");
1053 assert!(result.is_err());
1054 }
1055
1056 #[test]
1058 fn test_offset_modifier_basic() {
1059 let (rest, dur) = offset_modifier(" offset 5m").unwrap();
1060 assert!(rest.is_empty());
1061 assert_eq!(dur.as_millis(), 5 * 60 * 1000);
1062 }
1063
1064 #[test]
1065 fn test_offset_modifier_negative() {
1066 let (rest, dur) = offset_modifier(" offset -7m").unwrap();
1067 assert!(rest.is_empty());
1068 assert_eq!(dur.as_millis(), -7 * 60 * 1000);
1069 }
1070
1071 #[test]
1072 fn test_offset_modifier_uppercase() {
1073 let (rest, dur) = offset_modifier(" OFFSET 1h30m").unwrap();
1074 assert!(rest.is_empty());
1075 assert_eq!(dur.as_millis(), 90 * 60 * 1000);
1076 }
1077
1078 #[test]
1079 fn test_offset_modifier_complex_duration() {
1080 let (rest, dur) = offset_modifier(" OFFSET 1m30ms").unwrap();
1081 assert!(rest.is_empty());
1082 assert_eq!(dur.as_millis(), 60 * 1000 + 30);
1083 }
1084
1085 #[test]
1086 fn test_vector_selector_with_offset() {
1087 let (rest, sel) = vector_selector("foo offset 5m").unwrap();
1088 assert!(rest.is_empty());
1089 assert_eq!(sel.name, Some("foo".to_string()));
1090 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1091 }
1092
1093 #[test]
1094 fn test_vector_selector_with_negative_offset() {
1095 let (rest, sel) = vector_selector("foo offset -7m").unwrap();
1096 assert!(rest.is_empty());
1097 assert_eq!(sel.name, Some("foo".to_string()));
1098 assert_eq!(sel.offset.unwrap().as_millis(), -7 * 60 * 1000);
1099 }
1100
1101 #[test]
1102 fn test_vector_selector_with_labels_and_offset() {
1103 let (rest, sel) = vector_selector(r#"foo{bar="baz"} offset 1h"#).unwrap();
1104 assert!(rest.is_empty());
1105 assert_eq!(sel.name, Some("foo".to_string()));
1106 assert_eq!(sel.matchers.len(), 1);
1107 assert_eq!(sel.offset.unwrap().as_millis(), 60 * 60 * 1000);
1108 }
1109
1110 #[test]
1111 fn test_vector_selector_display_with_offset() {
1112 let mut sel = VectorSelector::new("foo");
1113 sel.offset = Some(Duration::from_secs(300));
1114 assert_eq!(sel.to_string(), "foo offset 5m");
1115 }
1116
1117 #[test]
1118 fn test_matrix_selector_with_offset() {
1119 let (rest, sel) = matrix_selector("foo[5m] offset 1h").unwrap();
1120 assert!(rest.is_empty());
1121 assert_eq!(sel.name(), Some("foo"));
1122 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
1123 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1124 }
1125
1126 #[test]
1127 fn test_matrix_selector_with_labels_and_offset() {
1128 let (rest, sel) = matrix_selector(r#"foo{bar="baz"}[5m] offset 30m"#).unwrap();
1129 assert!(rest.is_empty());
1130 assert_eq!(sel.name(), Some("foo"));
1131 assert_eq!(sel.matchers().len(), 1);
1132 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
1133 assert_eq!(sel.offset_millis(), Some(30 * 60 * 1000));
1134 }
1135
1136 #[test]
1137 fn test_matrix_selector_with_negative_offset() {
1138 let (rest, sel) = matrix_selector("foo[5m] offset -1h").unwrap();
1139 assert!(rest.is_empty());
1140 assert_eq!(sel.offset_millis(), Some(-60 * 60 * 1000));
1141 }
1142
1143 #[test]
1144 fn test_matrix_selector_display_with_offset() {
1145 let mut vs = VectorSelector::new("foo");
1146 vs.offset = Some(Duration::from_secs(3600));
1147 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1148 assert_eq!(sel.to_string(), "foo[5m] offset 1h");
1149 }
1150
1151 #[test]
1153 fn test_at_modifier_timestamp() {
1154 let (rest, at) = at_modifier(" @ 1603774568").unwrap();
1155 assert!(rest.is_empty());
1156 assert_eq!(at, AtModifier::Timestamp(1_603_774_568_000));
1157 }
1158
1159 #[test]
1160 fn test_at_modifier_negative_timestamp() {
1161 let (rest, at) = at_modifier(" @ -100").unwrap();
1162 assert!(rest.is_empty());
1163 assert_eq!(at, AtModifier::Timestamp(-100_000));
1164 }
1165
1166 #[test]
1167 fn test_at_modifier_float_timestamp() {
1168 let (rest, at) = at_modifier(" @ 3.33").unwrap();
1169 assert!(rest.is_empty());
1170 assert_eq!(at, AtModifier::Timestamp(3_330));
1171 }
1172
1173 #[test]
1174 fn test_at_modifier_start() {
1175 let (rest, at) = at_modifier(" @ start()").unwrap();
1176 assert!(rest.is_empty());
1177 assert_eq!(at, AtModifier::Start);
1178 }
1179
1180 #[test]
1181 fn test_at_modifier_end() {
1182 let (rest, at) = at_modifier(" @ end()").unwrap();
1183 assert!(rest.is_empty());
1184 assert_eq!(at, AtModifier::End);
1185 }
1186
1187 #[test]
1188 fn test_at_modifier_display_timestamp() {
1189 let at = AtModifier::Timestamp(1_603_774_568_000);
1190 assert_eq!(at.to_string(), "@ 1603774568.000");
1191 }
1192
1193 #[test]
1194 fn test_at_modifier_display_start() {
1195 assert_eq!(AtModifier::Start.to_string(), "@ start()");
1196 }
1197
1198 #[test]
1199 fn test_at_modifier_display_end() {
1200 assert_eq!(AtModifier::End.to_string(), "@ end()");
1201 }
1202
1203 #[test]
1204 fn test_vector_selector_with_at() {
1205 let (rest, sel) = vector_selector("foo @ 1603774568").unwrap();
1206 assert!(rest.is_empty());
1207 assert_eq!(sel.name, Some("foo".to_string()));
1208 assert_eq!(sel.at, Some(AtModifier::Timestamp(1_603_774_568_000)));
1209 }
1210
1211 #[test]
1212 fn test_vector_selector_with_at_start() {
1213 let (rest, sel) = vector_selector("foo @ start()").unwrap();
1214 assert!(rest.is_empty());
1215 assert_eq!(sel.at, Some(AtModifier::Start));
1216 }
1217
1218 #[test]
1219 fn test_vector_selector_with_at_and_offset() {
1220 let (rest, sel) = vector_selector("foo @ 123 offset 5m").unwrap();
1222 assert!(rest.is_empty());
1223 assert_eq!(sel.at, Some(AtModifier::Timestamp(123_000)));
1224 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1225 }
1226
1227 #[test]
1228 fn test_vector_selector_with_offset_and_at() {
1229 let (rest, sel) = vector_selector("foo offset 5m @ 123").unwrap();
1231 assert!(rest.is_empty());
1232 assert_eq!(sel.at, Some(AtModifier::Timestamp(123_000)));
1233 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1234 }
1235
1236 #[test]
1237 fn test_vector_selector_display_with_at() {
1238 let mut sel = VectorSelector::new("foo");
1239 sel.at = Some(AtModifier::Timestamp(123_000));
1240 assert_eq!(sel.to_string(), "foo @ 123.000");
1241 }
1242
1243 #[test]
1244 fn test_vector_selector_display_with_at_and_offset() {
1245 let mut sel = VectorSelector::new("foo");
1246 sel.at = Some(AtModifier::Start);
1247 sel.offset = Some(Duration::from_secs(300));
1248 assert_eq!(sel.to_string(), "foo @ start() offset 5m");
1249 }
1250
1251 #[test]
1252 fn test_matrix_selector_with_at() {
1253 let (rest, sel) = matrix_selector("foo[5m] @ 123").unwrap();
1254 assert!(rest.is_empty());
1255 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1256 }
1257
1258 #[test]
1259 fn test_matrix_selector_with_at_and_offset() {
1260 let (rest, sel) = matrix_selector("foo[5m] @ 123 offset 1h").unwrap();
1261 assert!(rest.is_empty());
1262 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1263 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1264 }
1265
1266 #[test]
1267 fn test_matrix_selector_with_offset_and_at() {
1268 let (rest, sel) = matrix_selector("foo[5m] offset 1h @ 123").unwrap();
1269 assert!(rest.is_empty());
1270 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1271 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1272 }
1273
1274 #[test]
1275 fn test_matrix_selector_display_with_at() {
1276 let mut vs = VectorSelector::new("foo");
1277 vs.at = Some(AtModifier::Start);
1278 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1279 assert_eq!(sel.to_string(), "foo[5m] @ start()");
1280 }
1281
1282 #[test]
1283 fn test_matrix_selector_display_with_at_and_offset() {
1284 let mut vs = VectorSelector::new("foo");
1285 vs.at = Some(AtModifier::Start);
1286 vs.offset = Some(Duration::from_secs(60));
1287 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1288 assert_eq!(sel.to_string(), "foo[5m] @ start() offset 1m");
1289 }
1290}