From 9d2e3b3803112ab36af486281b72764cfbd358fb Mon Sep 17 00:00:00 2001
From: Maaz Ahmed <maaz.a@subcom.tech>
Date: Mon, 8 Jan 2024 15:03:56 +0530
Subject: [PATCH] feat: keep_metric_names modifier

---
 src/query/mod.rs           | 15 ++++++++++---
 src/query/ops/modifiers.rs | 43 ++++++++++++++++++++++++++++++++++++++
 tests/operators.rs         | 11 +++++++++-
 3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/src/query/mod.rs b/src/query/mod.rs
index 8f463aa..75bc237 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 6cd4096..e9b2ae7 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/operators.rs b/tests/operators.rs
index a27ce15..9813aaa 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();
+}
-- 
GitLab