1use std::{
3 collections::{HashMap, HashSet},
4 fmt::Display,
5 num::TryFromIntError,
6};
7
8#[cfg(feature = "clock")]
9use chrono::Utc;
10use chrono::{DateTime, Duration, FixedOffset};
11use miette::SourceSpan;
12use pest::Parser as _;
13use strumbra::SharedString;
14
15use crate::{
16 ParseError,
17 enc_regex::EncodableRegex,
18 linker::{AlignFunction, ComputeFunction, GroupFunction, MapFunction},
19 parser::{self, MPLParser, ParseParamError, Rule},
20 tags::TagValue,
21 time::{Resolution, ResolutionError},
22 types::{BucketSpec, BucketType, Dataset, Metric, Parameterized},
23};
24
25mod fmt;
26#[cfg(test)]
27mod tests;
28
29#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
31pub struct MetricId {
32 pub dataset: Parameterized<Dataset>,
34 pub metric: Metric,
36}
37
38#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
40pub enum TimeUnit {
41 Millisecond,
43 Second,
45 Minute,
47 Hour,
49 Day,
51 Week,
53 Month,
55 Year,
57}
58
59#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
60pub struct RelativeTime {
62 pub value: u64,
64 pub unit: TimeUnit,
66}
67
68#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
70pub enum Time {
71 Relative(RelativeTime),
73 Timestamp(i64),
75 RFC3339(DateTime<FixedOffset>),
77 Modifier(String),
79}
80
81#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
83pub struct TimeRange {
84 pub start: Time,
86 pub end: Option<Time>,
88}
89
90#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
92pub struct Source {
93 pub metric_id: MetricId,
95 pub time: Option<TimeRange>,
97}
98impl Source {
99 fn time(&self) -> Option<&TimeRange> {
100 self.time.as_ref()
101 }
102}
103
104#[derive(Debug, thiserror::Error)]
106pub enum ValueError {
107 #[error("Invalid Float")]
109 BadFloat,
110}
111#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
113pub enum StringFragment {
114 Text(String),
116 Expr(Expr),
118}
119#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
121pub enum Expr {
122 Const(TagValue),
124 Param {
126 span: SourceSpan,
128 param: ParamDeclaration,
130 },
131 String(Vec<StringFragment>),
133 Array(Vec<Expr>),
135 Tag(String),
137}
138
139#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
141pub enum Cmp {
142 Eq(Expr),
144 Ne(Expr),
146 Gt(Expr),
148 Ge(Expr),
150 Lt(Expr),
152 Le(Expr),
154 In(Expr),
156 RegEx(Parameterized<EncodableRegex>),
158 RegExNot(Parameterized<EncodableRegex>),
160 Is(TagType),
162}
163
164#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
166pub struct As {
167 pub name: Metric,
169}
170
171#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
173pub enum Filter {
174 And(Vec<Filter>),
176 Or(Vec<Filter>),
178 Not(Box<Filter>),
180 Cmp {
182 field: String,
184 rhs: Cmp,
186 },
187}
188
189#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
191pub enum FilterOrIfDef {
192 Filter(Filter),
194 Ifdef {
196 param: ParamDeclaration,
198 filter: Filter,
200 else_filter: Option<Filter>,
202 },
203}
204
205impl FilterOrIfDef {
206 #[cfg(test)]
207 pub(crate) fn filter(&self) -> &Filter {
208 match self {
209 FilterOrIfDef::Filter(filter) | FilterOrIfDef::Ifdef { filter, .. } => filter,
210 }
211 }
212}
213
214#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
216pub struct Mapping {
217 pub function: MapFunction,
219 pub arg: Option<f64>,
221}
222
223#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
225pub struct Align {
226 pub function: AlignFunction,
228 pub time: Option<Parameterized<RelativeTime>>,
230}
231
232#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
234pub struct GroupBy {
235 pub span: SourceSpan,
237 pub function: GroupFunction,
239 pub tags: Vec<String>,
241}
242
243#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
245pub struct BucketBy {
246 pub span: SourceSpan,
248 pub function: BucketType,
250 pub time: Option<Parameterized<RelativeTime>>,
252 pub tags: Vec<String>,
254 pub spec: Vec<BucketSpec>,
256}
257
258#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
260pub enum Aggregate {
261 Map(Mapping),
263 Align(Align),
265 GroupBy(GroupBy),
267 Bucket(BucketBy),
269 As(As),
271}
272
273#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
275pub struct TagExtend {
276 pub tag: String,
278 pub value: Expr,
280}
281
282#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
284#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
285pub enum DirectiveValue {
286 Ident(String),
288 Int(i64),
290 Float(f64),
292 String(String),
294 Bool(bool),
296 None,
298}
299
300impl DirectiveValue {
301 #[must_use]
303 pub fn as_ident(&self) -> Option<&str> {
304 match self {
305 DirectiveValue::Ident(ident) => Some(ident),
306 _ => None,
307 }
308 }
309 #[must_use]
311 pub fn as_int(&self) -> Option<i64> {
312 match self {
313 DirectiveValue::Int(int) => Some(*int),
314 _ => None,
315 }
316 }
317 #[must_use]
319 pub fn as_float(&self) -> Option<f64> {
320 match self {
321 DirectiveValue::Float(float) => Some(*float),
322 _ => None,
323 }
324 }
325 #[must_use]
327 pub fn as_string(&self) -> Option<&str> {
328 match self {
329 DirectiveValue::String(string) => Some(string),
330 _ => None,
331 }
332 }
333 #[must_use]
335 pub fn as_bool(&self) -> Option<bool> {
336 match self {
337 DirectiveValue::Bool(bool) => Some(*bool),
338 _ => None,
339 }
340 }
341 #[must_use]
343 pub fn is_none(&self) -> bool {
344 matches!(self, DirectiveValue::None)
345 }
346 #[must_use]
348 pub fn is_some(&self) -> bool {
349 !self.is_none()
350 }
351}
352
353#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
355pub enum ParamType {
356 Terminal(TerminalParamType),
358 Optional(TerminalParamType),
360}
361
362impl ParamType {
363 fn is_optional(self) -> bool {
364 matches!(self, ParamType::Optional(_))
365 }
366 fn typ(self) -> TerminalParamType {
367 match self {
368 ParamType::Terminal(terminal_param_type) | ParamType::Optional(terminal_param_type) => {
369 terminal_param_type
370 }
371 }
372 }
373}
374
375impl std::fmt::Display for ParamType {
376 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
377 match self {
378 ParamType::Terminal(t) => t.fmt(f),
379 ParamType::Optional(t) => write!(f, "Option<{t}>"),
380 }
381 }
382}
383
384#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
386pub enum TerminalParamType {
387 Duration,
389 Dataset,
391 Regex,
393 Tag(TagType),
395}
396impl std::fmt::Display for TerminalParamType {
397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 match self {
399 TerminalParamType::Dataset => write!(f, "Dataset"),
400 TerminalParamType::Duration => write!(f, "Duration"),
401 TerminalParamType::Regex => write!(f, "Regex"),
402 TerminalParamType::Tag(t) => t.fmt(f),
403 }
404 }
405}
406
407#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
409#[derive(Clone, Copy, Debug, Hash, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
410pub enum TagType {
411 String,
413 Int,
415 Float,
417 Bool,
419 Null,
421 Array,
423}
424
425#[cfg(feature = "bincode")]
426#[test]
427fn test_renaming_none_to_null_has_no_bincode_side_effects() {
428 let enc = [4];
429 assert_eq!(
430 (TagType::Null, 1),
431 bincode::decode_from_slice(&enc, bincode::config::standard()).expect("it does ...")
432 );
433}
434
435impl std::fmt::Display for TagType {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 match self {
438 TagType::String => write!(f, "string"),
439 TagType::Int => write!(f, "int"),
440 TagType::Float => write!(f, "float"),
441 TagType::Bool => write!(f, "bool"),
442 TagType::Null => write!(f, "null"),
443 TagType::Array => write!(f, "array"),
444 }
445 }
446}
447
448pub type Directives = HashMap<String, DirectiveValue>;
450
451#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
453pub struct ParamDeclaration {
454 pub span: SourceSpan,
456 pub name: String,
458 pub typ: ParamType,
460}
461
462impl ParamDeclaration {
463 pub(crate) fn typ(&self) -> TerminalParamType {
464 self.typ.typ()
465 }
466
467 pub(crate) fn is_optional(&self) -> bool {
468 self.typ.is_optional()
469 }
470}
471
472#[derive(Debug, Clone, PartialEq)]
474pub enum ParamValue {
475 Dataset(Dataset),
477 Duration(RelativeTime),
479 String(String),
481 Int(i64),
483 Float(f64),
485 Bool(bool),
487 Regex(EncodableRegex),
489 Array(Vec<TagValue>),
491}
492
493impl ParamValue {
494 #[must_use]
496 pub fn typ(&self) -> TerminalParamType {
497 match self {
498 ParamValue::Dataset(_) => TerminalParamType::Dataset,
499 ParamValue::Duration(_) => TerminalParamType::Duration,
500 ParamValue::Regex(_) => TerminalParamType::Regex,
501 ParamValue::String(_) => TerminalParamType::Tag(TagType::String),
502 ParamValue::Int(_) => TerminalParamType::Tag(TagType::Int),
503 ParamValue::Float(_) => TerminalParamType::Tag(TagType::Float),
504 ParamValue::Bool(_) => TerminalParamType::Tag(TagType::Bool),
505 ParamValue::Array(_) => TerminalParamType::Tag(TagType::Array),
506 }
507 }
508}
509
510#[derive(Debug, Clone, PartialEq)]
512pub struct ProvidedParam {
513 pub name: String,
515 pub value: ParamValue,
517}
518
519impl ProvidedParam {
520 pub fn new(name: impl Into<String>, value: ParamValue) -> Self {
522 Self {
523 name: name.into(),
524 value,
525 }
526 }
527}
528
529#[derive(Debug, Clone, Default)]
531pub struct ProvidedParams {
532 inner: Vec<ProvidedParam>,
533}
534
535#[derive(Debug, thiserror::Error)]
537pub enum ResolveError {
538 #[error("Param ${0} was not provided to the query")]
540 ParamNotProvided(String),
541 #[error(
543 "Param ${name} is defined as `{defined}`, but was used in a context that expected one of: {}",
544 expected.iter().map(ToString::to_string).collect::<Vec<_>>().join(", ")
545 )]
546 InvalidType {
547 name: String,
549 defined: TerminalParamType,
551 expected: Vec<TerminalParamType>,
553 },
554 #[error("Shared string error: {0}")]
556 SharedString(#[from] strumbra::Error),
557}
558
559#[derive(Debug, thiserror::Error)]
561pub enum ParseProvidedParamsError {
562 #[error("Failed to parse the value for ${param_name} as {expected_type}: {err}")]
564 ParseParam {
565 param_name: String,
567 expected_type: ParamType,
569 err: ParseParamError,
571 },
572 #[error("These params were provided more than once: {}", .0.join(", "))]
574 ParamsProvidedMoreThanOnce(Vec<String>),
575 #[error("The following params were declared but not provided: {}", .0.join(", "))]
577 ParamsDeclaredButNotProvided(Vec<String>),
578 #[error("The number of params provided exceeds the upper limit of {0}")]
580 TooManyParamsProvided(usize),
581}
582#[derive(Debug)]
584pub enum WarningReason {
585 ParamNotDeclared(Vec<String>),
587 ParamUsingSystemPrefix {
589 param: String,
591 },
592 OldDuration,
594}
595
596impl Display for WarningReason {
597 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
598 match self {
599 WarningReason::ParamNotDeclared(items) => write!(
600 f,
601 "These params were provided but not declared: {}",
602 items.join(", ")
603 ),
604 WarningReason::OldDuration => {
605 write!(f, "`duration` is depricated, please ues `Duration`")
606 }
607 WarningReason::ParamUsingSystemPrefix { param } => {
608 write!(
609 f,
610 "The param ${param} uses the `__` prefix reserved for system params"
611 )
612 }
613 }
614 }
615}
616
617#[derive(Debug)]
619pub struct Warning {
620 source: Option<SourceSpan>,
621 warning: WarningReason,
622}
623
624impl Warning {
625 #[must_use]
627 pub fn warning(&self) -> &WarningReason {
628 &self.warning
629 }
630 #[must_use]
632 pub fn source(&self) -> Option<SourceSpan> {
633 self.source
634 }
635}
636
637#[derive(Debug, Default)]
639pub struct Warnings {
640 inner: Vec<Warning>,
641}
642
643impl Warnings {
644 #[must_use]
646 pub fn new() -> Self {
647 Self::default()
648 }
649
650 pub fn push(&mut self, warning: WarningReason) {
652 self.inner.push(Warning {
653 source: None,
654 warning,
655 });
656 }
657 pub fn push_span(&mut self, span: SourceSpan, warning: WarningReason) {
659 self.inner.push(Warning {
660 source: Some(span),
661 warning,
662 });
663 }
664
665 #[must_use]
667 pub fn is_empty(&self) -> bool {
668 self.inner.is_empty()
669 }
670
671 #[must_use]
673 pub fn as_slice(&self) -> &[Warning] {
674 &self.inner
675 }
676
677 #[must_use]
679 pub fn into_vec(self) -> Vec<Warning> {
680 self.inner
681 }
682}
683
684impl ProvidedParams {
685 #[must_use]
687 pub fn new(inner: Vec<ProvidedParam>) -> Self {
688 Self { inner }
689 }
690
691 pub fn parse_and_validate(
695 mpl_params: &Params,
696 query_params: &[(String, String)],
697 ) -> Result<(Self, Warnings), ParseProvidedParamsError> {
698 const PREFIX: &str = "param__";
699 const PARAM_COUNT_LIMIT: usize = 128;
700
701 let mut warnings = Warnings::new();
702 let mut defined_more_than_once = HashSet::new();
703 let mut provided_but_not_declared = HashSet::new();
704 let mut seen = HashSet::new();
705
706 let params = query_params
707 .iter()
708 .filter_map(|(name, value)| {
709 if !name.starts_with(PREFIX) {
710 return None;
711 }
712 let name = name.trim_start_matches(PREFIX);
713 if name.is_empty() {
714 return None;
715 }
716
717 Some((name, value))
718 })
719 .take(PARAM_COUNT_LIMIT + 1)
720 .collect::<Vec<(&str, &String)>>();
721
722 if params.len() > PARAM_COUNT_LIMIT {
724 return Err(ParseProvidedParamsError::TooManyParamsProvided(
725 PARAM_COUNT_LIMIT,
726 ));
727 }
728
729 let mut provided_params = Vec::new();
730 for (name, value) in params {
731 if seen.contains(name) {
732 defined_more_than_once.insert(name);
734 continue;
735 }
736 seen.insert(name);
737
738 let Some(mpl_param) = mpl_params.iter().find(|p| p.name == name) else {
740 provided_but_not_declared.insert(name);
741 continue;
742 };
743
744 let parsed = MPLParser::parse(Rule::param_value, value).map_err(|err| {
746 ParseProvidedParamsError::ParseParam {
747 param_name: name.to_string(),
748 expected_type: mpl_param.typ,
749 err: ParseParamError::Parse(ParseError::from(err)),
750 }
751 })?;
752
753 let value = parser::parse_param_value(mpl_param, parsed).map_err(|err| {
755 ParseProvidedParamsError::ParseParam {
756 param_name: name.to_string(),
757 expected_type: mpl_param.typ,
758 err,
759 }
760 })?;
761
762 provided_params.push(ProvidedParam {
763 name: name.to_string(),
764 value,
765 });
766 }
767
768 if !provided_but_not_declared.is_empty() {
769 let mut items = provided_but_not_declared
771 .into_iter()
772 .map(|p| format!("${p}"))
773 .collect::<Vec<String>>();
774 items.sort();
775
776 warnings.push(WarningReason::ParamNotDeclared(items));
778 }
779
780 if !defined_more_than_once.is_empty() {
781 let mut items = defined_more_than_once
783 .into_iter()
784 .map(String::from)
785 .collect::<Vec<String>>();
786 items.sort();
787
788 return Err(ParseProvidedParamsError::ParamsProvidedMoreThanOnce(items));
789 }
790
791 let declared_param_names = mpl_params
792 .iter()
793 .filter_map(|p| {
794 if p.typ.is_optional() {
796 None
797 } else {
798 Some(p.name.as_str())
799 }
800 })
801 .collect::<HashSet<&str>>();
802 let declared_but_not_provided = declared_param_names
803 .difference(&seen)
804 .collect::<Vec<&&str>>();
805 if !declared_but_not_provided.is_empty() {
806 let mut items = declared_but_not_provided
808 .into_iter()
809 .map(|s| String::from(*s))
810 .collect::<Vec<String>>();
811 items.sort();
812
813 return Err(ParseProvidedParamsError::ParamsDeclaredButNotProvided(
814 items,
815 ));
816 }
817
818 Ok((ProvidedParams::new(provided_params), warnings))
819 }
820
821 #[must_use]
823 pub fn as_slice(&self) -> &[ProvidedParam] {
824 self.inner.as_slice()
825 }
826
827 fn get_param(&self, name: &str) -> Result<&ProvidedParam, ResolveError> {
828 self.inner
829 .iter()
830 .find(|p| p.name == name)
831 .ok_or(ResolveError::ParamNotProvided(name.to_string()))
832 }
833
834 pub fn inline_params(&self, expr: Expr) -> Result<Expr, ResolveError> {
836 let param = match expr {
837 Expr::Const(val) => return Ok(Expr::Const(val)), Expr::Tag(tag) => return Ok(Expr::Tag(tag)), Expr::Param { span: _, param } => param,
840 Expr::Array(parts) => {
841 let parts = parts
842 .into_iter()
843 .map(|expr| self.inline_params(expr))
844 .collect::<Result<_, ResolveError>>()?;
845 return Ok(Expr::Array(parts));
846 }
847 Expr::String(parts) => {
848 let parts = parts
850 .into_iter()
851 .map(|part| match part {
852 StringFragment::Text(text) => Ok(StringFragment::Text(text)),
853 StringFragment::Expr(expr) => {
854 Ok(StringFragment::Expr(self.inline_params(expr)?))
855 }
856 })
857 .collect::<Result<Vec<_>, ResolveError>>()?;
858 return if parts.iter().all(|part| {
860 matches!(part, StringFragment::Text(_))
861 | matches!(part, StringFragment::Expr(Expr::Const(_)))
862 }) {
863 Ok(Expr::Const(
866 parts
867 .into_iter()
868 .map(|part| match part {
869 StringFragment::Text(text) => text,
870 StringFragment::Expr(Expr::Const(TagValue::String(s))) => {
873 s.to_string()
874 }
875 StringFragment::Expr(Expr::Const(c)) => c.to_string(),
876 StringFragment::Expr(_) => {
877 "unreachable string collapse".to_string()
878 }
879 })
880 .collect::<String>()
881 .try_into()?,
882 ))
883 } else {
884 Ok(Expr::String(parts))
885 };
886 }
887 };
888
889 let provided_param = self.get_param(¶m.name)?;
890 match &provided_param.value {
891 ParamValue::String(val) => {
892 Ok(Expr::Const(TagValue::String(SharedString::try_from(val)?)))
893 }
894 ParamValue::Int(val) => Ok(Expr::Const(TagValue::Int(*val))),
895 ParamValue::Float(val) => Ok(Expr::Const(TagValue::Float(*val))),
896 ParamValue::Bool(val) => Ok(Expr::Const(TagValue::Bool(*val))),
897 ParamValue::Array(val) => Ok(Expr::Const(TagValue::Array(val.clone()))),
898 val => Err(ResolveError::InvalidType {
899 name: param.name,
900 defined: val.typ(),
901 expected: vec![
902 TerminalParamType::Tag(TagType::String),
903 TerminalParamType::Tag(TagType::Int),
904 TerminalParamType::Tag(TagType::Float),
905 TerminalParamType::Tag(TagType::Bool),
906 ],
907 }),
908 }
909 }
910
911 pub fn resolve_dataset(&self, pv: Parameterized<Dataset>) -> Result<Dataset, ResolveError> {
913 let param = match pv {
914 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
916 };
917
918 let provided_param = self.get_param(¶m.name)?;
919 match &provided_param.value {
920 ParamValue::Dataset(dataset) => Ok(dataset.clone()),
921 val => Err(ResolveError::InvalidType {
922 name: param.name,
923 defined: val.typ(),
924 expected: vec![TerminalParamType::Dataset],
925 }),
926 }
927 }
928
929 pub fn resolve_relative_time(
931 &self,
932 pv: Parameterized<RelativeTime>,
933 ) -> Result<RelativeTime, ResolveError> {
934 let param = match pv {
935 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
937 };
938
939 let provided_param = self.get_param(¶m.name)?;
940 match &provided_param.value {
941 ParamValue::Duration(relative_time) => Ok(relative_time.clone()),
942 val => Err(ResolveError::InvalidType {
943 name: param.name,
944 defined: val.typ(),
945 expected: vec![TerminalParamType::Duration],
946 }),
947 }
948 }
949
950 pub fn resolve_regex(
952 &self,
953 pv: Parameterized<EncodableRegex>,
954 ) -> Result<EncodableRegex, ResolveError> {
955 let param = match pv {
956 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
958 };
959
960 let provided_param = self.get_param(¶m.name)?;
961 match &provided_param.value {
962 ParamValue::Regex(re) => Ok(re.clone()),
963 val => Err(ResolveError::InvalidType {
964 name: param.name,
965 defined: val.typ(),
966 expected: vec![TerminalParamType::Regex],
967 }),
968 }
969 }
970 #[must_use]
972 pub fn contains(&self, param: &str) -> bool {
973 self.get_param(param).is_ok()
974 }
975
976 #[must_use]
981 pub fn active_filter<'a>(&self, filter: &'a FilterOrIfDef) -> Option<&'a Filter> {
982 match filter {
983 FilterOrIfDef::Filter(filter) => Some(filter),
984 FilterOrIfDef::Ifdef { param, filter, .. } if self.contains(¶m.name) => {
985 Some(filter)
986 }
987 FilterOrIfDef::Ifdef { else_filter, .. } => else_filter.as_ref(),
988 }
989 }
990
991 #[must_use]
993 pub fn active_filters<'a>(&self, filters: &'a [FilterOrIfDef]) -> Vec<&'a Filter> {
994 filters
995 .iter()
996 .filter_map(|filter| self.active_filter(filter))
997 .collect()
998 }
999}
1000
1001pub type Params = Vec<ParamDeclaration>;
1003
1004#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1006pub enum Query {
1007 Simple {
1009 source: Source,
1011 filters: Vec<FilterOrIfDef>,
1013 aggregates: Vec<Aggregate>,
1015 directives: Directives,
1017 params: Params,
1019 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1021 extends: Vec<TagExtend>,
1022 sample: Option<f64>,
1024 },
1025 Compute {
1027 left: Box<Query>,
1029 right: Box<Query>,
1031 name: Metric,
1033 op: ComputeFunction,
1035 aggregates: Vec<Aggregate>,
1037 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1039 extends: Vec<TagExtend>,
1040 directives: Directives,
1042 params: Params,
1044 },
1045}
1046
1047impl Query {
1048 #[must_use]
1050 pub fn time_range(&self) -> Option<&TimeRange> {
1051 match self {
1052 Query::Simple { source, .. } => source.time(),
1053 Query::Compute { left, .. } => left.time_range(),
1054 }
1055 }
1056 #[must_use]
1058 pub fn params(&self) -> &Params {
1059 match self {
1060 Query::Simple { params, .. } | Query::Compute { params, .. } => params,
1061 }
1062 }
1063 #[must_use]
1065 pub fn directives(&self) -> &Directives {
1066 match self {
1067 Query::Simple { directives, .. } | Query::Compute { directives, .. } => directives,
1068 }
1069 }
1070}
1071
1072impl RelativeTime {
1073 pub fn to_duration(&self) -> Result<Duration, TimeError> {
1075 let v = i64::try_from(self.value).map_err(TimeError::InvalidDuration)?;
1076 Ok(match self.unit {
1077 TimeUnit::Millisecond => Duration::milliseconds(v),
1078 TimeUnit::Second => Duration::seconds(v),
1079 TimeUnit::Minute => Duration::minutes(v),
1080 TimeUnit::Hour => Duration::hours(v),
1081 TimeUnit::Day => Duration::days(v),
1082 TimeUnit::Week => Duration::weeks(v),
1083 TimeUnit::Month => Duration::days(v.saturating_mul(30)),
1084 TimeUnit::Year => Duration::days(v.saturating_mul(365)),
1085 })
1086 }
1087
1088 pub fn to_resolution(&self) -> Result<Resolution, ResolutionError> {
1090 match self.unit {
1091 TimeUnit::Millisecond => Resolution::secs(self.value / 1000),
1092 TimeUnit::Second => Resolution::secs(self.value),
1093 TimeUnit::Minute => Resolution::secs(self.value.saturating_mul(60)),
1094 TimeUnit::Hour => Resolution::secs(self.value.saturating_mul(60 * 60)),
1095 TimeUnit::Day => Resolution::secs(self.value.saturating_mul(60 * 60 * 24)),
1096 TimeUnit::Week => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 7)),
1097 TimeUnit::Month => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 30)),
1098 TimeUnit::Year => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 365)),
1099 }
1100 }
1101}
1102
1103#[derive(Debug, thiserror::Error)]
1105pub enum TimeError {
1106 #[error("Invalid timestamp {0}, could not be converted to a UTC datetime")]
1108 InvalidTimestamp(i64),
1109 #[error(
1111 "Invalid duration {0}, could not be converted to Duration as it exceeds the maximum i64"
1112 )]
1113 InvalidDuration(TryFromIntError),
1114}
1115#[cfg(feature = "clock")]
1116impl Time {
1117 fn to_datetime(&self) -> Result<DateTime<Utc>, TimeError> {
1118 Ok(match self {
1119 Time::Relative(t) => Utc::now() - t.to_duration()?,
1120 Time::Timestamp(ts) => {
1121 DateTime::<Utc>::from_timestamp(*ts, 0).ok_or(TimeError::InvalidTimestamp(*ts))?
1122 }
1123 Time::RFC3339(t) => t.with_timezone(&Utc),
1124 Time::Modifier(_) => todo!(),
1125 })
1126 }
1127}
1128
1129#[cfg(feature = "clock")]
1130impl TimeRange {
1131 pub fn to_start_end(&self) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> {
1133 let start = self.start.to_datetime()?;
1134 let end = self
1135 .end
1136 .as_ref()
1137 .map_or_else(|| Ok(Utc::now()), Time::to_datetime)?;
1138 Ok((start, end))
1139 }
1140}