From 5dc549387b572cf346ab4e7d0a3a168860ad60ab Mon Sep 17 00:00:00 2001 From: Maaz Ahmed <maaz.a@subcom.tech> Date: Fri, 15 Dec 2023 11:46:08 +0530 Subject: [PATCH] refactor: replace external PromqlResult type with internal Data type This removes the need for the user to import types from the `prometheus-http-query` crate where type annotations are required. These changes also ensure that the public API of mquery remains more stable, as it is decoupled from the external types. --- Cargo.lock | 1 + Cargo.toml | 1 + src/lib.rs | 15 ++++++++------- src/result.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- tests/utils.rs | 5 ++--- 5 files changed, 59 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75bf526..0400103 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -443,6 +443,7 @@ name = "mquery" version = "0.2.0" dependencies = [ "dotenv", + "enum-as-inner", "prometheus-http-query", "reqwest", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 3bdc678..08fef24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +enum-as-inner = "0.6.0" prometheus-http-query = "0.8.0" reqwest = "0.11.22" url = "2.5.0" diff --git a/src/lib.rs b/src/lib.rs index dbefb59..44c6480 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,10 @@ pub mod query; pub mod result; -use prometheus_http_query::{response::PromqlResult, Client}; +use prometheus_http_query::Client; use query::IntoQuery; use reqwest::header::HeaderValue; +use result::{IntoQryResult, QryResult}; use url::Url; /// The primary way to send queries and get deserialized responses from the metrics server @@ -66,7 +67,7 @@ impl QueryManager { /// The trait is implemented for `&str`, `String`, `&String`, and __mquery's__ /// internal types such as [`query::Metric`], [`query::Scalar`] and others that result /// from the query builder API. - pub async fn query<Q: IntoQuery>(&self, query: Q) -> Result<PromqlResult, result::Error> { + pub async fn query<Q: IntoQuery>(&self, query: Q) -> QryResult { let mut builder = self.client.query(query.into_query().as_ref()); if let Some((name, val)) = self.auth.get_header() { builder = builder.header(name, val); @@ -75,8 +76,8 @@ impl QueryManager { builder = builder.timeout(*timeout); } match self.method { - Method::Get => builder.get().await.map_err(|e| e.into()), - Method::Post => builder.post().await.map_err(|e| e.into()), + Method::Get => builder.get().await.into_qry_result(), + Method::Post => builder.post().await.into_qry_result(), } } @@ -92,7 +93,7 @@ impl QueryManager { start: i64, end: i64, step: f64, - ) -> Result<PromqlResult, result::Error> { + ) -> QryResult { let mut builder = self .client .query_range(query.into_query().as_ref(), start, end, step); @@ -103,8 +104,8 @@ impl QueryManager { builder = builder.timeout(*timeout); } match self.method { - Method::Get => builder.get().await.map_err(|e| e.into()), - Method::Post => builder.post().await.map_err(|e| e.into()), + Method::Get => builder.get().await.into_qry_result(), + Method::Post => builder.post().await.into_qry_result(), } } } diff --git a/src/result.rs b/src/result.rs index fac15e8..949d5ad 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,14 +1,58 @@ -//! `PromqlResult` and the `Error` types which are essentially clones of the types +//! `Data` and the `Error` types which are essentially clones of the types //! with the same name from the `prometheus-http-query` crate with slight modifications //! to suit the needs of `mqeury`. //! -//! The reason why this crate maintains its own types which are the same (almost) as the ones +//! Another reason why this crate maintains its own types which are the same (almost) as the ones //! provided by the other crate that is used internally, is to ensure that the public //! API remains stable even if the internal crate API changes. -use prometheus_http_query::error; +use enum_as_inner::EnumAsInner; +use prometheus_http_query::{error, response}; use std::fmt::{self, Display}; +pub type QryResult = std::result::Result<Data, Error>; + +/// Internal trait used for converting the `prometheus-http-query` crate's query result into the internal result type +pub(crate) trait IntoQryResult { + fn into_qry_result(self) -> QryResult; +} + +impl IntoQryResult for Result<response::PromqlResult, error::Error> { + fn into_qry_result(self) -> QryResult { + self.map(|r| r.into()).map_err(|e| e.into()) + } +} + +/// A wrapper for possible result types of expression queries ([`Client::query`](crate::Client::query) and [`Client::query_range`](crate::Client::query_range)). +#[derive(Clone, Debug, EnumAsInner)] +pub enum Data { + Vector(Vec<response::InstantVector>), + Matrix(Vec<response::RangeVector>), + Scalar(response::Sample), +} + +impl From<response::PromqlResult> for Data { + fn from(value: response::PromqlResult) -> Self { + let (data, _) = value.into_inner(); + match data { + response::Data::Vector(v) => Data::Vector(v), + response::Data::Matrix(m) => Data::Matrix(m), + response::Data::Scalar(s) => Data::Scalar(s), + } + } +} + +impl Data { + /// This is a shortcut to check if the query returned any data at all regardless of the exact type. + pub fn is_empty(&self) -> bool { + match self { + Data::Vector(v) => v.is_empty(), + Data::Matrix(v) => v.is_empty(), + Data::Scalar(_) => false, + } + } +} + /// A global error enum that contains all errors that are returned by this /// library. Some errors are wrappers for errors from underlying libraries. /// All errors (this enum as well as all contained structs) implement [`std::error::Error`]. diff --git a/tests/utils.rs b/tests/utils.rs index 12303de..e686901 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -1,9 +1,8 @@ -use mquery::{query::IntoQuery, QueryManager}; -use prometheus_http_query::response::PromqlResult; +use mquery::{query::IntoQuery, result::QryResult, QueryManager}; // local victoria metrics server pub static URL: &str = "http://localhost:8428"; -pub async fn send_query(query: impl IntoQuery) -> Result<PromqlResult, mquery::result::Error> { +pub async fn send_query(query: impl IntoQuery) -> QryResult { QueryManager::new(URL.parse().unwrap()).query(query).await } -- GitLab