Skip to content

Commit 06604d1

Browse files
authored
feat: fill*() binop modifiers (#135)
* feat: fill*() binop modifiers * refactor: improve parser and avoid unwrap * feat: allow fill/fill_left/fill_right as metric identifier * chore: restore test being removed * refactor: remove unneeded branch
1 parent c4bebc8 commit 06604d1

8 files changed

Lines changed: 317 additions & 27 deletions

File tree

build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ use lrlex::{ct_token_map, DefaultLexerTypes};
1717
use lrpar::CTParserBuilder;
1818

1919
fn main() -> Result<(), Box<dyn std::error::Error>> {
20-
let ctp = CTParserBuilder::<DefaultLexerTypes<u8>>::new()
20+
let ctp = CTParserBuilder::<DefaultLexerTypes<u16>>::new()
2121
.yacckind(YaccKind::Grmtools)
2222
.recoverer(lrpar::RecoveryKind::None)
2323
.grammar_in_src_dir("parser/promql.y")?
2424
.build()?;
25-
ct_token_map::<u8>("token_map", ctp.token_map(), None)
25+
ct_token_map::<u16>("token_map", ctp.token_map(), None)
2626
}

src/parser/ast.rs

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,38 @@ impl VectorMatchCardinality {
100100
}
101101
}
102102

103+
/// VectorMatchFillValues contains the fill values to use for Vector matching
104+
/// when one side does not find a match on the other side.
105+
/// When a fill value is nil, no fill is applied for that side, and there
106+
/// is no output for the match group if there is no match.
107+
#[derive(Debug, Clone, PartialEq, Default)]
108+
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
109+
pub struct VectorMatchFillValues {
110+
pub rhs: Option<f64>,
111+
pub lhs: Option<f64>,
112+
}
113+
114+
impl VectorMatchFillValues {
115+
pub fn new(lhs: f64, rhs: f64) -> Self {
116+
Self {
117+
rhs: Some(rhs),
118+
lhs: Some(lhs),
119+
}
120+
}
121+
122+
pub fn with_rhs(mut self, rhs: f64) -> Self {
123+
self.rhs = Some(rhs);
124+
self
125+
}
126+
127+
pub fn with_lhs(mut self, lhs: f64) -> Self {
128+
self.lhs = Some(lhs);
129+
self
130+
}
131+
}
132+
103133
/// Binary Expr Modifier
104-
#[derive(Debug, Clone, PartialEq, Eq)]
134+
#[derive(Debug, Clone, PartialEq)]
105135
pub struct BinModifier {
106136
/// The matching behavior for the operation if both operands are Vectors.
107137
/// If they are not this field is None.
@@ -112,6 +142,9 @@ pub struct BinModifier {
112142
pub matching: Option<LabelModifier>,
113143
/// If a comparison operator, return 0/1 rather than filtering.
114144
pub return_bool: bool,
145+
/// Fill-in values to use when a series from one side does not find a match
146+
/// on the other side.
147+
pub fill_values: VectorMatchFillValues,
115148
}
116149

117150
impl fmt::Display for BinModifier {
@@ -132,6 +165,21 @@ impl fmt::Display for BinModifier {
132165
_ => (),
133166
}
134167

168+
if self.fill_values.rhs.is_some() || self.fill_values.lhs.is_some() {
169+
if self.fill_values.rhs == self.fill_values.lhs {
170+
let fill_value = self.fill_values.rhs.unwrap();
171+
write!(s, "fill ({fill_value}) ")?;
172+
} else {
173+
if let Some(fill_value) = self.fill_values.lhs {
174+
write!(s, "fill_left ({fill_value}) ")?;
175+
}
176+
177+
if let Some(fill_value) = self.fill_values.rhs {
178+
write!(s, "fill_right ({fill_value}) ")?;
179+
}
180+
}
181+
}
182+
135183
if s.trim().is_empty() {
136184
write!(f, "")
137185
} else {
@@ -146,6 +194,7 @@ impl Default for BinModifier {
146194
card: VectorMatchCardinality::OneToOne,
147195
matching: None,
148196
return_bool: false,
197+
fill_values: VectorMatchFillValues::default(),
149198
}
150199
}
151200
}
@@ -166,6 +215,11 @@ impl BinModifier {
166215
self
167216
}
168217

218+
pub fn with_fill_values(mut self, fill_values: VectorMatchFillValues) -> Self {
219+
self.fill_values = fill_values;
220+
self
221+
}
222+
169223
pub fn is_labels_joint(&self) -> bool {
170224
matches!(
171225
(self.card.labels(), &self.matching),
@@ -255,6 +309,7 @@ where
255309
"include": [],
256310
"labels": labels,
257311
"on": true,
312+
"fillValues": t.fill_values,
258313
});
259314
map.serialize_value(&value)?;
260315
}
@@ -264,6 +319,7 @@ where
264319
"include": [],
265320
"labels": labels,
266321
"on": false,
322+
"fillValues": t.fill_values,
267323
});
268324
map.serialize_value(&value)?;
269325
}
@@ -274,6 +330,7 @@ where
274330
"include": [],
275331
"labels": [],
276332
"on": false,
333+
"fillValues": t.fill_values,
277334
});
278335
map.serialize_entry("matching", &value)?;
279336
}
@@ -322,7 +379,7 @@ where
322379
map.end()
323380
}
324381

