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)]
31#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
32#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
33pub struct MetricId {
34 pub dataset: Parameterized<Dataset>,
36 pub metric: Metric,
38}
39
40#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
42#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
43#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
44pub enum TimeUnit {
45 Millisecond,
47 Second,
49 Minute,
51 Hour,
53 Day,
55 Week,
57 Month,
59 Year,
61}
62
63#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
64#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
66#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
67pub struct RelativeTime {
68 pub value: u64,
70 pub unit: TimeUnit,
72}
73
74#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
76#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
77#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
78pub enum Time {
79 Relative(RelativeTime),
81 Timestamp(i64),
83 RFC3339(#[cfg_attr(feature = "wasm", tsify(type = "string"))] DateTime<FixedOffset>),
85 Modifier(String),
87}
88
89#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
91#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
92#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
93pub struct TimeRange {
94 pub start: Time,
96 pub end: Option<Time>,
98}
99
100#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
102#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
103#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
104pub struct Source {
105 pub metric_id: MetricId,
107 pub time: Option<TimeRange>,
109}
110impl Source {
111 fn time(&self) -> Option<&TimeRange> {
112 self.time.as_ref()
113 }
114}
115
116#[derive(Debug, thiserror::Error)]
118pub enum ValueError {
119 #[error("Invalid Float")]
121 BadFloat,
122}
123
124#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
126#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
127#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
128pub enum Cmp {
129 Eq(Parameterized<TagValue>),
131 Ne(Parameterized<TagValue>),
133 Gt(Parameterized<TagValue>),
135 Ge(Parameterized<TagValue>),
137 Lt(Parameterized<TagValue>),
139 Le(Parameterized<TagValue>),
141 RegEx(Parameterized<EncodableRegex>),
143 RegExNot(Parameterized<EncodableRegex>),
145 Is(TagType),
147}
148
149#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
151#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
152#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
153pub struct As {
154 pub name: Metric,
156}
157
158#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
160#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
161#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
162pub enum Filter {
163 And(Vec<Filter>),
165 Or(Vec<Filter>),
167 Not(Box<Filter>),
169 Cmp {
171 field: String,
173 rhs: Cmp,
175 },
176}
177
178#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
180#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
181#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
182pub enum FilterOrIfDef {
183 Filter(Filter),
185 Ifdef {
187 param: ParamDeclaration,
189 filter: Filter,
191 },
192}
193
194impl FilterOrIfDef {
195 #[cfg(test)]
196 pub(crate) fn filter(&self) -> &Filter {
197 match self {
198 FilterOrIfDef::Filter(filter) | FilterOrIfDef::Ifdef { filter, .. } => filter,
199 }
200 }
201}
202
203#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
205#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
206#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
207pub struct Mapping {
208 pub function: MapFunction,
210 pub arg: Option<f64>,
212}
213
214#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
216#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
217#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
218pub struct Align {
219 pub function: AlignFunction,
221 pub time: Option<Parameterized<RelativeTime>>,
223}
224
225#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
227#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
228#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
229pub struct GroupBy {
230 #[cfg_attr(feature = "wasm", tsify(type = "{ offset: number, length: number }"))]
232 pub span: SourceSpan,
233 pub function: GroupFunction,
235 pub tags: Vec<String>,
237}
238
239#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
241#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
242#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
243pub struct BucketBy {
244 #[cfg_attr(feature = "wasm", tsify(type = "{ offset: number, length: number }"))]
246 pub span: SourceSpan,
247 pub function: BucketType,
249 pub time: Option<Parameterized<RelativeTime>>,
251 pub tags: Vec<String>,
253 pub spec: Vec<BucketSpec>,
255}
256
257#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
259#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
260#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
261pub enum Aggregate {
262 Map(Mapping),
264 Align(Align),
266 GroupBy(GroupBy),
268 Bucket(BucketBy),
270 As(As),
272}
273
274#[cfg_attr(feature = "wasm", tsify::declare)]
276#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
277#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
278pub enum DirectiveValue {
279 Ident(String),
281 Int(i64),
283 Float(f64),
285 String(String),
287 Bool(bool),
289 None,
291}
292
293impl DirectiveValue {
294 #[must_use]
296 pub fn as_ident(&self) -> Option<&str> {
297 match self {
298 DirectiveValue::Ident(ident) => Some(ident),
299 _ => None,
300 }
301 }
302 #[must_use]
304 pub fn as_int(&self) -> Option<i64> {
305 match self {
306 DirectiveValue::Int(int) => Some(*int),
307 _ => None,
308 }
309 }
310 #[must_use]
312 pub fn as_float(&self) -> Option<f64> {
313 match self {
314 DirectiveValue::Float(float) => Some(*float),
315 _ => None,
316 }
317 }
318 #[must_use]
320 pub fn as_string(&self) -> Option<&str> {
321 match self {
322 DirectiveValue::String(string) => Some(string),
323 _ => None,
324 }
325 }
326 #[must_use]
328 pub fn as_bool(&self) -> Option<bool> {
329 match self {
330 DirectiveValue::Bool(bool) => Some(*bool),
331 _ => None,
332 }
333 }
334 #[must_use]
336 pub fn is_none(&self) -> bool {
337 matches!(self, DirectiveValue::None)
338 }
339 #[must_use]
341 pub fn is_some(&self) -> bool {
342 !self.is_none()
343 }
344}
345
346#[cfg_attr(feature = "wasm", tsify::declare)]
348#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
349pub enum ParamType {
350 Terminal(TerminalParamType),
352 Optional(TerminalParamType),
354}
355
356impl ParamType {
357 fn is_optional(self) -> bool {
358 matches!(self, ParamType::Optional(_))
359 }
360}
361
362impl std::fmt::Display for ParamType {
363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364 match self {
365 ParamType::Terminal(t) => t.fmt(f),
366 ParamType::Optional(t) => write!(f, "Option<{t}>"),
367 }
368 }
369}
370
371#[cfg_attr(feature = "wasm", tsify::declare)]
373#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
374pub enum TerminalParamType {
375 Duration,
377 Dataset,
379 Regex,
381 Tag(TagType),
383}
384impl std::fmt::Display for TerminalParamType {
385 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
386 match self {
387 TerminalParamType::Dataset => write!(f, "Dataset"),
388 TerminalParamType::Duration => write!(f, "Duration"),
389 TerminalParamType::Regex => write!(f, "Regex"),
390 TerminalParamType::Tag(t) => t.fmt(f),
391 }
392 }
393}
394
395#[cfg_attr(feature = "wasm", tsify::declare)]
397#[cfg_attr(feature = "bincode", derive(bincode::Encode, bincode::Decode))]
398#[derive(Clone, Copy, Debug, Hash, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
399pub enum TagType {
400 String,
402 Int,
404 Float,
406 Bool,
408 Null,
410}
411
412#[cfg(feature = "bincode")]
413#[test]
414fn test_renaming_none_to_null_has_no_bincode_side_effects() {
415 let enc = [4];
416 assert_eq!(
417 (TagType::Null, 1),
418 bincode::decode_from_slice(&enc, bincode::config::standard()).expect("it does ...")
419 );
420}
421
422impl std::fmt::Display for TagType {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 write!(
425 f,
426 "{}",
427 match self {
428 TagType::String => "string",
429 TagType::Int => "int",
430 TagType::Float => "float",
431 TagType::Bool => "bool",
432 TagType::Null => "null",
433 }
434 )
435 }
436}
437
438#[cfg_attr(feature = "wasm", tsify::declare)]
440pub type Directives = HashMap<String, DirectiveValue>;
441
442#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
444#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
445pub struct ParamDeclaration {
446 #[cfg_attr(feature = "wasm", tsify(type = "{ offset: number, length: number }"))]
448 pub span: SourceSpan,
449 pub name: String,
451 pub typ: ParamType,
453}
454
455impl ParamDeclaration {
456 pub(crate) fn typ(&self) -> TerminalParamType {
457 match self.typ {
458 ParamType::Terminal(terminal_param_type) | ParamType::Optional(terminal_param_type) => {
459 terminal_param_type
460 }
461 }
462 }
463
464 pub(crate) fn is_optional(&self) -> bool {
465 self.typ.is_optional()
466 }
467}
468
469#[derive(Debug, Clone, PartialEq)]
471pub enum ParamValue {
472 Dataset(Dataset),
474 Duration(RelativeTime),
476 String(String),
478 Int(i64),
480 Float(f64),
482 Bool(bool),
484 Regex(EncodableRegex),
486}
487
488impl ParamValue {
489 #[must_use]
491 pub fn typ(&self) -> TerminalParamType {
492 match self {
493 ParamValue::Dataset(_) => TerminalParamType::Dataset,
494 ParamValue::Duration(_) => TerminalParamType::Duration,
495 ParamValue::Regex(_) => TerminalParamType::Regex,
496 ParamValue::String(_) => TerminalParamType::Tag(TagType::String),
497 ParamValue::Int(_) => TerminalParamType::Tag(TagType::Int),
498 ParamValue::Float(_) => TerminalParamType::Tag(TagType::Float),
499 ParamValue::Bool(_) => TerminalParamType::Tag(TagType::Bool),
500 }
501 }
502}
503
504#[derive(Debug, Clone, PartialEq)]
506pub struct ProvidedParam {
507 pub name: String,
509 pub value: ParamValue,
511}
512
513impl ProvidedParam {
514 pub fn new(name: impl Into<String>, value: ParamValue) -> Self {
516 Self {
517 name: name.into(),
518 value,
519 }
520 }
521}
522
523#[derive(Debug, Clone, Default)]
525pub struct ProvidedParams {
526 inner: Vec<ProvidedParam>,
527}
528
529#[derive(Debug, thiserror::Error)]
531pub enum ResolveError {
532 #[error("Param ${0} was not provided to the query")]
534 ParamNotProvided(String),
535 #[error(
537 "Param ${name} is defined as `{defined}`, but was used in a context that expected one of: {}",
538 expected.iter().map(ToString::to_string).collect::<Vec<_>>().join(", ")
539 )]
540 InvalidType {
541 name: String,
543 defined: TerminalParamType,
545 expected: Vec<TerminalParamType>,
547 },
548 #[error("Shared string error: {0}")]
550 SharedString(#[from] strumbra::Error),
551}
552
553#[derive(Debug, thiserror::Error)]
555pub enum ParseProvidedParamsError {
556 #[error("Failed to parse the value for ${param_name} as {expected_type}: {err}")]
558 ParseParam {
559 param_name: String,
561 expected_type: ParamType,
563 err: ParseParamError,
565 },
566 #[error("These params were provided more than once: {}", .0.join(", "))]
568 ParamsProvidedMoreThanOnce(Vec<String>),
569 #[error("The following params were declared but not provided: {}", .0.join(", "))]
571 ParamsDeclaredButNotProvided(Vec<String>),
572 #[error("The number of params provided exceeds the upper limit of {0}")]
574 TooManyParamsProvided(usize),
575}
576#[derive(Debug)]
578pub enum WarningReason {
579 ParamNotDeclared(Vec<String>),
581 ParamUsingSystemPrefix {
583 param: String,
585 },
586 OldDuration,
588}
589
590impl Display for WarningReason {
591 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
592 match self {
593 WarningReason::ParamNotDeclared(items) => write!(
594 f,
595 "These params were provided but not declared: {}",
596 items.join(", ")
597 ),
598 WarningReason::OldDuration => {
599 write!(f, "`duration` is depricated, please ues `Duration`")
600 }
601 WarningReason::ParamUsingSystemPrefix { param } => {
602 write!(
603 f,
604 "The param ${param} uses the `__` prefix reserved for system params"
605 )
606 }
607 }
608 }
609}
610
611#[derive(Debug)]
613pub struct Warning {
614 source: Option<SourceSpan>,
615 warning: WarningReason,
616}
617
618impl Warning {
619 #[must_use]
621 pub fn warning(&self) -> &WarningReason {
622 &self.warning
623 }
624 #[must_use]
626 pub fn source(&self) -> Option<SourceSpan> {
627 self.source
628 }
629}
630
631#[derive(Debug, Default)]
633pub struct Warnings {
634 inner: Vec<Warning>,
635}
636
637impl Warnings {
638 #[must_use]
640 pub fn new() -> Self {
641 Self::default()
642 }
643
644 pub fn push(&mut self, warning: WarningReason) {
646 self.inner.push(Warning {
647 source: None,
648 warning,
649 });
650 }
651 pub fn push_span(&mut self, span: SourceSpan, warning: WarningReason) {
653 self.inner.push(Warning {
654 source: Some(span),
655 warning,
656 });
657 }
658
659 #[must_use]
661 pub fn is_empty(&self) -> bool {
662 self.inner.is_empty()
663 }
664
665 #[must_use]
667 pub fn as_slice(&self) -> &[Warning] {
668 &self.inner
669 }
670
671 #[must_use]
673 pub fn into_vec(self) -> Vec<Warning> {
674 self.inner
675 }
676}
677
678impl ProvidedParams {
679 #[must_use]
681 pub fn new(inner: Vec<ProvidedParam>) -> Self {
682 Self { inner }
683 }
684
685 pub fn parse_and_validate(
689 mpl_params: &Params,
690 query_params: &[(String, String)],
691 ) -> Result<(Self, Warnings), ParseProvidedParamsError> {
692 const PREFIX: &str = "param__";
693 const PARAM_COUNT_LIMIT: usize = 128;
694
695 let mut warnings = Warnings::new();
696 let mut defined_more_than_once = HashSet::new();
697 let mut provided_but_not_declared = HashSet::new();
698 let mut seen = HashSet::new();
699
700 let params = query_params
701 .iter()
702 .filter_map(|(name, value)| {
703 if !name.starts_with(PREFIX) {
704 return None;
705 }
706 let name = name.trim_start_matches(PREFIX);
707 if name.is_empty() {
708 return None;
709 }
710
711 Some((name, value))
712 })
713 .take(PARAM_COUNT_LIMIT + 1)
714 .collect::<Vec<(&str, &String)>>();
715
716 if params.len() > PARAM_COUNT_LIMIT {
718 return Err(ParseProvidedParamsError::TooManyParamsProvided(
719 PARAM_COUNT_LIMIT,
720 ));
721 }
722
723 let mut provided_params = Vec::new();
724 for (name, value) in params {
725 if seen.contains(name) {
726 defined_more_than_once.insert(name);
728 continue;
729 }
730 seen.insert(name);
731
732 let Some(mpl_param) = mpl_params.iter().find(|p| p.name == name) else {
734 provided_but_not_declared.insert(name);
735 continue;
736 };
737
738 let parsed = MPLParser::parse(Rule::param_value, value).map_err(|err| {
740 ParseProvidedParamsError::ParseParam {
741 param_name: name.to_string(),
742 expected_type: mpl_param.typ,
743 err: ParseParamError::Parse(ParseError::from(err)),
744 }
745 })?;
746
747 let value = parser::parse_param_value(mpl_param, parsed).map_err(|err| {
749 ParseProvidedParamsError::ParseParam {
750 param_name: name.to_string(),
751 expected_type: mpl_param.typ,
752 err,
753 }
754 })?;
755
756 provided_params.push(ProvidedParam {
757 name: name.to_string(),
758 value,
759 });
760 }
761
762 if !provided_but_not_declared.is_empty() {
763 let mut items = provided_but_not_declared
765 .into_iter()
766 .map(|p| format!("${p}"))
767 .collect::<Vec<String>>();
768 items.sort();
769
770 warnings.push(WarningReason::ParamNotDeclared(items));
772 }
773
774 if !defined_more_than_once.is_empty() {
775 let mut items = defined_more_than_once
777 .into_iter()
778 .map(String::from)
779 .collect::<Vec<String>>();
780 items.sort();
781
782 return Err(ParseProvidedParamsError::ParamsProvidedMoreThanOnce(items));
783 }
784
785 let declared_param_names = mpl_params
786 .iter()
787 .filter_map(|p| {
788 if p.typ.is_optional() {
790 None
791 } else {
792 Some(p.name.as_str())
793 }
794 })
795 .collect::<HashSet<&str>>();
796 let declared_but_not_provided = declared_param_names
797 .difference(&seen)
798 .collect::<Vec<&&str>>();
799 if !declared_but_not_provided.is_empty() {
800 let mut items = declared_but_not_provided
802 .into_iter()
803 .map(|s| String::from(*s))
804 .collect::<Vec<String>>();
805 items.sort();
806
807 return Err(ParseProvidedParamsError::ParamsDeclaredButNotProvided(
808 items,
809 ));
810 }
811
812 Ok((ProvidedParams::new(provided_params), warnings))
813 }
814
815 #[must_use]
817 pub fn as_slice(&self) -> &[ProvidedParam] {
818 self.inner.as_slice()
819 }
820
821 fn get_param(&self, name: &str) -> Result<&ProvidedParam, ResolveError> {
822 self.inner
823 .iter()
824 .find(|p| p.name == name)
825 .ok_or(ResolveError::ParamNotProvided(name.to_string()))
826 }
827
828 pub fn resolve_tag_value(&self, pv: Parameterized<TagValue>) -> Result<TagValue, ResolveError> {
830 let param = match pv {
831 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
833 };
834
835 let provided_param = self.get_param(¶m.name)?;
836 match &provided_param.value {
837 ParamValue::String(val) => Ok(TagValue::String(SharedString::try_from(val)?)),
838 ParamValue::Int(val) => Ok(TagValue::Int(*val)),
839 ParamValue::Float(val) => Ok(TagValue::Float(*val)),
840 ParamValue::Bool(val) => Ok(TagValue::Bool(*val)),
841 val => Err(ResolveError::InvalidType {
842 name: param.name,
843 defined: val.typ(),
844 expected: vec![
845 TerminalParamType::Tag(TagType::String),
846 TerminalParamType::Tag(TagType::Int),
847 TerminalParamType::Tag(TagType::Float),
848 TerminalParamType::Tag(TagType::Bool),
849 ],
850 }),
851 }
852 }
853
854 pub fn resolve_dataset(&self, pv: Parameterized<Dataset>) -> Result<Dataset, ResolveError> {
856 let param = match pv {
857 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
859 };
860
861 let provided_param = self.get_param(¶m.name)?;
862 match &provided_param.value {
863 ParamValue::Dataset(dataset) => Ok(dataset.clone()),
864 val => Err(ResolveError::InvalidType {
865 name: param.name,
866 defined: val.typ(),
867 expected: vec![TerminalParamType::Dataset],
868 }),
869 }
870 }
871
872 pub fn resolve_relative_time(
874 &self,
875 pv: Parameterized<RelativeTime>,
876 ) -> Result<RelativeTime, ResolveError> {
877 let param = match pv {
878 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
880 };
881
882 let provided_param = self.get_param(¶m.name)?;
883 match &provided_param.value {
884 ParamValue::Duration(relative_time) => Ok(relative_time.clone()),
885 val => Err(ResolveError::InvalidType {
886 name: param.name,
887 defined: val.typ(),
888 expected: vec![TerminalParamType::Duration],
889 }),
890 }
891 }
892
893 pub fn resolve_regex(
895 &self,
896 pv: Parameterized<EncodableRegex>,
897 ) -> Result<EncodableRegex, ResolveError> {
898 let param = match pv {
899 Parameterized::Concrete(val) => return Ok(val), Parameterized::Param { span: _, param } => param,
901 };
902
903 let provided_param = self.get_param(¶m.name)?;
904 match &provided_param.value {
905 ParamValue::Regex(re) => Ok(re.clone()),
906 val => Err(ResolveError::InvalidType {
907 name: param.name,
908 defined: val.typ(),
909 expected: vec![TerminalParamType::Regex],
910 }),
911 }
912 }
913 #[must_use]
915 pub fn contains(&self, param: &str) -> bool {
916 self.get_param(param).is_ok()
917 }
918
919 #[must_use]
924 pub fn active_filter<'a>(&self, filter: &'a FilterOrIfDef) -> Option<&'a Filter> {
925 match filter {
926 FilterOrIfDef::Filter(filter) => Some(filter),
927 FilterOrIfDef::Ifdef { param, filter } if self.contains(¶m.name) => Some(filter),
928 FilterOrIfDef::Ifdef { .. } => None,
929 }
930 }
931
932 #[must_use]
934 pub fn active_filters<'a>(&self, filters: &'a [FilterOrIfDef]) -> Vec<&'a Filter> {
935 filters
936 .iter()
937 .filter_map(|filter| self.active_filter(filter))
938 .collect()
939 }
940}
941
942#[cfg_attr(feature = "wasm", tsify::declare)]
944pub type Params = Vec<ParamDeclaration>;
945
946#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
948#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
949#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
950pub enum Query {
951 Simple {
953 source: Source,
955 filters: Vec<FilterOrIfDef>,
957 aggregates: Vec<Aggregate>,
959 directives: Directives,
961 params: Params,
963 sample: Option<f64>,
965 },
966 Compute {
968 left: Box<Query>,
970 right: Box<Query>,
972 name: Metric,
974 op: ComputeFunction,
976 aggregates: Vec<Aggregate>,
978 directives: Directives,
980 params: Params,
982 },
983}
984
985impl Query {
986 #[must_use]
988 pub fn time_range(&self) -> Option<&TimeRange> {
989 match self {
990 Query::Simple { source, .. } => source.time(),
991 Query::Compute { left, .. } => left.time_range(),
992 }
993 }
994 #[must_use]
996 pub fn params(&self) -> &Params {
997 match self {
998 Query::Simple { params, .. } | Query::Compute { params, .. } => params,
999 }
1000 }
1001 #[must_use]
1003 pub fn directives(&self) -> &Directives {
1004 match self {
1005 Query::Simple { directives, .. } | Query::Compute { directives, .. } => directives,
1006 }
1007 }
1008}
1009
1010impl RelativeTime {
1011 pub fn to_duration(&self) -> Result<Duration, TimeError> {
1013 let v = i64::try_from(self.value).map_err(TimeError::InvalidDuration)?;
1014 Ok(match self.unit {
1015 TimeUnit::Millisecond => Duration::milliseconds(v),
1016 TimeUnit::Second => Duration::seconds(v),
1017 TimeUnit::Minute => Duration::minutes(v),
1018 TimeUnit::Hour => Duration::hours(v),
1019 TimeUnit::Day => Duration::days(v),
1020 TimeUnit::Week => Duration::weeks(v),
1021 TimeUnit::Month => Duration::days(v.saturating_mul(30)),
1022 TimeUnit::Year => Duration::days(v.saturating_mul(365)),
1023 })
1024 }
1025
1026 pub fn to_resolution(&self) -> Result<Resolution, ResolutionError> {
1028 match self.unit {
1029 TimeUnit::Millisecond => Resolution::secs(self.value / 1000),
1030 TimeUnit::Second => Resolution::secs(self.value),
1031 TimeUnit::Minute => Resolution::secs(self.value.saturating_mul(60)),
1032 TimeUnit::Hour => Resolution::secs(self.value.saturating_mul(60 * 60)),
1033 TimeUnit::Day => Resolution::secs(self.value.saturating_mul(60 * 60 * 24)),
1034 TimeUnit::Week => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 7)),
1035 TimeUnit::Month => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 30)),
1036 TimeUnit::Year => Resolution::secs(self.value.saturating_mul(60 * 60 * 24 * 365)),
1037 }
1038 }
1039}
1040
1041#[derive(Debug, thiserror::Error)]
1043pub enum TimeError {
1044 #[error("Invalid timestamp {0}, could not be converted to a UTC datetime")]
1046 InvalidTimestamp(i64),
1047 #[error(
1049 "Invalid duration {0}, could not be converted to Duration as it exceeds the maximum i64"
1050 )]
1051 InvalidDuration(TryFromIntError),
1052}
1053#[cfg(feature = "clock")]
1054impl Time {
1055 fn to_datetime(&self) -> Result<DateTime<Utc>, TimeError> {
1056 Ok(match self {
1057 Time::Relative(t) => Utc::now() - t.to_duration()?,
1058 Time::Timestamp(ts) => {
1059 DateTime::<Utc>::from_timestamp(*ts, 0).ok_or(TimeError::InvalidTimestamp(*ts))?
1060 }
1061 Time::RFC3339(t) => t.with_timezone(&Utc),
1062 Time::Modifier(_) => todo!(),
1063 })
1064 }
1065}
1066
1067#[cfg(feature = "clock")]
1068impl TimeRange {
1069 pub fn to_start_end(&self) -> Result<(DateTime<Utc>, DateTime<Utc>), TimeError> {
1071 let start = self.start.to_datetime()?;
1072 let end = self
1073 .end
1074 .as_ref()
1075 .map_or_else(|| Ok(Utc::now()), Time::to_datetime)?;
1076 Ok((start, end))
1077 }
1078}