diff --git a/src/query/fns/label.rs b/src/query/fns/label.rs index 15b0e28d2323c5e22bae65d83ef08f0ea8daf786..6caa4bc0e37f66f638b71b0629ce08db2f8e52c2 100644 --- a/src/query/fns/label.rs +++ b/src/query/fns/label.rs @@ -7,6 +7,15 @@ use crate::query::{ ops::Operable, }; +/// MetricsQL's label_set label manipulation query function +#[inline] +pub fn mql_label_set<'a>( + qry_expr: impl Operable + 'a, + label_value_pairs: &'a [&'a str], +) -> QryFunc<impl Fn(&mut fmt::Formatter) -> fmt::Result + 'a> { + basic_label_fn("label_set", qry_expr, label_value_pairs) +} + /// MetricsQL's label_map query function pub fn mql_label_map<'a>( qry_expr: impl Operable + 'a, @@ -111,4 +120,10 @@ mod tests { r#"sort_by_label_numeric_desc(metric,"label","label2")"# ); } + + #[test] + fn label_label_set() { + let qry = mql_label_set(Metric::new("metric"), &["label", "value"]).to_string(); + assert_eq!(qry, r#"label_set(metric,"label","value")"#); + } } diff --git a/src/query/fns/rollup.rs b/src/query/fns/rollup.rs index 29b0f26c02b7329b9da1891b9d2b7f40b6713cc3..6565e8a065da152367f83caad79b4d7120779a89 100644 --- a/src/query/fns/rollup.rs +++ b/src/query/fns/rollup.rs @@ -4,6 +4,12 @@ use crate::query::ops::Operable; use super::{basic_fn, qry_fn, QryFunc}; +/// The timestamp rollup query function +#[inline] +pub fn timestamp(range_vec: impl Operable) -> QryFunc<impl Fn(&mut fmt::Formatter) -> fmt::Result> { + basic_fn("timestamp", range_vec) +} + /// The avg_over_time rollup query function #[inline] pub fn avg_over_time( @@ -150,4 +156,10 @@ mod tests { let string = last_over_time(test_metric()).to_string(); assert_eq!(string, "last_over_time(test_metric[15d])"); } + + #[test] + fn rollup_timestamp() { + let string = timestamp(test_metric()).to_string(); + assert_eq!(string, "timestamp(test_metric[15d])"); + } } diff --git a/src/query/mod.rs b/src/query/mod.rs index 8f463aa10c4423a3603f54f7bb3745973432a241..75bc237b7c23aca1d7b9a6d6d0b6304d85f6feb2 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -3,11 +3,12 @@ //! [`Metric`] and [`Scalar`] are the basic types used for building queries. //! For building complex queries involving operators, see module [`ops`]. -use std::fmt::Display; - +use self::ops::Operable; use crate::seal::Sealed; +use std::fmt::Display; -use self::ops::Operable; +#[cfg(feature = "metricsql")] +use ops::modifiers::KeepNames; pub mod fns; pub mod ops; @@ -450,6 +451,14 @@ pub trait QueryExt: Operable { { SubQry::new(self, dur) } + + #[cfg(feature = "metricsql")] + fn keep_metric_names(self) -> KeepNames<Self> + where + Self: Sized, + { + KeepNames(self) + } } impl<T: Operable> QueryExt for T {} diff --git a/src/query/ops/modifiers.rs b/src/query/ops/modifiers.rs index 6cd40966957d70c4ad5228411d9f3cb52a8bb5f9..e9b2ae7f5585a40d2cf60db7759cdd19cab98db1 100644 --- a/src/query/ops/modifiers.rs +++ b/src/query/ops/modifiers.rs @@ -1,5 +1,9 @@ use std::fmt::Display; +use crate::{query::IntoQuery, seal::Sealed}; + +use super::Operable; + #[derive(Debug, Clone, Default)] pub(crate) struct Mod<'a, M> { mod_type: M, @@ -114,3 +118,42 @@ impl Display for Mod<'_, AggrType> { Ok(()) } } + +/// MetricsQL's `keep_metric_names` modifier +/// +/// This modifier can only be applied using the `keep_metric_names` method made available by the [`QueryExt`](crate::query::QueryExt) trait. +#[cfg(feature = "metricsql")] +#[derive(Debug, Clone)] +pub struct KeepNames<E: Operable>(pub(crate) E); + +#[cfg(feature = "metricsql")] +impl<E: Operable> Display for KeepNames<E> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{exp} keep_metric_names", exp = self.0) + } +} + +#[cfg(feature = "metricsql")] +impl<E: Operable> Sealed for KeepNames<E> {} +#[cfg(feature = "metricsql")] +impl<E: Operable> Operable for KeepNames<E> {} + +#[cfg(feature = "metricsql")] +impl<E: Operable> IntoQuery for KeepNames<E> { + type Target = String; + fn into_query(self) -> Self::Target { + self.to_string() + } +} + +#[cfg(test)] +mod tests { + use crate::query::{Metric, QueryExt}; + + #[cfg(feature = "metricsql")] + #[test] + fn keep_names() { + let qry = Metric::new("metric").keep_metric_names(); + assert_eq!(qry.to_string(), "metric keep_metric_names"); + } +} diff --git a/tests/fns.rs b/tests/fns.rs index f63681a056bca6f17ebfaf0c1728b07992d38e4d..c81ceb02109f943bec4460ca983818de752862b6 100644 --- a/tests/fns.rs +++ b/tests/fns.rs @@ -83,7 +83,8 @@ rollup_tests!( stddev_over_time, stdvar_over_time, present_over_time, - last_over_time + last_over_time, + timestamp ); #[tokio::test] @@ -108,6 +109,7 @@ async fn mql_label_map() { #[cfg(feature = "metricsql")] label_tests!( + mql_label_set, mql_sort_by_label, mql_sort_by_label_desc, mql_sort_by_label_numeric, diff --git a/tests/operators.rs b/tests/operators.rs index a27ce155e8ed9b0822264b2a84d99a1a18b3d825..9813aaa2df25331951285a0a2a7042b0934e890d 100644 --- a/tests/operators.rs +++ b/tests/operators.rs @@ -1,6 +1,6 @@ use mquery::query::{ ops::{Arithmetic, Comparison, Logical}, - Metric, Scalar, + Metric, QueryExt, Scalar, }; mod utils; @@ -89,3 +89,12 @@ async fn logical_set() { .unless(Metric::new("fourth_metric")); utils::send_query(query).await.unwrap(); } + +#[cfg(feature = "metricsql")] +#[tokio::test] +async fn keep_metric_names_mod() { + let query = Metric::new("metric") + .add(Metric::new("metric2")) + .keep_metric_names(); + utils::send_query(query).await.unwrap(); +}