1use nom::{
61 IResult, Parser,
62 branch::alt,
63 bytes::complete::tag,
64 character::complete::char,
65 combinator::{map, opt},
66 multi::{fold_many0, separated_list0},
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
545enum Modifier {
547 At(AtModifier),
548 Offset(Duration),
549}
550
551pub(crate) fn parse_modifiers(
554 input: &str,
555) -> IResult<&str, (Option<AtModifier>, Option<Duration>)> {
556 fold_many0(
557 alt((
558 at_modifier.map(Modifier::At),
559 offset_modifier.map(Modifier::Offset),
560 )),
561 || (None, None),
562 |(at, offset), modifier| match modifier {
563 Modifier::At(a) if at.is_none() => (Some(a), offset),
564 Modifier::Offset(o) if offset.is_none() => (at, Some(o)),
565 _ => (at, offset),
567 },
568 )
569 .parse(input)
570}
571
572fn label_match_op(input: &str) -> IResult<&str, LabelMatchOp> {
574 alt((
575 map(tag("!="), |_| LabelMatchOp::NotEqual),
576 map(tag("!~"), |_| LabelMatchOp::RegexNotMatch),
577 map(tag("=~"), |_| LabelMatchOp::RegexMatch),
578 map(tag("="), |_| LabelMatchOp::Equal),
579 ))
580 .parse(input)
581}
582
583fn label_matcher(input: &str) -> IResult<&str, LabelMatcher> {
585 map(
586 (
587 ws_opt,
588 label_name,
589 ws_opt,
590 label_match_op,
591 ws_opt,
592 string_literal,
593 ),
594 |(_, name, _, op, _, value)| LabelMatcher::new(name.to_string(), op, value),
595 )
596 .parse(input)
597}
598
599fn quoted_metric_matcher(input: &str) -> IResult<&str, LabelMatcher> {
601 map((ws_opt, string_literal), |(_, name)| {
602 LabelMatcher::new("__name__", LabelMatchOp::Equal, name)
603 })
604 .parse(input)
605}
606
607fn matcher_item(input: &str) -> IResult<&str, LabelMatcher> {
609 alt((label_matcher, quoted_metric_matcher)).parse(input)
610}
611
612pub fn label_matchers(input: &str) -> IResult<&str, Vec<LabelMatcher>> {
614 delimited(
615 (char('{'), ws_opt),
616 terminated(
617 separated_list0(delimited(ws_opt, char(','), ws_opt), matcher_item),
618 opt((ws_opt, char(','))), ),
620 (ws_opt, char('}')),
621 )
622 .parse(input)
623}
624
625pub fn vector_selector(input: &str) -> IResult<&str, VectorSelector> {
646 map(
647 (base_vector_selector, parse_modifiers),
648 |(mut selector, (at, offset))| {
649 selector.at = at;
650 selector.offset = offset;
651 selector
652 },
653 )
654 .parse(input)
655}
656
657pub fn base_vector_selector(input: &str) -> IResult<&str, VectorSelector> {
660 let name_result = metric_name(input);
662
663 match name_result {
664 Ok((rest, name)) => {
665 let (rest, matchers) = opt(label_matchers).parse(rest)?;
667 Ok((
668 rest,
669 VectorSelector {
670 name: Some(name.to_string()),
671 matchers: matchers.unwrap_or_default(),
672 offset: None,
673 at: None,
674 },
675 ))
676 }
677 Err(_) => {
678 let (rest, matchers) = label_matchers(input)?;
680
681 let name = matchers
683 .iter()
684 .find(|m| m.name == "__name__" && m.op == LabelMatchOp::Equal)
685 .map(|m| m.value.clone());
686
687 let other_matchers: Vec<_> = if name.is_some() {
689 matchers
690 .into_iter()
691 .filter(|m| !(m.name == "__name__" && m.op == LabelMatchOp::Equal))
692 .collect()
693 } else {
694 matchers
695 };
696
697 Ok((
698 rest,
699 VectorSelector {
700 name,
701 matchers: other_matchers,
702 offset: None,
703 at: None,
704 },
705 ))
706 }
707 }
708}
709
710#[cfg(test)]
711mod tests {
712 use super::*;
713
714 #[test]
716 fn test_label_match_op_parse() {
717 assert_eq!(label_match_op("=").unwrap().1, LabelMatchOp::Equal);
718 assert_eq!(label_match_op("!=").unwrap().1, LabelMatchOp::NotEqual);
719 assert_eq!(label_match_op("=~").unwrap().1, LabelMatchOp::RegexMatch);
720 assert_eq!(label_match_op("!~").unwrap().1, LabelMatchOp::RegexNotMatch);
721 }
722
723 #[test]
724 fn test_label_match_op_display() {
725 assert_eq!(LabelMatchOp::Equal.to_string(), "=");
726 assert_eq!(LabelMatchOp::NotEqual.to_string(), "!=");
727 assert_eq!(LabelMatchOp::RegexMatch.to_string(), "=~");
728 assert_eq!(LabelMatchOp::RegexNotMatch.to_string(), "!~");
729 }
730
731 #[test]
732 fn test_label_match_op_properties() {
733 assert!(!LabelMatchOp::Equal.is_negative());
734 assert!(LabelMatchOp::NotEqual.is_negative());
735 assert!(!LabelMatchOp::RegexMatch.is_negative());
736 assert!(LabelMatchOp::RegexNotMatch.is_negative());
737
738 assert!(!LabelMatchOp::Equal.is_regex());
739 assert!(!LabelMatchOp::NotEqual.is_regex());
740 assert!(LabelMatchOp::RegexMatch.is_regex());
741 assert!(LabelMatchOp::RegexNotMatch.is_regex());
742 }
743
744 #[test]
746 fn test_label_matcher_parse() {
747 let (rest, m) = label_matcher(r#"job="prometheus""#).unwrap();
748 assert!(rest.is_empty());
749 assert_eq!(m.name, "job");
750 assert_eq!(m.op, LabelMatchOp::Equal);
751 assert_eq!(m.value, "prometheus");
752 }
753
754 #[test]
755 fn test_label_matcher_parse_with_spaces() {
756 let (rest, m) = label_matcher(r#" job = "prometheus" "#).unwrap();
757 assert_eq!(rest, " "); assert_eq!(m.name, "job");
759 assert_eq!(m.value, "prometheus");
760 }
761
762 #[test]
763 fn test_label_matcher_not_equal() {
764 let (_, m) = label_matcher(r#"env!="prod""#).unwrap();
765 assert_eq!(m.op, LabelMatchOp::NotEqual);
766 }
767
768 #[test]
769 fn test_label_matcher_regex() {
770 let (_, m) = label_matcher(r#"path=~"/api/.*""#).unwrap();
771 assert_eq!(m.op, LabelMatchOp::RegexMatch);
772 assert_eq!(m.value, "/api/.*");
773 }
774
775 #[test]
776 fn test_label_matcher_regex_not() {
777 let (_, m) = label_matcher(r#"status!~"5..""#).unwrap();
778 assert_eq!(m.op, LabelMatchOp::RegexNotMatch);
779 }
780
781 #[test]
782 fn test_label_matcher_matches_empty() {
783 assert!(LabelMatcher::new("a", LabelMatchOp::Equal, "").matches_empty());
785 assert!(!LabelMatcher::new("a", LabelMatchOp::Equal, "foo").matches_empty());
787 assert!(!LabelMatcher::new("a", LabelMatchOp::NotEqual, "").matches_empty());
789 assert!(LabelMatcher::new("a", LabelMatchOp::NotEqual, "foo").matches_empty());
791 assert!(LabelMatcher::new("a", LabelMatchOp::RegexMatch, ".*").matches_empty());
793 assert!(!LabelMatcher::new("a", LabelMatchOp::RegexMatch, ".+").matches_empty());
795 assert!(LabelMatcher::new("a", LabelMatchOp::RegexNotMatch, ".+").matches_empty());
797 }
798
799 #[test]
801 fn test_vector_selector_simple_name() {
802 let (rest, sel) = vector_selector("foo").unwrap();
803 assert!(rest.is_empty());
804 assert_eq!(sel.name, Some("foo".to_string()));
805 assert!(sel.matchers.is_empty());
806 }
807
808 #[test]
809 fn test_vector_selector_with_underscore() {
810 let (rest, sel) = vector_selector("http_requests_total").unwrap();
811 assert!(rest.is_empty());
812 assert_eq!(sel.name, Some("http_requests_total".to_string()));
813 }
814
815 #[test]
816 fn test_vector_selector_with_colon() {
817 let (rest, sel) = vector_selector("foo:bar:baz").unwrap();
818 assert!(rest.is_empty());
819 assert_eq!(sel.name, Some("foo:bar:baz".to_string()));
820 }
821
822 #[test]
823 fn test_vector_selector_with_label() {
824 let (rest, sel) = vector_selector(r#"foo{bar="baz"}"#).unwrap();
825 assert!(rest.is_empty());
826 assert_eq!(sel.name, Some("foo".to_string()));
827 assert_eq!(sel.matchers.len(), 1);
828 assert_eq!(sel.matchers[0].name, "bar");
829 assert_eq!(sel.matchers[0].value, "baz");
830 }
831
832 #[test]
833 fn test_vector_selector_multiple_labels() {
834 let (rest, sel) = vector_selector(r#"foo{a="b", c="d"}"#).unwrap();
835 assert!(rest.is_empty());
836 assert_eq!(sel.name, Some("foo".to_string()));
837 assert_eq!(sel.matchers.len(), 2);
838 assert_eq!(sel.matchers[0].name, "a");
839 assert_eq!(sel.matchers[1].name, "c");
840 }
841
842 #[test]
843 fn test_vector_selector_trailing_comma() {
844 let (rest, sel) = vector_selector(r#"foo{a="b",}"#).unwrap();
845 assert!(rest.is_empty());
846 assert_eq!(sel.matchers.len(), 1);
847 }
848
849 #[test]
850 fn test_vector_selector_labels_only() {
851 let (rest, sel) = vector_selector(r#"{job="prometheus"}"#).unwrap();
852 assert!(rest.is_empty());
853 assert!(sel.name.is_none());
854 assert_eq!(sel.matchers.len(), 1);
855 assert_eq!(sel.matchers[0].name, "job");
856 }
857
858 #[test]
859 fn test_vector_selector_quoted_metric_name() {
860 let (rest, sel) = vector_selector(r#"{"foo"}"#).unwrap();
861 assert!(rest.is_empty());
862 assert_eq!(sel.name, Some("foo".to_string()));
863 assert!(sel.matchers.is_empty());
864 }
865
866 #[test]
867 fn test_vector_selector_quoted_metric_with_labels() {
868 let (rest, sel) = vector_selector(r#"{"foo", bar="baz"}"#).unwrap();
869 assert!(rest.is_empty());
870 assert_eq!(sel.name, Some("foo".to_string()));
871 assert_eq!(sel.matchers.len(), 1);
872 }
873
874 #[test]
875 fn test_vector_selector_all_operators() {
876 let (rest, sel) = vector_selector(r#"foo{a="b", c!="d", e=~"f", g!~"h"}"#).unwrap();
877 assert!(rest.is_empty());
878 assert_eq!(sel.matchers.len(), 4);
879 assert_eq!(sel.matchers[0].op, LabelMatchOp::Equal);
880 assert_eq!(sel.matchers[1].op, LabelMatchOp::NotEqual);
881 assert_eq!(sel.matchers[2].op, LabelMatchOp::RegexMatch);
882 assert_eq!(sel.matchers[3].op, LabelMatchOp::RegexNotMatch);
883 }
884
885 #[test]
886 fn test_vector_selector_has_non_empty_matcher() {
887 let sel = VectorSelector::new("foo");
889 assert!(sel.has_non_empty_matcher());
890
891 let mut sel = VectorSelector::with_matchers(vec![]);
893 sel.add_matcher(LabelMatcher::new("job", LabelMatchOp::Equal, "test"));
894 assert!(sel.has_non_empty_matcher());
895
896 let sel =
898 VectorSelector::with_matchers(vec![LabelMatcher::new("x", LabelMatchOp::Equal, "")]);
899 assert!(!sel.has_non_empty_matcher());
900 }
901
902 #[test]
903 fn test_vector_selector_display() {
904 let mut sel = VectorSelector::new("foo");
905 assert_eq!(sel.to_string(), "foo");
906
907 sel.add_matcher(LabelMatcher::new("bar", LabelMatchOp::Equal, "baz"));
908 assert_eq!(sel.to_string(), r#"foo{bar="baz"}"#);
909 }
910
911 #[test]
912 fn test_vector_selector_single_quoted() {
913 let (rest, sel) = vector_selector(r#"foo{bar='baz'}"#).unwrap();
914 assert!(rest.is_empty());
915 assert_eq!(sel.matchers[0].value, "baz");
916 }
917
918 #[test]
919 fn test_vector_selector_backtick() {
920 let (rest, sel) = vector_selector(r#"foo{bar=`baz`}"#).unwrap();
921 assert!(rest.is_empty());
922 assert_eq!(sel.matchers[0].value, "baz");
923 }
924
925 #[test]
926 fn test_vector_selector_keyword_as_metric() {
927 for keyword in [
929 "sum", "min", "max", "avg", "count", "offset", "by", "without",
930 ] {
931 let result = vector_selector(keyword);
932 assert!(
933 result.is_ok(),
934 "Failed to parse keyword as metric: {}",
935 keyword
936 );
937 let (_, sel) = result.unwrap();
938 assert_eq!(sel.name, Some(keyword.to_string()));
939 }
940 }
941
942 #[test]
943 fn test_vector_selector_empty_braces() {
944 let (rest, sel) = vector_selector("{}").unwrap();
946 assert!(rest.is_empty());
947 assert!(sel.name.is_none());
948 assert!(sel.matchers.is_empty());
949 }
951
952 #[test]
954 fn test_matrix_selector_simple() {
955 let (rest, sel) = matrix_selector("foo[5m]").unwrap();
956 assert!(rest.is_empty());
957 assert_eq!(sel.name(), Some("foo"));
958 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
959 }
960
961 #[test]
962 fn test_matrix_selector_with_labels() {
963 let (rest, sel) = matrix_selector(r#"foo{bar="baz"}[5m]"#).unwrap();
964 assert!(rest.is_empty());
965 assert_eq!(sel.name(), Some("foo"));
966 assert_eq!(sel.matchers().len(), 1);
967 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
968 }
969
970 #[test]
971 fn test_matrix_selector_various_durations() {
972 let (_, sel) = matrix_selector("foo[30s]").unwrap();
974 assert_eq!(sel.range_millis(), 30 * 1000);
975
976 let (_, sel) = matrix_selector("foo[5m]").unwrap();
978 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
979
980 let (_, sel) = matrix_selector("foo[1h]").unwrap();
982 assert_eq!(sel.range_millis(), 60 * 60 * 1000);
983
984 let (_, sel) = matrix_selector("foo[1d]").unwrap();
986 assert_eq!(sel.range_millis(), 24 * 60 * 60 * 1000);
987
988 let (_, sel) = matrix_selector("foo[1w]").unwrap();
990 assert_eq!(sel.range_millis(), 7 * 24 * 60 * 60 * 1000);
991
992 let (_, sel) = matrix_selector("foo[100ms]").unwrap();
994 assert_eq!(sel.range_millis(), 100);
995 }
996
997 #[test]
998 fn test_matrix_selector_compound_duration() {
999 let (rest, sel) = matrix_selector("foo[1h30m]").unwrap();
1001 assert!(rest.is_empty());
1002 assert_eq!(sel.range_millis(), (60 + 30) * 60 * 1000);
1003 }
1004
1005 #[test]
1006 fn test_matrix_selector_labels_only() {
1007 let (rest, sel) = matrix_selector(r#"{job="prometheus"}[5m]"#).unwrap();
1008 assert!(rest.is_empty());
1009 assert!(sel.name().is_none());
1010 assert_eq!(sel.matchers().len(), 1);
1011 }
1012
1013 #[test]
1014 fn test_matrix_selector_display() {
1015 let sel = MatrixSelector::with_name("foo", Duration::from_secs(300));
1016 assert_eq!(sel.to_string(), "foo[5m]");
1017 }
1018
1019 #[test]
1020 fn test_matrix_selector_display_with_labels() {
1021 let mut vs = VectorSelector::new("foo");
1022 vs.add_matcher(LabelMatcher::new("bar", LabelMatchOp::Equal, "baz"));
1023 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1024 assert_eq!(sel.to_string(), r#"foo{bar="baz"}[5m]"#);
1025 }
1026
1027 #[test]
1028 fn test_matrix_selector_no_range_fails() {
1029 let result = matrix_selector("foo");
1031 assert!(result.is_err());
1032 }
1033
1034 #[test]
1035 fn test_matrix_selector_empty_range_fails() {
1036 let result = matrix_selector("foo[]");
1037 assert!(result.is_err());
1038 }
1039
1040 #[test]
1042 fn test_offset_modifier_basic() {
1043 let (rest, dur) = offset_modifier(" offset 5m").unwrap();
1044 assert!(rest.is_empty());
1045 assert_eq!(dur.as_millis(), 5 * 60 * 1000);
1046 }
1047
1048 #[test]
1049 fn test_offset_modifier_negative() {
1050 let (rest, dur) = offset_modifier(" offset -7m").unwrap();
1051 assert!(rest.is_empty());
1052 assert_eq!(dur.as_millis(), -7 * 60 * 1000);
1053 }
1054
1055 #[test]
1056 fn test_offset_modifier_uppercase() {
1057 let (rest, dur) = offset_modifier(" OFFSET 1h30m").unwrap();
1058 assert!(rest.is_empty());
1059 assert_eq!(dur.as_millis(), 90 * 60 * 1000);
1060 }
1061
1062 #[test]
1063 fn test_offset_modifier_complex_duration() {
1064 let (rest, dur) = offset_modifier(" OFFSET 1m30ms").unwrap();
1065 assert!(rest.is_empty());
1066 assert_eq!(dur.as_millis(), 60 * 1000 + 30);
1067 }
1068
1069 #[test]
1070 fn test_vector_selector_with_offset() {
1071 let (rest, sel) = vector_selector("foo offset 5m").unwrap();
1072 assert!(rest.is_empty());
1073 assert_eq!(sel.name, Some("foo".to_string()));
1074 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1075 }
1076
1077 #[test]
1078 fn test_vector_selector_with_negative_offset() {
1079 let (rest, sel) = vector_selector("foo offset -7m").unwrap();
1080 assert!(rest.is_empty());
1081 assert_eq!(sel.name, Some("foo".to_string()));
1082 assert_eq!(sel.offset.unwrap().as_millis(), -7 * 60 * 1000);
1083 }
1084
1085 #[test]
1086 fn test_vector_selector_with_labels_and_offset() {
1087 let (rest, sel) = vector_selector(r#"foo{bar="baz"} offset 1h"#).unwrap();
1088 assert!(rest.is_empty());
1089 assert_eq!(sel.name, Some("foo".to_string()));
1090 assert_eq!(sel.matchers.len(), 1);
1091 assert_eq!(sel.offset.unwrap().as_millis(), 60 * 60 * 1000);
1092 }
1093
1094 #[test]
1095 fn test_vector_selector_display_with_offset() {
1096 let mut sel = VectorSelector::new("foo");
1097 sel.offset = Some(Duration::from_secs(300));
1098 assert_eq!(sel.to_string(), "foo offset 5m");
1099 }
1100
1101 #[test]
1102 fn test_matrix_selector_with_offset() {
1103 let (rest, sel) = matrix_selector("foo[5m] offset 1h").unwrap();
1104 assert!(rest.is_empty());
1105 assert_eq!(sel.name(), Some("foo"));
1106 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
1107 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1108 }
1109
1110 #[test]
1111 fn test_matrix_selector_with_labels_and_offset() {
1112 let (rest, sel) = matrix_selector(r#"foo{bar="baz"}[5m] offset 30m"#).unwrap();
1113 assert!(rest.is_empty());
1114 assert_eq!(sel.name(), Some("foo"));
1115 assert_eq!(sel.matchers().len(), 1);
1116 assert_eq!(sel.range_millis(), 5 * 60 * 1000);
1117 assert_eq!(sel.offset_millis(), Some(30 * 60 * 1000));
1118 }
1119
1120 #[test]
1121 fn test_matrix_selector_with_negative_offset() {
1122 let (rest, sel) = matrix_selector("foo[5m] offset -1h").unwrap();
1123 assert!(rest.is_empty());
1124 assert_eq!(sel.offset_millis(), Some(-60 * 60 * 1000));
1125 }
1126
1127 #[test]
1128 fn test_matrix_selector_display_with_offset() {
1129 let mut vs = VectorSelector::new("foo");
1130 vs.offset = Some(Duration::from_secs(3600));
1131 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1132 assert_eq!(sel.to_string(), "foo[5m] offset 1h");
1133 }
1134
1135 #[test]
1137 fn test_at_modifier_timestamp() {
1138 let (rest, at) = at_modifier(" @ 1603774568").unwrap();
1139 assert!(rest.is_empty());
1140 assert_eq!(at, AtModifier::Timestamp(1_603_774_568_000));
1141 }
1142
1143 #[test]
1144 fn test_at_modifier_negative_timestamp() {
1145 let (rest, at) = at_modifier(" @ -100").unwrap();
1146 assert!(rest.is_empty());
1147 assert_eq!(at, AtModifier::Timestamp(-100_000));
1148 }
1149
1150 #[test]
1151 fn test_at_modifier_float_timestamp() {
1152 let (rest, at) = at_modifier(" @ 3.33").unwrap();
1153 assert!(rest.is_empty());
1154 assert_eq!(at, AtModifier::Timestamp(3_330));
1155 }
1156
1157 #[test]
1158 fn test_at_modifier_start() {
1159 let (rest, at) = at_modifier(" @ start()").unwrap();
1160 assert!(rest.is_empty());
1161 assert_eq!(at, AtModifier::Start);
1162 }
1163
1164 #[test]
1165 fn test_at_modifier_end() {
1166 let (rest, at) = at_modifier(" @ end()").unwrap();
1167 assert!(rest.is_empty());
1168 assert_eq!(at, AtModifier::End);
1169 }
1170
1171 #[test]
1172 fn test_at_modifier_display_timestamp() {
1173 let at = AtModifier::Timestamp(1_603_774_568_000);
1174 assert_eq!(at.to_string(), "@ 1603774568.000");
1175 }
1176
1177 #[test]
1178 fn test_at_modifier_display_start() {
1179 assert_eq!(AtModifier::Start.to_string(), "@ start()");
1180 }
1181
1182 #[test]
1183 fn test_at_modifier_display_end() {
1184 assert_eq!(AtModifier::End.to_string(), "@ end()");
1185 }
1186
1187 #[test]
1188 fn test_vector_selector_with_at() {
1189 let (rest, sel) = vector_selector("foo @ 1603774568").unwrap();
1190 assert!(rest.is_empty());
1191 assert_eq!(sel.name, Some("foo".to_string()));
1192 assert_eq!(sel.at, Some(AtModifier::Timestamp(1_603_774_568_000)));
1193 }
1194
1195 #[test]
1196 fn test_vector_selector_with_at_start() {
1197 let (rest, sel) = vector_selector("foo @ start()").unwrap();
1198 assert!(rest.is_empty());
1199 assert_eq!(sel.at, Some(AtModifier::Start));
1200 }
1201
1202 #[test]
1203 fn test_vector_selector_with_at_and_offset() {
1204 let (rest, sel) = vector_selector("foo @ 123 offset 5m").unwrap();
1206 assert!(rest.is_empty());
1207 assert_eq!(sel.at, Some(AtModifier::Timestamp(123_000)));
1208 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1209 }
1210
1211 #[test]
1212 fn test_vector_selector_with_offset_and_at() {
1213 let (rest, sel) = vector_selector("foo offset 5m @ 123").unwrap();
1215 assert!(rest.is_empty());
1216 assert_eq!(sel.at, Some(AtModifier::Timestamp(123_000)));
1217 assert_eq!(sel.offset.unwrap().as_millis(), 5 * 60 * 1000);
1218 }
1219
1220 #[test]
1221 fn test_vector_selector_display_with_at() {
1222 let mut sel = VectorSelector::new("foo");
1223 sel.at = Some(AtModifier::Timestamp(123_000));
1224 assert_eq!(sel.to_string(), "foo @ 123.000");
1225 }
1226
1227 #[test]
1228 fn test_vector_selector_display_with_at_and_offset() {
1229 let mut sel = VectorSelector::new("foo");
1230 sel.at = Some(AtModifier::Start);
1231 sel.offset = Some(Duration::from_secs(300));
1232 assert_eq!(sel.to_string(), "foo @ start() offset 5m");
1233 }
1234
1235 #[test]
1236 fn test_matrix_selector_with_at() {
1237 let (rest, sel) = matrix_selector("foo[5m] @ 123").unwrap();
1238 assert!(rest.is_empty());
1239 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1240 }
1241
1242 #[test]
1243 fn test_matrix_selector_with_at_and_offset() {
1244 let (rest, sel) = matrix_selector("foo[5m] @ 123 offset 1h").unwrap();
1245 assert!(rest.is_empty());
1246 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1247 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1248 }
1249
1250 #[test]
1251 fn test_matrix_selector_with_offset_and_at() {
1252 let (rest, sel) = matrix_selector("foo[5m] offset 1h @ 123").unwrap();
1253 assert!(rest.is_empty());
1254 assert_eq!(sel.at(), Some(&AtModifier::Timestamp(123_000)));
1255 assert_eq!(sel.offset_millis(), Some(60 * 60 * 1000));
1256 }
1257
1258 #[test]
1259 fn test_matrix_selector_display_with_at() {
1260 let mut vs = VectorSelector::new("foo");
1261 vs.at = Some(AtModifier::Start);
1262 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1263 assert_eq!(sel.to_string(), "foo[5m] @ start()");
1264 }
1265
1266 #[test]
1267 fn test_matrix_selector_display_with_at_and_offset() {
1268 let mut vs = VectorSelector::new("foo");
1269 vs.at = Some(AtModifier::Start);
1270 vs.offset = Some(Duration::from_secs(60));
1271 let sel = MatrixSelector::new(vs, Duration::from_secs(300));
1272 assert_eq!(sel.to_string(), "foo[5m] @ start() offset 1m");
1273 }
1274}