325-
#[derive(Debug, Clone, PartialEq, Eq)]
382+
#[derive(Debug, Clone, PartialEq)]
326383
pub enum Offset {
327384
Pos(Duration),
328385
Neg(Duration),
@@ -359,7 +416,7 @@ impl fmt::Display for Offset {
359416
}
360417
}
361418

362-
#[derive(Debug, Clone, PartialEq, Eq)]
419+
#[derive(Debug, Clone, PartialEq)]
363420
pub enum AtModifier {
364421
Start,
365422
End,
@@ -487,7 +544,7 @@ impl fmt::Display for EvalStmt {
487544
/// ```
488545
///
489546
/// parameter is only required for `count_values`, `quantile`, `topk` and `bottomk`.
490-
#[derive(Debug, Clone, PartialEq, Eq)]
547+
#[derive(Debug, Clone, PartialEq)]
491548
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
492549
pub struct AggregateExpr {
493550
/// The used aggregation operation.
@@ -544,7 +601,7 @@ impl Prettier for AggregateExpr {
544601
}
545602

546603
/// UnaryExpr will negate the expr
547-
#[derive(Debug, Clone, PartialEq, Eq)]
604+
#[derive(Debug, Clone, PartialEq)]
548605
pub struct UnaryExpr {
549606
pub expr: Box<Expr>,
550607
}
@@ -587,7 +644,7 @@ impl serde::Serialize for UnaryExpr {
587644
/// <vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
588645
/// <vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
589646
/// ```
590-
#[derive(Debug, Clone, PartialEq, Eq)]
647+
#[derive(Debug, Clone, PartialEq)]
591648
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
592649
pub struct BinaryExpr {
593650
/// The operation of the expression.
@@ -658,7 +715,7 @@ impl Prettier for BinaryExpr {
658715
}
659716
}
660717

661-
#[derive(Debug, Clone, PartialEq, Eq)]
718+
#[derive(Debug, Clone, PartialEq)]
662719
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
663720
pub struct ParenExpr {
664721
pub expr: Box<Expr>,
@@ -685,7 +742,7 @@ impl Prettier for ParenExpr {
685742
/// ```norust
686743
/// <instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]
687744
/// ```
688-
#[derive(Debug, Clone, PartialEq, Eq)]
745+
#[derive(Debug, Clone, PartialEq)]
689746
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
690747
pub struct SubqueryExpr {
691748
pub expr: Box<Expr>,
@@ -805,7 +862,7 @@ impl Prettier for NumberLiteral {
805862
}
806863
}
807864

808-
#[derive(Debug, Clone, PartialEq, Eq)]
865+
#[derive(Debug, Clone, PartialEq)]
809866
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
810867
pub struct StringLiteral {
811868
pub val: String,
@@ -823,7 +880,7 @@ impl Prettier for StringLiteral {
823880
}
824881
}
825882

826-
#[derive(Debug, Clone, PartialEq, Eq)]
883+
#[derive(Debug, Clone, PartialEq)]
827884
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
828885
pub struct VectorSelector {
829886
pub name: Option<String>,
@@ -928,7 +985,7 @@ impl Prettier for VectorSelector {
928985
}
929986
}
930987

931-
#[derive(Debug, Clone, PartialEq, Eq)]
988+
#[derive(Debug, Clone, PartialEq)]
932989
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
933990
pub struct MatrixSelector {
934991
#[cfg_attr(feature = "ser", serde(flatten))]
@@ -1010,7 +1067,7 @@ impl Prettier for MatrixSelector {
10101067
/// - sinh()
10111068
/// - tan()
10121069
/// - tanh()
1013-
#[derive(Debug, Clone, PartialEq, Eq)]
1070+
#[derive(Debug, Clone, PartialEq)]
10141071
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
10151072
pub struct Call {
10161073
pub func: Function,
@@ -1061,7 +1118,7 @@ impl PartialEq for Extension {
10611118

10621119
impl Eq for Extension {}
10631120

1064-
#[derive(Debug, Clone, PartialEq, Eq)]
1121+
#[derive(Debug, Clone, PartialEq)]
10651122
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
10661123
#[cfg_attr(feature = "ser", serde(tag = "type", rename_all = "camelCase"))]
10671124
pub enum Expr {
@@ -1988,6 +2045,17 @@ mod tests {
19882045
("a - on(b) group_left c", "a - on (b) group_left () c"),
19892046
("a - ignoring(b) c", "a - ignoring (b) c"),
19902047
("a - ignoring() c", "a - c"),
2048+
("a + fill(-23) b", "a + fill (-23) b"),
2049+
("a + fill_left(-23) b", "a + fill_left (-23) b"),
2050+
("a + fill_right(42) b", "a + fill_right (42) b"),
2051+
(
2052+
"a + fill_left(-23) fill_right(42) b",
2053+
"a + fill_left (-23) fill_right (42) b",
2054+
),
2055+
(
2056+
"a + on(b) group_left fill(-23) c",
2057+
"a + on (b) group_left () fill (-23) c",
2058+
),
19912059
("up > bool 0", "up > bool 0"),
19922060
("a offset 1m", "a offset 1m"),
19932061
("a offset -7m", "a offset -7m"),

src/parser/function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::parser::{Expr, Prettier};
2222
use crate::util::join_vector;
2323

2424
/// called by func in Call
25-
#[derive(Debug, Clone, PartialEq, Eq)]
25+
#[derive(Debug, Clone, PartialEq)]
2626
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
2727
pub struct FunctionArgs {
2828
pub args: Vec<Box<Expr>>,

src/parser/lex.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,32 @@ impl Lexer {
408408
}
409409

410410
let s = self.lexeme_string();
411-
match get_keyword_token(&s.to_lowercase()) {
412-
Some(token_id) => State::Lexeme(token_id),
411+
let s_lower = s.to_lowercase();
412+
match get_keyword_token(&s_lower) {
413+
Some(token_id) => {
414+
// fill, fill_left, fill_right can be used as metric identifiers
415+
// if not followed by a left parenthesis
416+
if token_id == T_FILL || token_id == T_FILL_LEFT || token_id == T_FILL_RIGHT {
417+
// Look ahead to see if next non-whitespace char is '('
418+
let mut idx = self.ctx.idx;
419+
let mut found_lparen = false;
420+
while let Some(&ch) = self.ctx.chars.get(idx) {
421+
if ch.is_ascii_whitespace() {
422+
idx += 1;
423+
} else if ch == '(' {
424+
found_lparen = true;
425+
break;
426+
} else {
427+
break;
428+
}
429+
}
430+
if !found_lparen {
431+
// Not followed by (, treat as metric identifier
432+
return State::Lexeme(T_IDENTIFIER);
433+
}
434+
}
435+
State::Lexeme(token_id)
436+
}
413437
None if s.contains(':') => State::Lexeme(T_METRIC_IDENTIFIER),
414438
_ => State::Lexeme(T_IDENTIFIER),
415439
}
@@ -940,6 +964,72 @@ mod tests {
940964
("group_right", vec![(T_GROUP_RIGHT, 0, 11)], None),
941965
("bool", vec![(T_BOOL, 0, 4)], None),
942966
("atan2", vec![(T_ATAN2, 0, 5)], None),
967+
// fill as metric identifier (not followed by ()
968+
("fill", vec![(T_IDENTIFIER, 0, 4)], None),
969+
("fill_left", vec![(T_IDENTIFIER, 0, 9)], None),
970+
("fill_right", vec![(T_IDENTIFIER, 0, 10)], None),
971+
// fill as modifier (followed by ()
972+
(
973+
"fill(1)",
974+
vec![
975+
(T_FILL, 0, 4),
976+
(T_LEFT_PAREN, 4, 1),
977+
(T_NUMBER, 5, 1),
978+
(T_RIGHT_PAREN, 6, 1),
979+
],
980+
None,
981+
),
982+
(
983+
"fill_left(1)",
984+
vec![
985+
(T_FILL_LEFT, 0, 9),
986+
(T_LEFT_PAREN, 9, 1),
987+
(T_NUMBER, 10, 1),
988+
(T_RIGHT_PAREN, 11, 1),
989+
],
990+
None,
991+
),
992+
(
993+
"fill_right(2)",
994+
vec![
995+
(T_FILL_RIGHT, 0, 10),
996+
(T_LEFT_PAREN, 10, 1),
997+
(T_NUMBER, 11, 1),
998+
(T_RIGHT_PAREN, 12, 1),
999+
],
1000+
None,
1001+
),
1002+
// fill with whitespace before (
1003+
(
1004+
"fill (1)",
1005+
vec![
1006+
(T_FILL, 0, 4),
1007+
(T_LEFT_PAREN, 5, 1),
1008+
(T_NUMBER, 6, 1),
1009+
(T_RIGHT_PAREN, 7, 1),
1010+
],
1011+
None,
1012+
),
1013+
(
1014+
"fill_left (1)",
1015+
vec![
1016+
(T_FILL_LEFT, 0, 9),
1017+
(T_LEFT_PAREN, 10, 1),
1018+
(T_NUMBER, 11, 1),
1019+
(T_RIGHT_PAREN, 12, 1),
1020+
],
1021+
None,
1022+
),
1023+
(
1024+
"fill_right (2)",
1025+
vec![
1026+
(T_FILL_RIGHT, 0, 10),
1027+
(T_LEFT_PAREN, 11, 1),
1028+
(T_NUMBER, 12, 1),
1029+
(T_RIGHT_PAREN, 13, 1),
1030+
],
1031+
None,
1032+
),
9431033
];
9441034
assert_matches(cases);
9451035
}

src/parser/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub mod value;
3131
pub use ast::{
3232
AggregateExpr, AtModifier, BinModifier, BinaryExpr, Call, EvalStmt, Expr, Extension,
3333
LabelModifier, MatrixSelector, NumberLiteral, Offset, ParenExpr, StringLiteral, SubqueryExpr,
34-
UnaryExpr, VectorMatchCardinality, VectorSelector,
34+
UnaryExpr, VectorMatchCardinality, VectorMatchFillValues, VectorSelector,
3535
};
3636
pub use function::{Function, FunctionArgs};
3737
pub use lex::lexer;

0 commit comments

Comments
 (0)