diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 141ad20..c6ecc1f 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -43,7 +43,6 @@ use std::time::{Duration, SystemTime}; /// /// if empty listed labels, meaning no grouping #[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ser", derive(serde::Serialize))] pub enum LabelModifier { Include(Labels), Exclude(Labels), @@ -200,6 +199,34 @@ impl BinModifier { } } +#[cfg(feature = "ser")] +pub(crate) fn serialize_grouping( + this: &Option, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(2))?; + match this { + Some(LabelModifier::Include(l)) => { + map.serialize_entry("grouping", l)?; + map.serialize_entry("without", &false)?; + } + Some(LabelModifier::Exclude(l)) => { + map.serialize_entry("grouping", l)?; + map.serialize_entry("without", &true)?; + } + None => { + map.serialize_entry("grouping", &(vec![] as Vec))?; + map.serialize_entry("without", &false)?; + } + } + + map.end() +} + #[cfg(feature = "ser")] pub(crate) fn serialize_bin_modifier( this: &Option, @@ -257,6 +284,44 @@ where map.end() } +#[cfg(feature = "ser")] +pub(crate) fn serialize_at_modifier( + this: &Option, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(2))?; + match this { + Some(AtModifier::Start) => { + map.serialize_entry("startOrEnd", &Some("start"))?; + map.serialize_entry("timestamp", &None::)?; + } + Some(AtModifier::End) => { + map.serialize_entry("startOrEnd", &Some("end"))?; + map.serialize_entry("timestamp", &None::)?; + } + Some(AtModifier::At(time)) => { + map.serialize_entry("startOrEnd", &None::<&str>)?; + map.serialize_entry( + "timestamp", + &time + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap_or(Duration::ZERO) + .as_millis(), + )?; + } + None => { + map.serialize_entry("startOrEnd", &None::<&str>)?; + map.serialize_entry("timestamp", &None::)?; + } + } + + map.end() +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Offset { Pos(Duration), @@ -317,39 +382,6 @@ impl fmt::Display for AtModifier { } } -#[cfg(feature = "ser")] -impl serde::Serialize for AtModifier { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeMap; - let mut map = serializer.serialize_map(Some(2))?; - match self { - AtModifier::Start => { - map.serialize_entry("startOrEnd", &Some("start"))?; - map.serialize_entry("timestamp", &None::)?; - } - AtModifier::End => { - map.serialize_entry("startOrEnd", &Some("end"))?; - map.serialize_entry("timestamp", &None::)?; - } - AtModifier::At(time) => { - map.serialize_entry("startOrEnd", &None::<&str>)?; - map.serialize_entry( - "timestamp", - &time - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or(Duration::ZERO) - .as_millis(), - )?; - } - } - - map.end() - } -} - impl TryFrom for AtModifier { type Error = String; @@ -465,6 +497,8 @@ pub struct AggregateExpr { /// Parameter used by some aggregators. pub param: Option>, /// modifier is optional for some aggregation operators, like sum. + #[cfg_attr(feature = "ser", serde(flatten))] + #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_grouping"))] pub modifier: Option, } @@ -658,6 +692,7 @@ pub struct SubqueryExpr { #[cfg_attr(feature = "ser", serde(serialize_with = "Offset::serialize_offset"))] pub offset: Option, #[cfg_attr(feature = "ser", serde(flatten))] + #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_at_modifier"))] pub at: Option, #[cfg_attr( feature = "ser", @@ -797,6 +832,7 @@ pub struct VectorSelector { #[cfg_attr(feature = "ser", serde(serialize_with = "Offset::serialize_offset"))] pub offset: Option, #[cfg_attr(feature = "ser", serde(flatten))] + #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_at_modifier"))] pub at: Option, } @@ -1030,7 +1066,7 @@ impl Eq for Extension {} #[cfg_attr(feature = "ser", serde(tag = "type", rename_all = "camelCase"))] pub enum Expr { /// Aggregate represents an aggregation operation on a Vector. - #[cfg_attr(feature = "ser", serde(rename = "aggregateExpr"))] + #[cfg_attr(feature = "ser", serde(rename = "aggregation"))] Aggregate(AggregateExpr), /// Unary represents a unary operation on another expression. diff --git a/tests/ser.rs b/tests/ser.rs index b7346e2..d3ea9a9 100644 --- a/tests/ser.rs +++ b/tests/ser.rs @@ -35,7 +35,9 @@ fn test_serialize() { "matchers": [], "name": "prometheus_tsdb_wal_writes_failed_total", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }); assert_json_ser_eq!( @@ -51,7 +53,9 @@ fn test_serialize() { ], "name": "prometheus_tsdb_wal_writes_failed_total", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null } ); @@ -68,7 +72,9 @@ fn test_serialize() { ], "name": "prometheus_tsdb_wal_writes_failed_total", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }); assert_json_ser_eq!( @@ -84,7 +90,9 @@ fn test_serialize() { ], "name": "prometheus_tsdb_wal_writes_failed_total", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }); assert_json_ser_eq!( @@ -139,7 +147,9 @@ fn test_serialize() { "name": "prometheus_tsdb_wal_writes_failed_total", "offset": 0, "range": 60000, - "type": "matrixSelector" + "type": "matrixSelector", + "startOrEnd": null, + "timestamp": null } ], "func": { @@ -192,7 +202,9 @@ fn test_serialize() { "matchers": [], "name": "process_cpu_seconds_total", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "op": "-", "type": "unaryExpr" @@ -224,7 +236,9 @@ fn test_serialize() { ], "name": "node_memory_MemAvailable_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "matching": { "card": "many-to-many", @@ -250,7 +264,9 @@ fn test_serialize() { ], "name": "node_memory_Buffers_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "matching": null, "op": "+", @@ -264,7 +280,9 @@ fn test_serialize() { ], "name": "node_memory_Cached_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" }, @@ -280,7 +298,9 @@ fn test_serialize() { ], "name": "node_memory_MemFree_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" }, @@ -296,7 +316,9 @@ fn test_serialize() { ], "name": "node_memory_Slab_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" }, @@ -318,7 +340,9 @@ fn test_serialize() { ], "name": "node_memory_MemTotal_bytes", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" }, @@ -335,7 +359,9 @@ fn test_serialize() { "matchers": [], "name": "foo", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "matching": { "card": "one-to-one", @@ -350,7 +376,9 @@ fn test_serialize() { "matchers": [], "name": "bar", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" }); @@ -362,7 +390,9 @@ fn test_serialize() { "matchers": [], "name": "foo", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "matching": { "card": "one-to-one", @@ -377,7 +407,9 @@ fn test_serialize() { "matchers": [], "name": "bar", "offset": 0, - "type": "vectorSelector" + "type": "vectorSelector", + "startOrEnd": null, + "timestamp": null }, "type": "binaryExpr" } @@ -394,7 +426,9 @@ fn test_serialize() { "name": "http_requests_total", "offset": 0, "range": 300000, - "type": "matrixSelector" + "type": "matrixSelector", + "startOrEnd": null, + "timestamp": null } ], "func": { @@ -410,7 +444,9 @@ fn test_serialize() { "offset": 0, "range": 1800000, "step": 60000, - "type": "subquery" + "type": "subquery", + "startOrEnd": null, + "timestamp": null } ], "func": { @@ -424,5 +460,98 @@ fn test_serialize() { "type": "call" } - ); + ); + + assert_json_ser_eq!("sum(rate(http_requests_total[5m]))", + { + "expr": { + "args": [ + { + "matchers": [], + "name": "http_requests_total", + "offset": 0, + "range": 300000, + "type": "matrixSelector", + "startOrEnd": null, + "timestamp": null + } + ], + "func": { + "argTypes": [ + "matrix" + ], + "name": "rate", + "returnType": "vector", + "variadic": 0 + }, + "type": "call" + }, + "grouping": [], + "op": "sum", + "param": null, + "type": "aggregation", + "without": false + }); + + assert_json_ser_eq!("sum by(host) (rate(http_requests_total[5m]))", + { + "expr": { + "args": [ + { + "matchers": [], + "name": "http_requests_total", + "offset": 0, + "range": 300000, + "type": "matrixSelector", + "startOrEnd": null, + "timestamp": null + } + ], + "func": { + "argTypes": [ + "matrix" + ], + "name": "rate", + "returnType": "vector", + "variadic": 0 + }, + "type": "call" + }, + "grouping": ["host"], + "op": "sum", + "param": null, + "type": "aggregation", + "without": false + }); + + assert_json_ser_eq!("sum without(host) (rate(http_requests_total[5m]))", + { + "expr": { + "args": [ + { + "matchers": [], + "name": "http_requests_total", + "offset": 0, + "range": 300000, + "type": "matrixSelector", + "startOrEnd": null, + "timestamp": null + } + ], + "func": { + "argTypes": [ + "matrix" + ], + "name": "rate", + "returnType": "vector", + "variadic": 0 + }, + "type": "call" + }, + "grouping": ["host"], + "op": "sum", + "param": null, + "type": "aggregation", + "without": true + }); }