Skip to main content

promql_parser/parser/
ast.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::label::{Labels, Matchers, METRIC_NAME};
16use crate::parser::token::{
17    self, token_display, T_BOTTOMK, T_COUNT_VALUES, T_END, T_QUANTILE, T_START, T_TOPK,
18};
19use crate::parser::token::{Token, TokenId, TokenType};
20use crate::parser::value::ValueType;
21use crate::parser::{indent, Function, FunctionArgs, Prettier, MAX_CHARACTERS_PER_LINE};
22use crate::util::{display_duration, escape_string};
23use chrono::{DateTime, Utc};
24use std::fmt::{self, Write};
25use std::ops::Neg;
26use std::sync::Arc;
27use std::time::{Duration, SystemTime};
28
29/// LabelModifier acts as
30///
31/// # Aggregation Modifier
32///
33/// - Exclude means `ignoring`
34/// - Include means `on`
35///
36/// # Vector Match Modifier
37///
38/// - Exclude means `without` removes the listed labels from the result vector,
39///   while all other labels are preserved in the output.
40///
41/// - Include means `by` does the opposite and drops labels that are not listed in the by clause,
42///   even if their label values are identical between all elements of the vector.
43///
44/// if empty listed labels, meaning no grouping
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum LabelModifier {
47    Include(Labels),
48    Exclude(Labels),
49}
50
51impl LabelModifier {
52    pub fn labels(&self) -> &Labels {
53        match self {
54            LabelModifier::Include(l) => l,
55            LabelModifier::Exclude(l) => l,
56        }
57    }
58
59    pub fn is_include(&self) -> bool {
60        matches!(*self, LabelModifier::Include(_))
61    }
62
63    pub fn include(ls: Vec<&str>) -> Self {
64        Self::Include(Labels::new(ls))
65    }
66
67    pub fn exclude(ls: Vec<&str>) -> Self {
68        Self::Exclude(Labels::new(ls))
69    }
70}
71
72/// The label list provided with the group_left or group_right modifier contains
73/// additional labels from the "one"-side to be included in the result metrics.
74#[derive(Debug, Clone, PartialEq, Eq)]
75#[cfg_attr(feature = "ser", derive(serde::Serialize))]
76#[cfg_attr(feature = "ser", serde(rename_all = "kebab-case"))]
77pub enum VectorMatchCardinality {
78    OneToOne,
79    ManyToOne(Labels),
80    OneToMany(Labels),
81    ManyToMany, // logical/set binary operators
82}
83
84impl VectorMatchCardinality {
85    pub fn labels(&self) -> Option<&Labels> {
86        match self {
87            VectorMatchCardinality::ManyToOne(l) => Some(l),
88            VectorMatchCardinality::OneToMany(l) => Some(l),
89            VectorMatchCardinality::ManyToMany => None,
90            VectorMatchCardinality::OneToOne => None,
91        }
92    }
93
94    pub fn many_to_one(ls: Vec<&str>) -> Self {
95        Self::ManyToOne(Labels::new(ls))
96    }
97
98    pub fn one_to_many(ls: Vec<&str>) -> Self {
99        Self::OneToMany(Labels::new(ls))
100    }
101}
102
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))]
109pub struct VectorMatchFillValues {
110    pub rhs: Option<f64>,
111    pub lhs: Option<f64>,
112}
113
114impl 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
133/// Binary Expr Modifier
134#[derive(Debug, Clone, PartialEq)]
135pub struct BinModifier {
136    /// The matching behavior for the operation if both operands are Vectors.
137    /// If they are not this field is None.
138    pub card: VectorMatchCardinality,
139
140    /// on/ignoring on labels.
141    /// like a + b, no match modifier is needed.
142    pub matching: Option<LabelModifier>,
143    /// If a comparison operator, return 0/1 rather than filtering.
144    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,
148}
149
150impl fmt::Display for BinModifier {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        let mut s = String::from(self.bool_str());
153
154        if let Some(matching) = &self.matching {
155            match matching {
156                LabelModifier::Include(ls) => write!(s, "on ({ls}) ")?,
157                LabelModifier::Exclude(ls) if !ls.is_empty() => write!(s, "ignoring ({ls}) ")?,
158                _ => (),
159            }
160        }
161
162        match &self.card {
163            VectorMatchCardinality::ManyToOne(ls) => write!(s, "group_left ({ls}) ")?,
164            VectorMatchCardinality::OneToMany(ls) => write!(s, "group_right ({ls}) ")?,
165            _ => (),
166        }
167
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
183        if s.trim().is_empty() {
184            write!(f, "")
185        } else {
186            write!(f, " {}", s.trim_end()) // there is a leading space here
187        }
188    }
189}
190
191impl Default for BinModifier {
192    fn default() -> Self {
193        Self {
194            card: VectorMatchCardinality::OneToOne,
195            matching: None,
196            return_bool: false,
197            fill_values: VectorMatchFillValues::default(),
198        }
199    }
200}
201
202impl BinModifier {
203    pub fn with_card(mut self, card: VectorMatchCardinality) -> Self {
204        self.card = card;
205        self
206    }
207
208    pub fn with_matching(mut self, matching: Option<LabelModifier>) -> Self {
209        self.matching = matching;
210        self
211    }
212
213    pub fn with_return_bool(mut self, return_bool: bool) -> Self {
214        self.return_bool = return_bool;
215        self
216    }
217
218    pub fn with_fill_values(mut self, fill_values: VectorMatchFillValues) -> Self {
219        self.fill_values = fill_values;
220        self
221    }
222
223    pub fn is_labels_joint(&self) -> bool {
224        matches!(
225            (self.card.labels(), &self.matching),
226            (Some(labels), Some(matching)) if labels.is_joint(matching.labels())
227        )
228    }
229
230    pub fn intersect_labels(&self) -> Option<Vec<String>> {
231        if let Some(labels) = self.card.labels() {
232            if let Some(matching) = &self.matching {
233                return Some(labels.intersect(matching.labels()).labels);
234            }
235        };
236        None
237    }
238
239    pub fn is_matching_on(&self) -> bool {
240        matches!(&self.matching, Some(matching) if matching.is_include())
241    }
242
243    pub fn is_matching_labels_not_empty(&self) -> bool {
244        matches!(&self.matching, Some(matching) if !matching.labels().is_empty())
245    }
246
247    pub fn bool_str(&self) -> &str {
248        if self.return_bool {
249            "bool "
250        } else {
251            ""
252        }
253    }
254}
255
256#[cfg(feature = "ser")]
257pub(crate) fn serialize_grouping<S>(
258    this: &Option<LabelModifier>,
259    serializer: S,
260) -> Result<S::Ok, S::Error>
261where
262    S: serde::Serializer,
263{
264    use serde::ser::SerializeMap;
265    let mut map = serializer.serialize_map(Some(2))?;
266    match this {
267        Some(LabelModifier::Include(l)) => {
268            map.serialize_entry("grouping", l)?;
269            map.serialize_entry("without", &false)?;
270        }
271        Some(LabelModifier::Exclude(l)) => {
272            map.serialize_entry("grouping", l)?;
273            map.serialize_entry("without", &true)?;
274        }
275        None => {
276            map.serialize_entry("grouping", &(vec![] as Vec<String>))?;
277            map.serialize_entry("without", &false)?;
278        }
279    }
280
281    map.end()
282}
283
284#[cfg(feature = "ser")]
285pub(crate) fn serialize_bin_modifier<S>(
286    this: &Option<BinModifier>,
287    serializer: S,
288) -> Result<S::Ok, S::Error>
289where
290    S: serde::Serializer,
291{
292    use serde::ser::SerializeMap;
293    use serde_json::json;
294
295    let mut map = serializer.serialize_map(Some(2))?;
296
297    map.serialize_entry(
298        "bool",
299        &this.as_ref().map(|t| t.return_bool).unwrap_or(false),
300    )?;
301    if let Some(t) = this {
302        if let Some(labels) = &t.matching {
303            map.serialize_key("matching")?;
304
305            match labels {
306                LabelModifier::Include(labels) => {
307                    let value = json!({
308                        "card": t.card,
309                        "include": [],
310                        "labels": labels,
311                        "on": true,
312                        "fillValues": t.fill_values,
313                    });
314                    map.serialize_value(&value)?;
315                }
316                LabelModifier::Exclude(labels) => {
317                    let value = json!({
318                        "card": t.card,
319                        "include": [],
320                        "labels": labels,
321                        "on": false,
322                        "fillValues": t.fill_values,
323                    });
324                    map.serialize_value(&value)?;
325                }
326            }
327        } else {
328            let value = json!({
329                "card": t.card,
330                "include": [],
331                "labels": [],
332                "on": false,
333                "fillValues": t.fill_values,
334            });
335            map.serialize_entry("matching", &value)?;
336        }
337    } else {
338        map.serialize_entry("matching", &None::<bool>)?;
339    }
340
341    map.end()
342}
343
344#[cfg(feature = "ser")]
345pub(crate) fn serialize_at_modifier<S>(
346    this: &Option<AtModifier>,
347    serializer: S,
348) -> Result<S::Ok, S::Error>
349where
350    S: serde::Serializer,
351{
352    use serde::ser::SerializeMap;
353    let mut map = serializer.serialize_map(Some(2))?;
354    match this {
355        Some(AtModifier::Start) => {
356            map.serialize_entry("startOrEnd", &Some("start"))?;
357            map.serialize_entry("timestamp", &None::<u128>)?;
358        }
359        Some(AtModifier::End) => {
360            map.serialize_entry("startOrEnd", &Some("end"))?;
361            map.serialize_entry("timestamp", &None::<u128>)?;
362        }
363        Some(AtModifier::At(time)) => {
364            map.serialize_entry("startOrEnd", &None::<&str>)?;
365            map.serialize_entry(
366                "timestamp",
367                &time
368                    .duration_since(SystemTime::UNIX_EPOCH)
369                    .unwrap_or(Duration::ZERO)
370                    .as_millis(),
371            )?;
372        }
373        None => {
374            map.serialize_entry("startOrEnd", &None::<&str>)?;
375            map.serialize_entry("timestamp", &None::<u128>)?;
376        }
377    }
378
379    map.end()
380}
381
382#[derive(Debug, Clone, PartialEq)]
383pub enum Offset {
384    Pos(Duration),
385    Neg(Duration),
386}
387
388impl Offset {
389    #[cfg(feature = "ser")]
390    pub(crate) fn as_millis(&self) -> i128 {
391        match self {
392            Self::Pos(dur) => dur.as_millis() as i128,
393            Self::Neg(dur) => -(dur.as_millis() as i128),
394        }
395    }
396
397    #[cfg(feature = "ser")]
398    pub(crate) fn serialize_offset<S>(
399        offset: &Option<Self>,
400        serializer: S,
401    ) -> Result<S::Ok, S::Error>
402    where
403        S: serde::Serializer,
404    {
405        let value = offset.as_ref().map(|o| o.as_millis()).unwrap_or(0);
406        serializer.serialize_i128(value)
407    }
408}
409
410impl fmt::Display for Offset {
411    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412        match self {
413            Offset::Pos(dur) => write!(f, "{}", display_duration(dur)),
414            Offset::Neg(dur) => write!(f, "-{}", display_duration(dur)),
415        }
416    }
417}
418
419#[derive(Debug, Clone, PartialEq)]
420pub enum AtModifier {
421    Start,
422    End,
423    /// at can be earlier than UNIX_EPOCH
424    At(SystemTime),
425}
426
427impl fmt::Display for AtModifier {
428    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429        match self {
430            AtModifier::Start => write!(f, "@ {}()", token_display(T_START)),
431            AtModifier::End => write!(f, "@ {}()", token_display(T_END)),
432            AtModifier::At(time) => {
433                let d = time
434                    .duration_since(SystemTime::UNIX_EPOCH)
435                    .unwrap_or(Duration::ZERO); // This should not happen
436                write!(f, "@ {:.3}", d.as_secs_f64())
437            }
438        }
439    }
440}
441
442impl TryFrom<TokenId> for AtModifier {
443    type Error = String;
444
445    fn try_from(id: TokenId) -> Result<Self, Self::Error> {
446        match id {
447            T_START => Ok(AtModifier::Start),
448            T_END => Ok(AtModifier::End),
449            _ => Err(format!(
450                "invalid @ modifier preprocessor '{}', START or END is valid.",
451                token::token_display(id)
452            )),
453        }
454    }
455}
456
457impl TryFrom<Token> for AtModifier {
458    type Error = String;
459
460    fn try_from(token: Token) -> Result<Self, Self::Error> {
461        AtModifier::try_from(token.id())
462    }
463}
464
465impl TryFrom<NumberLiteral> for AtModifier {
466    type Error = String;
467
468    fn try_from(num: NumberLiteral) -> Result<Self, Self::Error> {
469        AtModifier::try_from(num.val)
470    }
471}
472
473impl TryFrom<Expr> for AtModifier {
474    type Error = String;
475
476    fn try_from(ex: Expr) -> Result<Self, Self::Error> {
477        match ex {
478            Expr::NumberLiteral(nl) => AtModifier::try_from(nl),
479            _ => Err("invalid float value after @ modifier".into()),
480        }
481    }
482}
483
484impl TryFrom<f64> for AtModifier {
485    type Error = String;
486
487    fn try_from(secs: f64) -> Result<Self, Self::Error> {
488        let err_info = format!("timestamp out of bounds for @ modifier: {secs}");
489
490        if secs.is_nan() || secs.is_infinite() || secs >= f64::MAX || secs <= f64::MIN {
491            return Err(err_info);
492        }
493        let milli = (secs * 1000f64).round().abs() as u64;
494
495        let duration = Duration::from_millis(milli);
496        let mut st = Some(SystemTime::UNIX_EPOCH);
497        if secs.is_sign_positive() {
498            st = SystemTime::UNIX_EPOCH.checked_add(duration);
499        }
500        if secs.is_sign_negative() {
501            st = SystemTime::UNIX_EPOCH.checked_sub(duration);
502        }
503
504        st.map(Self::At).ok_or(err_info)
505    }
506}
507
508/// EvalStmt holds an expression and information on the range it should
509/// be evaluated on.
510#[allow(rustdoc::broken_intra_doc_links)]
511#[derive(Debug, Clone)]
512pub struct EvalStmt {
513    /// Expression to be evaluated.
514    pub expr: Expr,
515
516    /// The time boundaries for the evaluation. If start equals end an instant
517    /// is evaluated.
518    pub start: SystemTime,
519    pub end: SystemTime,
520    /// Time between two evaluated instants for the range [start:end].
521    pub interval: Duration,
522    /// Lookback delta to use for this evaluation.
523    pub lookback_delta: Duration,
524}
525
526impl fmt::Display for EvalStmt {
527    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528        write!(
529            f,
530            "[{}] @ [{}, {}, {}, {}]",
531            self.expr,
532            DateTime::<Utc>::from(self.start).to_rfc3339(),
533            DateTime::<Utc>::from(self.end).to_rfc3339(),
534            display_duration(&self.interval),
535            display_duration(&self.lookback_delta)
536        )
537    }
538}
539
540/// Grammar:
541/// ``` norust
542/// <aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
543/// <aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
544/// ```
545///
546/// parameter is only required for `count_values`, `quantile`, `topk` and `bottomk`.
547#[derive(Debug, Clone, PartialEq)]
548#[cfg_attr(feature = "ser", derive(serde::Serialize))]
549pub struct AggregateExpr {
550    /// The used aggregation operation.
551    pub op: TokenType,
552    /// The Vector expression over which is aggregated.
553    pub expr: Box<Expr>,
554    /// Parameter used by some aggregators.
555    pub param: Option<Box<Expr>>,
556    /// modifier is optional for some aggregation operators, like sum.
557    #[cfg_attr(feature = "ser", serde(flatten))]
558    #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_grouping"))]
559    pub modifier: Option<LabelModifier>,
560}
561
562impl AggregateExpr {
563    fn get_op_string(&self) -> String {
564        let mut s = self.op.to_string();
565
566        if let Some(modifier) = &self.modifier {
567            match modifier {
568                LabelModifier::Exclude(ls) => write!(s, " without ({ls}) ").unwrap(),
569                LabelModifier::Include(ls) if !ls.is_empty() => write!(s, " by ({ls}) ").unwrap(),
570                _ => (),
571            }
572        }
573        s
574    }
575}
576
577impl fmt::Display for AggregateExpr {
578    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
579        write!(f, "{}", self.get_op_string())?;
580
581        write!(f, "(")?;
582        if let Some(param) = &self.param {
583            write!(f, "{param}, ")?;
584        }
585        write!(f, "{})", self.expr)?;
586
587        Ok(())
588    }
589}
590
591impl Prettier for AggregateExpr {
592    fn format(&self, level: usize, max: usize) -> String {
593        let mut s = format!("{}{}(\n", indent(level), self.get_op_string());
594        if let Some(param) = &self.param {
595            writeln!(s, "{},", param.pretty(level + 1, max)).unwrap();
596        }
597        writeln!(s, "{}", self.expr.pretty(level + 1, max)).unwrap();
598        write!(s, "{})", indent(level)).unwrap();
599        s
600    }
601}
602
603/// UnaryExpr will negate the expr
604#[derive(Debug, Clone, PartialEq)]
605pub struct UnaryExpr {
606    pub expr: Box<Expr>,
607}
608
609impl fmt::Display for UnaryExpr {
610    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
611        write!(f, "-{}", self.expr)
612    }
613}
614
615impl Prettier for UnaryExpr {
616    fn pretty(&self, level: usize, max: usize) -> String {
617        format!(
618            "{}-{}",
619            indent(level),
620            self.expr.pretty(level, max).trim_start()
621        )
622    }
623}
624
625#[cfg(feature = "ser")]
626impl serde::Serialize for UnaryExpr {
627    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
628    where
629        S: serde::Serializer,
630    {
631        use serde::ser::SerializeMap;
632        let mut map = serializer.serialize_map(Some(2))?;
633        map.serialize_entry("op", "-")?;
634        map.serialize_entry("expr", &self.expr)?;
635
636        map.end()
637    }
638}
639
640/// Grammar:
641/// ``` norust
642/// <vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
643/// <vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
644/// <vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
645/// <vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
646/// ```
647#[derive(Debug, Clone, PartialEq)]
648#[cfg_attr(feature = "ser", derive(serde::Serialize))]
649pub struct BinaryExpr {
650    /// The operation of the expression.
651    pub op: TokenType,
652    /// The operands on the left sides of the operator.
653    pub lhs: Box<Expr>,
654    /// The operands on the right sides of the operator.
655    pub rhs: Box<Expr>,
656    #[cfg_attr(feature = "ser", serde(flatten))]
657    #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_bin_modifier"))]
658    pub modifier: Option<BinModifier>,
659}
660
661impl BinaryExpr {
662    pub fn is_matching_on(&self) -> bool {
663        matches!(&self.modifier, Some(modifier) if modifier.is_matching_on())
664    }
665
666    pub fn is_matching_labels_not_empty(&self) -> bool {
667        matches!(&self.modifier, Some(modifier) if modifier.is_matching_labels_not_empty())
668    }
669
670    pub fn return_bool(&self) -> bool {
671        matches!(&self.modifier, Some(modifier) if modifier.return_bool)
672    }
673
674    /// check if labels of card and matching are joint
675    pub fn is_labels_joint(&self) -> bool {
676        matches!(&self.modifier, Some(modifier) if modifier.is_labels_joint())
677    }
678
679    /// intersect labels of card and matching
680    pub fn intersect_labels(&self) -> Option<Vec<String>> {
681        self.modifier
682            .as_ref()
683            .and_then(|modifier| modifier.intersect_labels())
684    }
685
686    fn get_op_matching_string(&self) -> String {
687        match &self.modifier {
688            Some(modifier) => format!("{}{modifier}", self.op),
689            None => self.op.to_string(),
690        }
691    }
692}
693
694impl fmt::Display for BinaryExpr {
695    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
696        write!(
697            f,
698            "{} {} {}",
699            self.lhs,
700            self.get_op_matching_string(),
701            self.rhs
702        )
703    }
704}
705
706impl Prettier for BinaryExpr {
707    fn format(&self, level: usize, max: usize) -> String {
708        format!(
709            "{}\n{}{}\n{}",
710            self.lhs.pretty(level + 1, max),
711            indent(level),
712            self.get_op_matching_string(),
713            self.rhs.pretty(level + 1, max)
714        )
715    }
716}
717
718#[derive(Debug, Clone, PartialEq)]
719#[cfg_attr(feature = "ser", derive(serde::Serialize))]
720pub struct ParenExpr {
721    pub expr: Box<Expr>,
722}
723
724impl fmt::Display for ParenExpr {
725    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
726        write!(f, "({})", self.expr)
727    }
728}
729
730impl Prettier for ParenExpr {
731    fn format(&self, level: usize, max: usize) -> String {
732        format!(
733            "{}(\n{}\n{})",
734            indent(level),
735            self.expr.pretty(level + 1, max),
736            indent(level)
737        )
738    }
739}
740
741/// Grammar:
742/// ```norust
743/// <instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]
744/// ```
745#[derive(Debug, Clone, PartialEq)]
746#[cfg_attr(feature = "ser", derive(serde::Serialize))]
747pub struct SubqueryExpr {
748    pub expr: Box<Expr>,
749    #[cfg_attr(feature = "ser", serde(serialize_with = "Offset::serialize_offset"))]
750    pub offset: Option<Offset>,
751    #[cfg_attr(feature = "ser", serde(flatten))]
752    #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_at_modifier"))]
753    pub at: Option<AtModifier>,
754    #[cfg_attr(
755        feature = "ser",
756        serde(serialize_with = "crate::util::duration::serialize_duration")
757    )]
758    pub range: Duration,
759    /// Default is the global evaluation interval.
760    #[cfg_attr(
761        feature = "ser",
762        serde(serialize_with = "crate::util::duration::serialize_duration_opt")
763    )]
764    pub step: Option<Duration>,
765}
766
767impl SubqueryExpr {
768    fn get_time_suffix_string(&self) -> String {
769        let step = match &self.step {
770            Some(step) => display_duration(step),
771            None => String::from(""),
772        };
773        let range = display_duration(&self.range);
774
775        let mut s = format!("[{range}:{step}]");
776
777        if let Some(at) = &self.at {
778            write!(s, " {at}").unwrap();
779        }
780
781        if let Some(offset) = &self.offset {
782            write!(s, " offset {offset}").unwrap();
783        }
784        s
785    }
786}
787
788impl fmt::Display for SubqueryExpr {
789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790        write!(f, "{}{}", self.expr, self.get_time_suffix_string())
791    }
792}
793
794impl Prettier for SubqueryExpr {
795    fn pretty(&self, level: usize, max: usize) -> String {
796        format!(
797            "{}{}",
798            self.expr.pretty(level, max),
799            self.get_time_suffix_string()
800        )
801    }
802}
803
804#[derive(Debug, Clone)]
805pub struct NumberLiteral {
806    pub val: f64,
807}
808
809impl NumberLiteral {
810    pub fn new(val: f64) -> Self {
811        Self { val }
812    }
813}
814
815impl PartialEq for NumberLiteral {
816    fn eq(&self, other: &Self) -> bool {
817        self.val == other.val || self.val.is_nan() && other.val.is_nan()
818    }
819}
820
821impl Eq for NumberLiteral {}
822
823impl Neg for NumberLiteral {
824    type Output = Self;
825
826    fn neg(self) -> Self::Output {
827        NumberLiteral { val: -self.val }
828    }
829}
830
831impl fmt::Display for NumberLiteral {
832    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
833        if self.val == f64::INFINITY {
834            write!(f, "Inf")
835        } else if self.val == f64::NEG_INFINITY {
836            write!(f, "-Inf")
837        } else if f64::is_nan(self.val) {
838            write!(f, "NaN")
839        } else {
840            write!(f, "{}", self.val)
841        }
842    }
843}
844
845#[cfg(feature = "ser")]
846impl serde::Serialize for NumberLiteral {
847    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
848    where
849        S: serde::Serializer,
850    {
851        use serde::ser::SerializeMap;
852        let mut map = serializer.serialize_map(Some(1))?;
853        map.serialize_entry("val", &self.to_string())?;
854
855        map.end()
856    }
857}
858
859impl Prettier for NumberLiteral {
860    fn needs_split(&self, _max: usize) -> bool {
861        false
862    }
863}
864
865#[derive(Debug, Clone, PartialEq)]
866#[cfg_attr(feature = "ser", derive(serde::Serialize))]
867pub struct StringLiteral {
868    pub val: String,
869}
870
871impl fmt::Display for StringLiteral {
872    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
873        write!(f, "\"{}\"", escape_string(&self.val))
874    }
875}
876
877impl Prettier for StringLiteral {
878    fn needs_split(&self, _max: usize) -> bool {
879        false
880    }
881}
882
883#[derive(Debug, Clone, PartialEq)]
884#[cfg_attr(feature = "ser", derive(serde::Serialize))]
885pub struct VectorSelector {
886    pub name: Option<String>,
887    #[cfg_attr(feature = "ser", serde(flatten))]
888    pub matchers: Matchers,
889    #[cfg_attr(feature = "ser", serde(serialize_with = "Offset::serialize_offset"))]
890    pub offset: Option<Offset>,
891    #[cfg_attr(feature = "ser", serde(flatten))]
892    #[cfg_attr(feature = "ser", serde(serialize_with = "serialize_at_modifier"))]
893    pub at: Option<AtModifier>,
894}
895
896impl VectorSelector {
897    pub fn new(name: Option<String>, matchers: Matchers) -> Self {
898        VectorSelector {
899            name,
900            matchers,
901            offset: None,
902            at: None,
903        }
904    }
905}
906
907impl Default for VectorSelector {
908    fn default() -> Self {
909        Self {
910            name: None,
911            matchers: Matchers::empty(),
912            offset: None,
913            at: None,
914        }
915    }
916}
917
918impl From<String> for VectorSelector {
919    fn from(name: String) -> Self {
920        VectorSelector {
921            name: Some(name),
922            offset: None,
923            at: None,
924            matchers: Matchers::empty(),
925        }
926    }
927}
928
929/// directly create an instant vector with only METRIC_NAME matcher.
930///
931/// # Examples
932///
933/// Basic usage:
934///
935/// ``` rust
936/// use promql_parser::label::Matchers;
937/// use promql_parser::parser::VectorSelector;
938///
939/// let vs = VectorSelector {
940///     name: Some(String::from("foo")),
941///     offset: None,
942///     at: None,
943///     matchers: Matchers::empty(),
944/// };
945///
946/// assert_eq!(VectorSelector::from("foo"), vs);
947/// ```
948impl From<&str> for VectorSelector {
949    fn from(name: &str) -> Self {
950        VectorSelector::from(name.to_string())
951    }
952}
953
954impl Neg for VectorSelector {
955    type Output = UnaryExpr;
956
957    fn neg(self) -> Self::Output {
958        let ex = Expr::VectorSelector(self);
959        UnaryExpr { expr: Box::new(ex) }
960    }
961}
962
963impl fmt::Display for VectorSelector {
964    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
965        if let Some(name) = &self.name {
966            write!(f, "{name}")?;
967        }
968        let matchers = &self.matchers.to_string();
969        if !matchers.is_empty() {
970            write!(f, "{{{matchers}}}")?;
971        }
972        if let Some(at) = &self.at {
973            write!(f, " {at}")?;
974        }
975        if let Some(offset) = &self.offset {
976            write!(f, " offset {offset}")?;
977        }
978        Ok(())
979    }
980}
981
982impl Prettier for VectorSelector {
983    fn needs_split(&self, _max: usize) -> bool {
984        false
985    }
986}
987
988#[derive(Debug, Clone, PartialEq)]
989#[cfg_attr(feature = "ser", derive(serde::Serialize))]
990pub struct MatrixSelector {
991    #[cfg_attr(feature = "ser", serde(flatten))]
992    pub vs: VectorSelector,
993    #[cfg_attr(
994        feature = "ser",
995        serde(serialize_with = "crate::util::duration::serialize_duration")
996    )]
997    pub range: Duration,
998}
999
1000impl fmt::Display for MatrixSelector {
1001    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1002        if let Some(name) = &self.vs.name {
1003            write!(f, "{name}")?;
1004        }
1005
1006        let matchers = &self.vs.matchers.to_string();
1007        if !matchers.is_empty() {
1008            write!(f, "{{{matchers}}}")?;
1009        }
1010
1011        write!(f, "[{}]", display_duration(&self.range))?;
1012
1013        if let Some(at) = &self.vs.at {
1014            write!(f, " {at}")?;
1015        }
1016
1017        if let Some(offset) = &self.vs.offset {
1018            write!(f, " offset {offset}")?;
1019        }
1020
1021        Ok(())
1022    }
1023}
1024
1025impl Prettier for MatrixSelector {
1026    fn needs_split(&self, _max: usize) -> bool {
1027        false
1028    }
1029}
1030
1031/// Call represents Prometheus Function.
1032/// Some functions have special cases:
1033///
1034/// ## exp
1035///
1036/// exp(v instant-vector) calculates the exponential function for all elements in v.
1037/// Special cases are:
1038///
1039/// ```promql
1040/// Exp(+Inf) = +Inf
1041/// Exp(NaN) = NaN
1042/// ```
1043///
1044/// ## ln
1045///
1046/// ln(v instant-vector) calculates the natural logarithm for all elements in v.
1047/// Special cases are:
1048///
1049/// ```promql
1050/// ln(+Inf) = +Inf
1051/// ln(0) = -Inf
1052/// ln(x < 0) = NaN
1053/// ln(NaN) = NaN
1054/// ```
1055///
1056/// TODO: support more special cases of function call
1057///
1058///  - acos()
1059///  - acosh()
1060///  - asin()
1061///  - asinh()
1062///  - atan()
1063///  - atanh()
1064///  - cos()
1065///  - cosh()
1066///  - sin()
1067///  - sinh()
1068///  - tan()
1069///  - tanh()
1070#[derive(Debug, Clone, PartialEq)]
1071#[cfg_attr(feature = "ser", derive(serde::Serialize))]
1072pub struct Call {
1073    pub func: Function,
1074    #[cfg_attr(feature = "ser", serde(flatten))]
1075    pub args: FunctionArgs,
1076}
1077
1078impl fmt::Display for Call {
1079    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1080        write!(f, "{}({})", self.func.name, self.args)
1081    }
1082}
1083
1084impl Prettier for Call {
1085    fn format(&self, level: usize, max: usize) -> String {
1086        format!(
1087            "{}{}(\n{}\n{})",
1088            indent(level),
1089            self.func.name,
1090            self.args.pretty(level + 1, max),
1091            indent(level)
1092        )
1093    }
1094}
1095
1096/// Node for extending the AST. [Extension] won't be generate by this parser itself.
1097#[derive(Debug, Clone)]
1098pub struct Extension {
1099    pub expr: Arc<dyn ExtensionExpr>,
1100}
1101
1102/// The interface for extending the AST with custom expression node.
1103pub trait ExtensionExpr: std::fmt::Debug + Send + Sync {
1104    fn as_any(&self) -> &dyn std::any::Any;
1105
1106    fn name(&self) -> &str;
1107
1108    fn value_type(&self) -> ValueType;
1109
1110    fn children(&self) -> &[Expr];
1111
1112    fn with_new_children(&self, children: Vec<Expr>) -> Arc<dyn ExtensionExpr>;
1113}
1114
1115impl PartialEq for Extension {
1116    fn eq(&self, other: &Self) -> bool {
1117        format!("{self:?}") == format!("{other:?}")
1118    }
1119}
1120
1121impl Eq for Extension {}
1122
1123#[derive(Debug, Clone, PartialEq)]
1124#[cfg_attr(feature = "ser", derive(serde::Serialize))]
1125#[cfg_attr(feature = "ser", serde(tag = "type", rename_all = "camelCase"))]
1126pub enum Expr {
1127    /// Aggregate represents an aggregation operation on a Vector.
1128    #[cfg_attr(feature = "ser", serde(rename = "aggregation"))]
1129    Aggregate(AggregateExpr),
1130
1131    /// Unary represents a unary operation on another expression.
1132    /// Currently unary operations are only supported for Scalars.
1133    #[cfg_attr(feature = "ser", serde(rename = "unaryExpr"))]
1134    Unary(UnaryExpr),
1135
1136    /// Binary represents a binary expression between two child expressions.
1137    #[cfg_attr(feature = "ser", serde(rename = "binaryExpr"))]
1138    Binary(BinaryExpr),
1139
1140    /// Paren wraps an expression so it cannot be disassembled as a consequence
1141    /// of operator precedence.
1142    #[cfg_attr(feature = "ser", serde(rename = "parenExpr"))]
1143    Paren(ParenExpr),
1144
1145    /// SubqueryExpr represents a subquery.
1146    Subquery(SubqueryExpr),
1147
1148    /// NumberLiteral represents a number.
1149    NumberLiteral(NumberLiteral),
1150
1151    /// StringLiteral represents a string.
1152    StringLiteral(StringLiteral),
1153
1154    /// VectorSelector represents a Vector selection.
1155    VectorSelector(VectorSelector),
1156
1157    /// MatrixSelector represents a Matrix selection.
1158    MatrixSelector(MatrixSelector),
1159
1160    /// Call represents a function call.
1161    Call(Call),
1162
1163    /// Extension represents an extension expression. It is for user to attach additional
1164    /// information to the AST. This parser won't generate Extension node.
1165    #[cfg_attr(feature = "ser", serde(skip))]
1166    Extension(Extension),
1167}
1168
1169impl Expr {
1170    pub(crate) fn new_vector_selector(
1171        name: Option<String>,
1172        matchers: Matchers,
1173    ) -> Result<Self, String> {
1174        let vs = VectorSelector::new(name, matchers);
1175        Ok(Self::VectorSelector(vs))
1176    }
1177
1178    pub(crate) fn new_unary_expr(expr: Expr) -> Result<Self, String> {
1179        match expr {
1180            Expr::StringLiteral(_) => Err("unary expression only allowed on expressions of type scalar or vector, got: string".into()),
1181            Expr::MatrixSelector(_) => Err("unary expression only allowed on expressions of type scalar or vector, got: matrix".into()),
1182            _ => Ok(-expr),
1183        }
1184    }
1185
1186    pub(crate) fn new_subquery_expr(
1187        expr: Expr,
1188        range: Duration,
1189        step: Option<Duration>,
1190    ) -> Result<Self, String> {
1191        let se = Expr::Subquery(SubqueryExpr {
1192            expr: Box::new(expr),
1193            offset: None,
1194            at: None,
1195            range,
1196            step,
1197        });
1198        Ok(se)
1199    }
1200
1201    pub(crate) fn new_paren_expr(expr: Expr) -> Result<Self, String> {
1202        let ex = Expr::Paren(ParenExpr {
1203            expr: Box::new(expr),
1204        });
1205        Ok(ex)
1206    }
1207
1208    /// NOTE: @ and offset is not set here.
1209    pub(crate) fn new_matrix_selector(expr: Expr, range: Duration) -> Result<Self, String> {
1210        match expr {
1211            Expr::VectorSelector(VectorSelector {
1212                offset: Some(_), ..
1213            }) => Err("no offset modifiers allowed before range".into()),
1214            Expr::VectorSelector(VectorSelector { at: Some(_), .. }) => {
1215                Err("no @ modifiers allowed before range".into())
1216            }
1217            Expr::VectorSelector(vs) => {
1218                let ms = Expr::MatrixSelector(MatrixSelector { vs, range });
1219                Ok(ms)
1220            }
1221            _ => Err("ranges only allowed for vector selectors".into()),
1222        }
1223    }
1224
1225    pub(crate) fn at_expr(self, at: AtModifier) -> Result<Self, String> {
1226        let already_set_err = Err("@ <timestamp> may not be set multiple times".into());
1227        match self {
1228            Expr::VectorSelector(mut vs) => match vs.at {
1229                None => {
1230                    vs.at = Some(at);
1231                    Ok(Expr::VectorSelector(vs))
1232                }
1233                Some(_) => already_set_err,
1234            },
1235            Expr::MatrixSelector(mut ms) => match ms.vs.at {
1236                None => {
1237                    ms.vs.at = Some(at);
1238                    Ok(Expr::MatrixSelector(ms))
1239                }
1240                Some(_) => already_set_err,
1241            },
1242            Expr::Subquery(mut s) => match s.at {
1243                None => {
1244                    s.at = Some(at);
1245                    Ok(Expr::Subquery(s))
1246                }
1247                Some(_) => already_set_err,
1248            },
1249            _ => {
1250                Err("@ modifier must be preceded by an vector selector or matrix selector or a subquery".into())
1251            }
1252        }
1253    }
1254
1255    /// set offset field for specified Expr, but CAN ONLY be set once.
1256    pub(crate) fn offset_expr(self, offset: Offset) -> Result<Self, String> {
1257        let already_set_err = Err("offset may not be set multiple times".into());
1258        match self {
1259            Expr::VectorSelector(mut vs) => match vs.offset {
1260                None => {
1261                    vs.offset = Some(offset);
1262                    Ok(Expr::VectorSelector(vs))
1263                }
1264                Some(_) => already_set_err,
1265            },
1266            Expr::MatrixSelector(mut ms) => match ms.vs.offset {
1267                None => {
1268                    ms.vs.offset = Some(offset);
1269                    Ok(Expr::MatrixSelector(ms))
1270                }
1271                Some(_) => already_set_err,
1272            },
1273            Expr::Subquery(mut s) => match s.offset {
1274                None => {
1275                    s.offset = Some(offset);
1276                    Ok(Expr::Subquery(s))
1277                }
1278                Some(_) => already_set_err,
1279            },
1280            _ => {
1281                Err("offset modifier must be preceded by an vector selector or matrix selector or a subquery".into())
1282            }
1283        }
1284    }
1285
1286    pub(crate) fn new_call(func: Function, args: FunctionArgs) -> Result<Expr, String> {
1287        Ok(Expr::Call(Call { func, args }))
1288    }
1289
1290    pub(crate) fn new_binary_expr(
1291        lhs: Expr,
1292        op: TokenId,
1293        modifier: Option<BinModifier>,
1294        rhs: Expr,
1295    ) -> Result<Expr, String> {
1296        let ex = BinaryExpr {
1297            op: TokenType::new(op),
1298            lhs: Box::new(lhs),
1299            rhs: Box::new(rhs),
1300            modifier,
1301        };
1302        Ok(Expr::Binary(ex))
1303    }
1304
1305    pub(crate) fn new_aggregate_expr(
1306        op: TokenId,
1307        modifier: Option<LabelModifier>,
1308        args: FunctionArgs,
1309    ) -> Result<Expr, String> {
1310        let op = TokenType::new(op);
1311        if args.is_empty() {
1312            return Err(format!(
1313                "no arguments for aggregate expression '{op}' provided"
1314            ));
1315        }
1316        let mut desired_args_count = 1;
1317        let mut param = None;
1318        if op.is_aggregator_with_param() {
1319            desired_args_count = 2;
1320            param = args.first();
1321        }
1322        if args.len() != desired_args_count {
1323            return Err(format!(
1324                "wrong number of arguments for aggregate expression provided, expected {}, got {}",
1325                desired_args_count,
1326                args.len()
1327            ));
1328        }
1329
1330        match args.last() {
1331            Some(expr) => Ok(Expr::Aggregate(AggregateExpr {
1332                op,
1333                expr,
1334                param,
1335                modifier,
1336            })),
1337            None => Err(
1338                "aggregate operation needs a single instant vector parameter, but found none"
1339                    .into(),
1340            ),
1341        }
1342    }
1343
1344    pub fn value_type(&self) -> ValueType {
1345        match self {
1346            Expr::Aggregate(_) => ValueType::Vector,
1347            Expr::Unary(ex) => ex.expr.value_type(),
1348            Expr::Binary(ex) => {
1349                if ex.lhs.value_type() == ValueType::Scalar
1350                    && ex.rhs.value_type() == ValueType::Scalar
1351                {
1352                    ValueType::Scalar
1353                } else {
1354                    ValueType::Vector
1355                }
1356            }
1357            Expr::Paren(ex) => ex.expr.value_type(),
1358            Expr::Subquery(_) => ValueType::Matrix,
1359            Expr::NumberLiteral(_) => ValueType::Scalar,
1360            Expr::StringLiteral(_) => ValueType::String,
1361            Expr::VectorSelector(_) => ValueType::Vector,
1362            Expr::MatrixSelector(_) => ValueType::Matrix,
1363            Expr::Call(ex) => ex.func.return_type,
1364            Expr::Extension(ex) => ex.expr.value_type(),
1365        }
1366    }
1367
1368    /// only Some if expr is [Expr::NumberLiteral]
1369    pub(crate) fn scalar_value(&self) -> Option<f64> {
1370        match self {
1371            Expr::NumberLiteral(nl) => Some(nl.val),
1372            _ => None,
1373        }
1374    }
1375
1376    pub fn prettify(&self) -> String {
1377        self.pretty(0, MAX_CHARACTERS_PER_LINE)
1378    }
1379}
1380
1381impl From<String> for Expr {
1382    fn from(val: String) -> Self {
1383        Expr::StringLiteral(StringLiteral { val })
1384    }
1385}
1386
1387impl From<&str> for Expr {
1388    fn from(s: &str) -> Self {
1389        Expr::StringLiteral(StringLiteral { val: s.into() })
1390    }
1391}
1392
1393impl From<f64> for Expr {
1394    fn from(val: f64) -> Self {
1395        Expr::NumberLiteral(NumberLiteral { val })
1396    }
1397}
1398
1399/// directly create an Expr::VectorSelector from instant vector
1400///
1401/// # Examples
1402///
1403/// Basic usage:
1404///
1405/// ``` rust
1406/// use promql_parser::label::Matchers;
1407/// use promql_parser::parser::{Expr, VectorSelector};
1408///
1409/// let name = String::from("foo");
1410/// let vs = VectorSelector::new(Some(name), Matchers::empty());
1411///
1412/// assert_eq!(Expr::VectorSelector(vs), Expr::from(VectorSelector::from("foo")));
1413/// ```
1414impl From<VectorSelector> for Expr {
1415    fn from(vs: VectorSelector) -> Self {
1416        Expr::VectorSelector(vs)
1417    }
1418}
1419
1420impl Neg for Expr {
1421    type Output = Self;
1422
1423    fn neg(self) -> Self::Output {
1424        match self {
1425            Expr::NumberLiteral(nl) => Expr::NumberLiteral(-nl),
1426            _ => Expr::Unary(UnaryExpr {
1427                expr: Box::new(self),
1428            }),
1429        }
1430    }
1431}
1432
1433impl fmt::Display for Expr {
1434    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1435        match self {
1436            Expr::Aggregate(ex) => write!(f, "{ex}"),
1437            Expr::Unary(ex) => write!(f, "{ex}"),
1438            Expr::Binary(ex) => write!(f, "{ex}"),
1439            Expr::Paren(ex) => write!(f, "{ex}"),
1440            Expr::Subquery(ex) => write!(f, "{ex}"),
1441            Expr::NumberLiteral(ex) => write!(f, "{ex}"),
1442            Expr::StringLiteral(ex) => write!(f, "{ex}"),
1443            Expr::VectorSelector(ex) => write!(f, "{ex}"),
1444            Expr::MatrixSelector(ex) => write!(f, "{ex}"),
1445            Expr::Call(ex) => write!(f, "{ex}"),
1446            Expr::Extension(ext) => write!(f, "{ext:?}"),
1447        }
1448    }
1449}
1450
1451impl Prettier for Expr {
1452    fn pretty(&self, level: usize, max: usize) -> String {
1453        match self {
1454            Expr::Aggregate(ex) => ex.pretty(level, max),
1455            Expr::Unary(ex) => ex.pretty(level, max),
1456            Expr::Binary(ex) => ex.pretty(level, max),
1457            Expr::Paren(ex) => ex.pretty(level, max),
1458            Expr::Subquery(ex) => ex.pretty(level, max),
1459            Expr::NumberLiteral(ex) => ex.pretty(level, max),
1460            Expr::StringLiteral(ex) => ex.pretty(level, max),
1461            Expr::VectorSelector(ex) => ex.pretty(level, max),
1462            Expr::MatrixSelector(ex) => ex.pretty(level, max),
1463            Expr::Call(ex) => ex.pretty(level, max),
1464            Expr::Extension(ext) => format!("{ext:?}"),
1465        }
1466    }
1467}
1468
1469/// check_ast checks the validity of the provided AST. This includes type checking.
1470/// Recursively check correct typing for child nodes and raise errors in case of bad typing.
1471pub(crate) fn check_ast(expr: Expr) -> Result<Expr, String> {
1472    match expr {
1473        Expr::Binary(ex) => check_ast_for_binary_expr(ex),
1474        Expr::Aggregate(ex) => check_ast_for_aggregate_expr(ex),
1475        Expr::Call(ex) => check_ast_for_call(ex),
1476        Expr::Unary(ex) => check_ast_for_unary(ex),
1477        Expr::Subquery(ex) => check_ast_for_subquery(ex),
1478        Expr::VectorSelector(ex) => check_ast_for_vector_selector(ex),
1479        Expr::Paren(_) => Ok(expr),
1480        Expr::NumberLiteral(_) => Ok(expr),
1481        Expr::StringLiteral(_) => Ok(expr),
1482        Expr::MatrixSelector(_) => Ok(expr),
1483        Expr::Extension(_) => Ok(expr),
1484    }
1485}
1486
1487fn expect_type(
1488    expected: ValueType,
1489    actual: Option<ValueType>,
1490    context: &str,
1491) -> Result<bool, String> {
1492    match actual {
1493        Some(actual) => {
1494            if actual == expected {
1495                Ok(true)
1496            } else {
1497                Err(format!(
1498                    "expected type {expected} in {context}, got {actual}"
1499                ))
1500            }
1501        }
1502        None => Err(format!("expected type {expected} in {context}, got None")),
1503    }
1504}
1505
1506/// the original logic is redundant in prometheus, and the following coding blocks
1507/// have been optimized for readability, but all logic SHOULD be covered.
1508fn check_ast_for_binary_expr(mut ex: BinaryExpr) -> Result<Expr, String> {
1509    if !ex.op.is_operator() {
1510        return Err(format!(
1511            "binary expression does not support operator '{}'",
1512            ex.op
1513        ));
1514    }
1515
1516    if ex.return_bool() && !ex.op.is_comparison_operator() {
1517        return Err("bool modifier can only be used on comparison operators".into());
1518    }
1519
1520    if ex.op.is_comparison_operator()
1521        && ex.lhs.value_type() == ValueType::Scalar
1522        && ex.rhs.value_type() == ValueType::Scalar
1523        && !ex.return_bool()
1524    {
1525        return Err("comparisons between scalars must use BOOL modifier".into());
1526    }
1527
1528    // For `on` matching, a label can only appear in one of the lists.
1529    // Every time series of the result vector must be uniquely identifiable.
1530    if ex.is_matching_on() && ex.is_labels_joint() {
1531        if let Some(labels) = ex.intersect_labels() {
1532            if let Some(label) = labels.first() {
1533                return Err(format!(
1534                    "label '{label}' must not occur in ON and GROUP clause at once"
1535                ));
1536            }
1537        };
1538    }
1539
1540    if ex.op.is_set_operator() {
1541        if ex.lhs.value_type() == ValueType::Scalar || ex.rhs.value_type() == ValueType::Scalar {
1542            return Err(format!(
1543                "set operator '{}' not allowed in binary scalar expression",
1544                ex.op
1545            ));
1546        }
1547
1548        if ex.lhs.value_type() == ValueType::Vector && ex.rhs.value_type() == ValueType::Vector {
1549            if let Some(ref modifier) = ex.modifier {
1550                if matches!(modifier.card, VectorMatchCardinality::OneToMany(_))
1551                    || matches!(modifier.card, VectorMatchCardinality::ManyToOne(_))
1552                {
1553                    return Err(format!("no grouping allowed for '{}' operation", ex.op));
1554                }
1555            };
1556        }
1557
1558        match &mut ex.modifier {
1559            Some(modifier) => {
1560                if modifier.card == VectorMatchCardinality::OneToOne {
1561                    modifier.card = VectorMatchCardinality::ManyToMany;
1562                }
1563            }
1564            None => {
1565                ex.modifier =
1566                    Some(BinModifier::default().with_card(VectorMatchCardinality::ManyToMany));
1567            }
1568        }
1569    }
1570
1571    if ex.lhs.value_type() != ValueType::Scalar && ex.lhs.value_type() != ValueType::Vector {
1572        return Err("binary expression must contain only scalar and instant vector types".into());
1573    }
1574    if ex.rhs.value_type() != ValueType::Scalar && ex.rhs.value_type() != ValueType::Vector {
1575        return Err("binary expression must contain only scalar and instant vector types".into());
1576    }
1577
1578    if (ex.lhs.value_type() != ValueType::Vector || ex.rhs.value_type() != ValueType::Vector)
1579        && ex.is_matching_labels_not_empty()
1580    {
1581        return Err("vector matching only allowed between vectors".into());
1582    }
1583
1584    Ok(Expr::Binary(ex))
1585}
1586
1587fn check_ast_for_aggregate_expr(ex: AggregateExpr) -> Result<Expr, String> {
1588    if !ex.op.is_aggregator() {
1589        return Err(format!(
1590            "aggregation operator expected in aggregation expression but got '{}'",
1591            ex.op
1592        ));
1593    }
1594
1595    expect_type(
1596        ValueType::Vector,
1597        Some(ex.expr.value_type()),
1598        "aggregation expression",
1599    )?;
1600
1601    if matches!(ex.op.id(), T_TOPK | T_BOTTOMK | T_QUANTILE) {
1602        expect_type(
1603            ValueType::Scalar,
1604            ex.param.as_ref().map(|ex| ex.value_type()),
1605            "aggregation expression",
1606        )?;
1607    }
1608
1609    if ex.op.id() == T_COUNT_VALUES {
1610        expect_type(
1611            ValueType::String,
1612            ex.param.as_ref().map(|ex| ex.value_type()),
1613            "aggregation expression",
1614        )?;
1615    }
1616
1617    Ok(Expr::Aggregate(ex))
1618}
1619
1620fn check_ast_for_call(ex: Call) -> Result<Expr, String> {
1621    let name = ex.func.name;
1622
1623    check_call_arity(
1624        ex.func.arg_types.len(),
1625        ex.func.variadic,
1626        ex.args.len(),
1627        name,
1628    )?;
1629
1630    // special cases from https://prometheus.io/docs/prometheus/latest/querying/functions
1631    if name.eq("exp") {
1632        if let Some(val) = ex.args.first().and_then(|ex| ex.scalar_value()) {
1633            if val.is_nan() || val.is_infinite() {
1634                return Ok(Expr::Call(ex));
1635            }
1636        }
1637    } else if name.eq("ln") || name.eq("log2") || name.eq("log10") {
1638        if let Some(val) = ex.args.first().and_then(|ex| ex.scalar_value()) {
1639            if val.is_nan() || val.is_infinite() || val <= 0.0 {
1640                return Ok(Expr::Call(ex));
1641            }
1642        }
1643    }
1644
1645    check_args_match_types(&ex.args.args, &ex.func.arg_types, name)?;
1646    Ok(Expr::Call(ex))
1647}
1648
1649fn check_call_arity(nargs: usize, variadic: i32, actual: usize, name: &str) -> Result<(), String> {
1650    if variadic == 0 {
1651        if nargs != actual {
1652            return Err(format!(
1653                "expected {nargs} argument(s) in call to '{name}', got {actual}"
1654            ));
1655        }
1656    } else {
1657        let na = nargs.saturating_sub(1);
1658        if na > actual {
1659            return Err(format!(
1660                "expected at least {na} argument(s) in call to '{name}', got {actual}"
1661            ));
1662        } else if variadic > 0 {
1663            let nargsmax = na + variadic as usize;
1664            if nargsmax < actual {
1665                return Err(format!(
1666                    "expected at most {nargsmax} argument(s) in call to '{name}', got {actual}"
1667                ));
1668            }
1669        }
1670    }
1671    Ok(())
1672}
1673
1674fn check_args_match_types(
1675    args: &[Box<Expr>],
1676    arg_types: &[ValueType],
1677    name: &str,
1678) -> Result<(), String> {
1679    for (i, actual_arg) in args.iter().enumerate() {
1680        let expected_idx = if i < arg_types.len() {
1681            i
1682        } else {
1683            arg_types.len() - 1
1684        };
1685        expect_type(
1686            arg_types[expected_idx],
1687            Some(actual_arg.value_type()),
1688            &format!("call to function '{name}'"),
1689        )?;
1690    }
1691    Ok(())
1692}
1693
1694fn check_ast_for_unary(ex: UnaryExpr) -> Result<Expr, String> {
1695    let value_type = ex.expr.value_type();
1696    if value_type != ValueType::Scalar && value_type != ValueType::Vector {
1697        return Err(format!(
1698            "unary expression only allowed on expressions of type scalar or vector, got {value_type}"
1699        ));
1700    }
1701
1702    Ok(Expr::Unary(ex))
1703}
1704
1705fn check_ast_for_subquery(ex: SubqueryExpr) -> Result<Expr, String> {
1706    let value_type = ex.expr.value_type();
1707    if value_type != ValueType::Vector {
1708        return Err(format!(
1709            "subquery is only allowed on vector, got {value_type} instead"
1710        ));
1711    }
1712
1713    Ok(Expr::Subquery(ex))
1714}
1715
1716fn check_ast_for_vector_selector(ex: VectorSelector) -> Result<Expr, String> {
1717    match ex.name {
1718        Some(ref name) => match ex.matchers.find_matcher_value(METRIC_NAME) {
1719            Some(val) => Err(format!(
1720                "metric name must not be set twice: '{name}' or '{val}'"
1721            )),
1722            None => Ok(Expr::VectorSelector(ex)),
1723        },
1724        None if ex.matchers.is_empty_matchers() => {
1725            // When name is None, a vector selector must contain at least one non-empty matcher
1726            // to prevent implicit selection of all metrics (e.g. by a typo).
1727            Err("vector selector must contain at least one non-empty matcher".into())
1728        }
1729        _ => Ok(Expr::VectorSelector(ex)),
1730    }
1731}
1732
1733#[cfg(test)]
1734mod tests {
1735    use super::*;
1736    use crate::label::{MatchOp, Matcher};
1737
1738    #[test]
1739    fn test_valid_at_modifier() {
1740        let cases = vec![
1741            // tuple: (seconds, elapsed milliseconds before or after UNIX_EPOCH)
1742            (0.0, 0),
1743            (1000.3, 1000300),    // after UNIX_EPOCH
1744            (1000.9, 1000900),    // after UNIX_EPOCH
1745            (1000.9991, 1000999), // after UNIX_EPOCH
1746            (1000.9999, 1001000), // after UNIX_EPOCH
1747            (-1000.3, 1000300),   // before UNIX_EPOCH
1748            (-1000.9, 1000900),   // before UNIX_EPOCH
1749        ];
1750
1751        for (secs, elapsed) in cases {
1752            match AtModifier::try_from(secs).unwrap() {
1753                AtModifier::At(st) => {
1754                    if secs.is_sign_positive() || secs == 0.0 {
1755                        assert_eq!(
1756                            elapsed,
1757                            st.duration_since(SystemTime::UNIX_EPOCH)
1758                                .unwrap()
1759                                .as_millis()
1760                        )
1761                    } else if secs.is_sign_negative() {
1762                        assert_eq!(
1763                            elapsed,
1764                            SystemTime::UNIX_EPOCH
1765                                .duration_since(st)
1766                                .unwrap()
1767                                .as_millis()
1768                        )
1769                    }
1770                }
1771                _ => panic!(),
1772            }
1773        }
1774
1775        assert_eq!(
1776            AtModifier::try_from(Expr::from(1.0)),
1777            AtModifier::try_from(1.0),
1778        );
1779    }
1780
1781    #[test]
1782    fn test_invalid_at_modifier() {
1783        let cases = vec![
1784            f64::MAX,
1785            f64::MIN,
1786            f64::NAN,
1787            f64::INFINITY,
1788            f64::NEG_INFINITY,
1789        ];
1790
1791        for secs in cases {
1792            assert!(AtModifier::try_from(secs).is_err())
1793        }
1794
1795        assert_eq!(
1796            AtModifier::try_from(token::T_ADD),
1797            Err("invalid @ modifier preprocessor '+', START or END is valid.".into())
1798        );
1799
1800        assert_eq!(
1801            AtModifier::try_from(Expr::from("string literal")),
1802            Err("invalid float value after @ modifier".into())
1803        );
1804    }
1805
1806    #[test]
1807    fn test_binary_labels() {
1808        assert_eq!(
1809            &Labels::new(vec!["foo", "bar"]),
1810            LabelModifier::Include(Labels::new(vec!["foo", "bar"])).labels()
1811        );
1812
1813        assert_eq!(
1814            &Labels::new(vec!["foo", "bar"]),
1815            LabelModifier::Exclude(Labels::new(vec!["foo", "bar"])).labels()
1816        );
1817
1818        assert_eq!(
1819            &Labels::new(vec!["foo", "bar"]),
1820            VectorMatchCardinality::OneToMany(Labels::new(vec!["foo", "bar"]))
1821                .labels()
1822                .unwrap()
1823        );
1824
1825        assert_eq!(
1826            &Labels::new(vec!["foo", "bar"]),
1827            VectorMatchCardinality::ManyToOne(Labels::new(vec!["foo", "bar"]))
1828                .labels()
1829                .unwrap()
1830        );
1831
1832        assert_eq!(VectorMatchCardinality::OneToOne.labels(), None);
1833        assert_eq!(VectorMatchCardinality::ManyToMany.labels(), None);
1834    }
1835
1836    #[test]
1837    fn test_neg() {
1838        assert_eq!(
1839            -VectorSelector::from("foo"),
1840            UnaryExpr {
1841                expr: Box::new(Expr::from(VectorSelector::from("foo")))
1842            }
1843        )
1844    }
1845
1846    #[test]
1847    fn test_scalar_value() {
1848        assert_eq!(Some(1.0), Expr::from(1.0).scalar_value());
1849        assert_eq!(None, Expr::from("1.0").scalar_value());
1850    }
1851
1852    #[test]
1853    fn test_at_expr() {
1854        assert_eq!(
1855            "@ <timestamp> may not be set multiple times",
1856            Expr::from(VectorSelector::from("foo"))
1857                .at_expr(AtModifier::try_from(1.0).unwrap())
1858                .and_then(|ex| ex.at_expr(AtModifier::try_from(1.0).unwrap()))
1859                .unwrap_err()
1860        );
1861
1862        assert_eq!(
1863            "@ <timestamp> may not be set multiple times",
1864            Expr::new_matrix_selector(
1865                Expr::from(VectorSelector::from("foo")),
1866                Duration::from_secs(1),
1867            )
1868            .and_then(|ex| ex.at_expr(AtModifier::try_from(1.0).unwrap()))
1869            .and_then(|ex| ex.at_expr(AtModifier::try_from(1.0).unwrap()))
1870            .unwrap_err()
1871        );
1872
1873        assert_eq!(
1874            "@ <timestamp> may not be set multiple times",
1875            Expr::new_subquery_expr(
1876                Expr::from(VectorSelector::from("foo")),
1877                Duration::from_secs(1),
1878                None,
1879            )
1880            .and_then(|ex| ex.at_expr(AtModifier::try_from(1.0).unwrap()))
1881            .and_then(|ex| ex.at_expr(AtModifier::try_from(1.0).unwrap()))
1882            .unwrap_err()
1883        )
1884    }
1885
1886    #[test]
1887    fn test_offset_expr() {
1888        assert_eq!(
1889            "offset may not be set multiple times",
1890            Expr::from(VectorSelector::from("foo"))
1891                .offset_expr(Offset::Pos(Duration::from_secs(1000)))
1892                .and_then(|ex| ex.offset_expr(Offset::Pos(Duration::from_secs(1000))))
1893                .unwrap_err()
1894        );
1895
1896        assert_eq!(
1897            "offset may not be set multiple times",
1898            Expr::new_matrix_selector(
1899                Expr::from(VectorSelector::from("foo")),
1900                Duration::from_secs(1),
1901            )
1902            .and_then(|ex| ex.offset_expr(Offset::Pos(Duration::from_secs(1000))))
1903            .and_then(|ex| ex.offset_expr(Offset::Pos(Duration::from_secs(1000))))
1904            .unwrap_err()
1905        );
1906
1907        assert_eq!(
1908            "offset may not be set multiple times",
1909            Expr::new_subquery_expr(
1910                Expr::from(VectorSelector::from("foo")),
1911                Duration::from_secs(1),
1912                None,
1913            )
1914            .and_then(|ex| ex.offset_expr(Offset::Pos(Duration::from_secs(1000))))
1915            .and_then(|ex| ex.offset_expr(Offset::Pos(Duration::from_secs(1000))))
1916            .unwrap_err()
1917        );
1918    }
1919
1920    #[test]
1921    fn test_expr_to_string() {
1922        let mut cases = vec![
1923            ("1", "1"),
1924            ("- 1", "-1"),
1925            ("+ 1", "1"),
1926            ("Inf", "Inf"),
1927            ("inf", "Inf"),
1928            ("+Inf", "Inf"),
1929            ("- Inf", "-Inf"),
1930            (".5", "0.5"),
1931            ("5.", "5"),
1932            ("123.4567", "123.4567"),
1933            ("5e-3", "0.005"),
1934            ("5e3", "5000"),
1935            ("0xc", "12"),
1936            ("0755", "493"),
1937            ("08", "8"),
1938            ("+5.5e-3", "0.0055"),
1939            ("-0755", "-493"),
1940            ("NaN", "NaN"),
1941            ("NAN", "NaN"),
1942            ("- 1^2", "-1 ^ 2"),
1943            ("+1 + -2 * 1", "1 + -2 * 1"),
1944            ("1 + 2/(3*1)", "1 + 2 / (3 * 1)"),
1945            ("foo*sum", "foo * sum"),
1946            ("foo * on(test,blub) bar", "foo * on (test, blub) bar"),
1947            (
1948                r#"up{job="hi", instance="in"} offset 5m @ 100"#,
1949                r#"up{instance="in",job="hi"} @ 100.000 offset 5m"#,
1950            ),
1951            (
1952                r#"up{job="hi", instance="in"}"#,
1953                r#"up{instance="in",job="hi"}"#,
1954            ),
1955            ("sum (up) by (job,instance)", "sum by (job, instance) (up)"),
1956            (
1957                "foo / on(test,blub) group_left(bar) bar",
1958                "foo / on (test, blub) group_left (bar) bar",
1959            ),
1960            (
1961                "foo / on(test,blub) group_right(bar) bar",
1962                "foo / on (test, blub) group_right (bar) bar",
1963            ),
1964            (
1965                r#"foo{a="b",foo!="bar",test=~"test",bar!~"baz"}"#,
1966                r#"foo{a="b",bar!~"baz",foo!="bar",test=~"test"}"#,
1967            ),
1968            (
1969                r#"{__name__=~"foo.+",__name__=~".*bar"}"#,
1970                r#"{__name__=~".*bar",__name__=~"foo.+"}"#,
1971            ),
1972            (
1973                r#"test{a="b"}[5y] OFFSET 3d"#,
1974                r#"test{a="b"}[5y] offset 3d"#,
1975            ),
1976            (
1977                r#"{a="b"}[5y] OFFSET 3d"#,
1978                r#"{a="b"}[5y] offset 3d"#,
1979            ),
1980            (
1981                "sum(some_metric) without(and, by, avg, count, alert, annotations)",
1982                "sum without (and, by, avg, count, alert, annotations) (some_metric)",
1983            ),
1984            (
1985                r#"floor(some_metric{foo!="bar"})"#,
1986                r#"floor(some_metric{foo!="bar"})"#,
1987            ),
1988            (
1989                "sum(rate(http_request_duration_seconds[10m])) / count(rate(http_request_duration_seconds[10m]))",
1990                "sum(rate(http_request_duration_seconds[10m])) / count(rate(http_request_duration_seconds[10m]))",
1991            ),
1992            ("rate(some_metric[5m])", "rate(some_metric[5m])"),
1993            ("round(some_metric,5)", "round(some_metric, 5)"),
1994            (
1995                r#"absent(sum(nonexistent{job="myjob"}))"#,
1996                r#"absent(sum(nonexistent{job="myjob"}))"#,
1997            ),
1998            (
1999                "histogram_quantile(0.9,rate(http_request_duration_seconds_bucket[10m]))",
2000                "histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[10m]))",
2001            ),
2002            (
2003                "histogram_quantile(0.9,sum(rate(http_request_duration_seconds_bucket[10m])) by(job,le))",
2004                "histogram_quantile(0.9, sum by (job, le) (rate(http_request_duration_seconds_bucket[10m])))",
2005            ),
2006            (
2007                r#"label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")"#,
2008                r#"label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")"#,
2009            ),
2010            (
2011                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s] @ 100"#,
2012                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s] @ 100.000"#,
2013            ),
2014            (
2015                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]"#,
2016                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:])[4m:3s]"#,
2017            ),
2018            (
2019                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 4m)[4m:3s]"#,
2020                r#"min_over_time(rate(foo{bar="baz"}[2s])[5m:] offset 4m)[4m:3s]"#,
2021            ),
2022            ("some_metric OFFSET 1m [10m:5s]", "some_metric offset 1m[10m:5s]"),
2023            ("some_metric @123 [10m:5s]", "some_metric @ 123.000[10m:5s]"),
2024            ("some_metric <= 1ms", "some_metric <= 0.001"),
2025        ];
2026
2027        // the following cases are from https://github.com/prometheus/prometheus/blob/main/promql/parser/printer_test.go
2028        let mut cases1 = vec![
2029            (
2030                r#"sum by() (task:errors:rate10s{job="s"})"#,
2031                r#"sum(task:errors:rate10s{job="s"})"#,
2032            ),
2033            (
2034                r#"sum by(code) (task:errors:rate10s{job="s"})"#,
2035                r#"sum by (code) (task:errors:rate10s{job="s"})"#,
2036            ),
2037            (
2038                r#"sum without() (task:errors:rate10s{job="s"})"#,
2039                r#"sum without () (task:errors:rate10s{job="s"})"#,
2040            ),
2041            (
2042                r#"sum without(instance) (task:errors:rate10s{job="s"})"#,
2043                r#"sum without (instance) (task:errors:rate10s{job="s"})"#,
2044            ),
2045            (
2046                r#"topk(5, task:errors:rate10s{job="s"})"#,
2047                r#"topk(5, task:errors:rate10s{job="s"})"#,
2048            ),
2049            (
2050                r#"count_values("value", task:errors:rate10s{job="s"})"#,
2051                r#"count_values("value", task:errors:rate10s{job="s"})"#,
2052            ),
2053            ("a - on() c", "a - on () c"),
2054            ("a - on(b) c", "a - on (b) c"),
2055            ("a - on(b) group_left(x) c", "a - on (b) group_left (x) c"),
2056            (
2057                "a - on(b) group_left(x, y) c",
2058                "a - on (b) group_left (x, y) c",
2059            ),
2060            ("a - on(b) group_left c", "a - on (b) group_left () c"),
2061            ("a - ignoring(b) c", "a - ignoring (b) c"),
2062            ("a - ignoring() c", "a - c"),
2063            ("a + fill(-23) b", "a + fill (-23) b"),
2064            ("a + fill_left(-23) b", "a + fill_left (-23) b"),
2065            ("a + fill_right(42) b", "a + fill_right (42) b"),
2066            (
2067                "a + fill_left(-23) fill_right(42) b",
2068                "a + fill_left (-23) fill_right (42) b",
2069            ),
2070            (
2071                "a + on(b) group_left fill(-23) c",
2072                "a + on (b) group_left () fill (-23) c",
2073            ),
2074            ("up > bool 0", "up > bool 0"),
2075            ("a offset 1m", "a offset 1m"),
2076            ("a offset -7m", "a offset -7m"),
2077            (r#"a{c="d"}[5m] offset 1m"#, r#"a{c="d"}[5m] offset 1m"#),
2078            ("a[5m] offset 1m", "a[5m] offset 1m"),
2079            ("a[12m] offset -3m", "a[12m] offset -3m"),
2080            ("a[1h:5m] offset 1m", "a[1h:5m] offset 1m"),
2081            (r#"{__name__="a"}"#, r#"{__name__="a"}"#),
2082            (r#"a{b!="c"}[1m]"#, r#"a{b!="c"}[1m]"#),
2083            (r#"a{b=~"c"}[1m]"#, r#"a{b=~"c"}[1m]"#),
2084            (r#"a{b!~"c"}[1m]"#, r#"a{b!~"c"}[1m]"#),
2085            ("a @ 10", "a @ 10.000"),
2086            ("a[1m] @ 10", "a[1m] @ 10.000"),
2087            ("a @ start()", "a @ start()"),
2088            ("a @ end()", "a @ end()"),
2089            ("a[1m] @ start()", "a[1m] @ start()"),
2090            ("a[1m] @ end()", "a[1m] @ end()"),
2091        ];
2092
2093        // the following cases copy the tests from the following: https://github.com/prometheus/prometheus/pull/9138
2094        let mut cases2 = vec![
2095            (
2096                r#"test{a="b"}[5y] OFFSET 3d"#,
2097                r#"test{a="b"}[5y] offset 3d"#,
2098            ),
2099            (
2100                r#"test{a="b"}[5m] OFFSET 3600"#,
2101                r#"test{a="b"}[5m] offset 1h"#,
2102            ),
2103            ("foo[3ms] @ 2.345", "foo[3ms] @ 2.345"),
2104            ("foo[4s180ms] @ 2.345", "foo[4s180ms] @ 2.345"),
2105            ("foo[4.18] @ 2.345", "foo[4s180ms] @ 2.345"),
2106            ("foo[4s18ms] @ 2.345", "foo[4s18ms] @ 2.345"),
2107            ("foo[4.018] @ 2.345", "foo[4s18ms] @ 2.345"),
2108            ("test[5]", "test[5s]"),
2109            ("some_metric[5m] @ 1m", "some_metric[5m] @ 60.000"),
2110            ("metric @ 100s", "metric @ 100.000"),
2111            ("metric @ 1m40s", "metric @ 100.000"),
2112            ("metric @ 100 offset 50", "metric @ 100.000 offset 50s"),
2113            ("metric offset 50 @ 100", "metric @ 100.000 offset 50s"),
2114            ("metric @ 0 offset -50", "metric @ 0.000 offset -50s"),
2115            ("metric offset -50 @ 0", "metric @ 0.000 offset -50s"),
2116            (
2117                r#"sum_over_time(metric{job="1"}[100] @ 100 offset 50)"#,
2118                r#"sum_over_time(metric{job="1"}[1m40s] @ 100.000 offset 50s)"#,
2119            ),
2120            (
2121                r#"sum_over_time(metric{job="1"}[100] offset 50s @ 100)"#,
2122                r#"sum_over_time(metric{job="1"}[1m40s] @ 100.000 offset 50s)"#,
2123            ),
2124            (
2125                r#"sum_over_time(metric{job="1"}[100] @ 100) + label_replace(sum_over_time(metric{job="2"}[100] @ 100), "job", "1", "", "")"#,
2126                r#"sum_over_time(metric{job="1"}[1m40s] @ 100.000) + label_replace(sum_over_time(metric{job="2"}[1m40s] @ 100.000), "job", "1", "", "")"#,
2127            ),
2128            (
2129                r#"sum_over_time(metric{job="1"}[100:1] offset 20 @ 100)"#,
2130                r#"sum_over_time(metric{job="1"}[1m40s:1s] @ 100.000 offset 20s)"#,
2131            ),
2132        ];
2133
2134        cases.append(&mut cases1);
2135        cases.append(&mut cases2);
2136        for (input, expected) in cases {
2137            let expr = crate::parser::parse(input).unwrap();
2138            assert_eq!(expected, expr.to_string())
2139        }
2140    }
2141
2142    #[test]
2143    fn test_vector_selector_to_string() {
2144        let cases = vec![
2145            (VectorSelector::default(), ""),
2146            (VectorSelector::from("foobar"), "foobar"),
2147            (
2148                {
2149                    let name = Some(String::from("foobar"));
2150                    let matchers = Matchers::one(Matcher::new(MatchOp::Equal, "a", "x"));
2151                    VectorSelector::new(name, matchers)
2152                },
2153                r#"foobar{a="x"}"#,
2154            ),
2155            (
2156                {
2157                    let matchers = Matchers::new(vec![
2158                        Matcher::new(MatchOp::Equal, "a", "x"),
2159                        Matcher::new(MatchOp::Equal, "b", "y"),
2160                    ]);
2161                    VectorSelector::new(None, matchers)
2162                },
2163                r#"{a="x",b="y"}"#,
2164            ),
2165            (
2166                {
2167                    let matchers =
2168                        Matchers::one(Matcher::new(MatchOp::Equal, METRIC_NAME, "foobar"));
2169                    VectorSelector::new(None, matchers)
2170                },
2171                r#"{__name__="foobar"}"#,
2172            ),
2173        ];
2174
2175        for (vs, expect) in cases {
2176            assert_eq!(expect, vs.to_string())
2177        }
2178    }
2179
2180    #[test]
2181    fn test_aggregate_expr_pretty() {
2182        let cases = vec![
2183            ("sum(foo)", "sum(foo)"),
2184            (
2185                r#"sum by() (task:errors:rate10s{job="s"})"#,
2186                r#"sum(
2187  task:errors:rate10s{job="s"}
2188)"#,
2189            ),
2190            (
2191                r#"sum without(job,foo) (task:errors:rate10s{job="s"})"#,
2192                r#"sum without (job, foo) (
2193  task:errors:rate10s{job="s"}
2194)"#,
2195            ),
2196            (
2197                r#"sum(task:errors:rate10s{job="s"}) without(job,foo)"#,
2198                r#"sum without (job, foo) (
2199  task:errors:rate10s{job="s"}
2200)"#,
2201            ),
2202            (
2203                r#"sum by(job,foo) (task:errors:rate10s{job="s"})"#,
2204                r#"sum by (job, foo) (
2205  task:errors:rate10s{job="s"}
2206)"#,
2207            ),
2208            (
2209                r#"sum (task:errors:rate10s{job="s"}) by(job,foo)"#,
2210                r#"sum by (job, foo) (
2211  task:errors:rate10s{job="s"}
2212)"#,
2213            ),
2214            (
2215                r#"topk(10, ask:errors:rate10s{job="s"})"#,
2216                r#"topk(
2217  10,
2218  ask:errors:rate10s{job="s"}
2219)"#,
2220            ),
2221            (
2222                r#"sum by(job,foo) (sum by(job,foo) (task:errors:rate10s{job="s"}))"#,
2223                r#"sum by (job, foo) (
2224  sum by (job, foo) (
2225    task:errors:rate10s{job="s"}
2226  )
2227)"#,
2228            ),
2229            (
2230                r#"sum by(job,foo) (sum by(job,foo) (sum by(job,foo) (task:errors:rate10s{job="s"})))"#,
2231                r#"sum by (job, foo) (
2232  sum by (job, foo) (
2233    sum by (job, foo) (
2234      task:errors:rate10s{job="s"}
2235    )
2236  )
2237)"#,
2238            ),
2239            (
2240                r#"sum by(job,foo)
2241(sum by(job,foo) (task:errors:rate10s{job="s"}))"#,
2242                r#"sum by (job, foo) (
2243  sum by (job, foo) (
2244    task:errors:rate10s{job="s"}
2245  )
2246)"#,
2247            ),
2248            (
2249                r#"sum by(job,foo)
2250(sum(task:errors:rate10s{job="s"}) without(job,foo))"#,
2251                r#"sum by (job, foo) (
2252  sum without (job, foo) (
2253    task:errors:rate10s{job="s"}
2254  )
2255)"#,
2256            ),
2257            (
2258                r#"sum by(job,foo) # Comment 1.
2259(sum by(job,foo) ( # Comment 2.
2260task:errors:rate10s{job="s"}))"#,
2261                r#"sum by (job, foo) (
2262  sum by (job, foo) (
2263    task:errors:rate10s{job="s"}
2264  )
2265)"#,
2266            ),
2267        ];
2268
2269        for (input, expect) in cases {
2270            let expr = crate::parser::parse(input);
2271            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2272        }
2273    }
2274
2275    #[test]
2276    fn test_binary_expr_pretty() {
2277        let cases = vec![
2278            ("a+b", "a + b"),
2279            (
2280                "a == bool 1",
2281                "  a
2282== bool
2283  1",
2284            ),
2285            (
2286                "a == 1024000",
2287                "  a
2288==
2289  1024000",
2290            ),
2291            (
2292                "a + ignoring(job) b",
2293                "  a
2294+ ignoring (job)
2295  b",
2296            ),
2297            (
2298                "foo_1 + foo_2",
2299                "  foo_1
2300+
2301  foo_2",
2302            ),
2303            (
2304                "foo_1 + foo_2 + foo_3",
2305                "    foo_1
2306  +
2307    foo_2
2308+
2309  foo_3",
2310            ),
2311            (
2312                "foo + baar + foo_3",
2313                "  foo + baar
2314+
2315  foo_3",
2316            ),
2317            (
2318                "foo_1 + foo_2 + foo_3 + foo_4",
2319                "      foo_1
2320    +
2321      foo_2
2322  +
2323    foo_3
2324+
2325  foo_4",
2326            ),
2327            (
2328                "foo_1 + ignoring(foo) foo_2 + ignoring(job) group_left foo_3 + on(instance) group_right foo_4",
2329
2330                 "      foo_1
2331    + ignoring (foo)
2332      foo_2
2333  + ignoring (job) group_left ()
2334    foo_3
2335+ on (instance) group_right ()
2336  foo_4",
2337            ),
2338        ];
2339
2340        for (input, expect) in cases {
2341            let expr = crate::parser::parse(input);
2342            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2343        }
2344    }
2345
2346    #[test]
2347    fn test_call_expr_pretty() {
2348        let cases = vec![
2349            (
2350                "rate(foo[1m])",
2351                "rate(
2352  foo[1m]
2353)",
2354            ),
2355            (
2356                "sum_over_time(foo[1m])",
2357                "sum_over_time(
2358  foo[1m]
2359)",
2360            ),
2361            (
2362                "rate(long_vector_selector[10m:1m] @ start() offset 1m)",
2363                "rate(
2364  long_vector_selector[10m:1m] @ start() offset 1m
2365)",
2366            ),
2367            (
2368                "histogram_quantile(0.9, rate(foo[1m]))",
2369                "histogram_quantile(
2370  0.9,
2371  rate(
2372    foo[1m]
2373  )
2374)",
2375            ),
2376            (
2377                "histogram_quantile(0.9, rate(foo[1m] @ start()))",
2378                "histogram_quantile(
2379  0.9,
2380  rate(
2381    foo[1m] @ start()
2382  )
2383)",
2384            ),
2385            (
2386                "max_over_time(rate(demo_api_request_duration_seconds_count[1m])[1m:] @ start() offset 1m)",
2387                "max_over_time(
2388  rate(
2389    demo_api_request_duration_seconds_count[1m]
2390  )[1m:] @ start() offset 1m
2391)",
2392            ),
2393            (
2394                r#"label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")"#,
2395                r#"label_replace(
2396  up{job="api-server",service="a:c"},
2397  "foo",
2398  "$1",
2399  "service",
2400  "(.*):.*"
2401)"#,
2402            ),
2403            (
2404                r#"label_replace(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*")"#,
2405                r#"label_replace(
2406  label_replace(
2407    up{job="api-server",service="a:c"},
2408    "foo",
2409    "$1",
2410    "service",
2411    "(.*):.*"
2412  ),
2413  "foo",
2414  "$1",
2415  "service",
2416  "(.*):.*"
2417)"#,
2418            ),
2419        ];
2420
2421        for (input, expect) in cases {
2422            let expr = crate::parser::parse(input);
2423            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2424        }
2425    }
2426
2427    #[test]
2428    fn test_paren_expr_pretty() {
2429        let cases = vec![
2430            ("(foo)", "(foo)"),
2431            (
2432                "(_foo_long_)",
2433                "(
2434  _foo_long_
2435)",
2436            ),
2437            (
2438                "((foo_long))",
2439                "(
2440  (foo_long)
2441)",
2442            ),
2443            (
2444                "((_foo_long_))",
2445                "(
2446  (
2447    _foo_long_
2448  )
2449)",
2450            ),
2451            (
2452                "(((foo_long)))",
2453                "(
2454  (
2455    (foo_long)
2456  )
2457)",
2458            ),
2459            ("(1 + 2)", "(1 + 2)"),
2460            (
2461                "(foo + bar)",
2462                "(
2463  foo + bar
2464)",
2465            ),
2466            (
2467                "(foo_long + bar_long)",
2468                "(
2469    foo_long
2470  +
2471    bar_long
2472)",
2473            ),
2474            (
2475                "(foo_long + bar_long + bar_2_long)",
2476                "(
2477      foo_long
2478    +
2479      bar_long
2480  +
2481    bar_2_long
2482)",
2483            ),
2484            (
2485                "((foo_long + bar_long) + bar_2_long)",
2486                "(
2487    (
2488        foo_long
2489      +
2490        bar_long
2491    )
2492  +
2493    bar_2_long
2494)",
2495            ),
2496            (
2497                "(1111 + 2222)",
2498                "(
2499    1111
2500  +
2501    2222
2502)",
2503            ),
2504            (
2505                "(sum_over_time(foo[1m]))",
2506                "(
2507  sum_over_time(
2508    foo[1m]
2509  )
2510)",
2511            ),
2512            (
2513                r#"(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"))"#,
2514                r#"(
2515  label_replace(
2516    up{job="api-server",service="a:c"},
2517    "foo",
2518    "$1",
2519    "service",
2520    "(.*):.*"
2521  )
2522)"#,
2523            ),
2524            (
2525                r#"(label_replace(label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*"))"#,
2526                r#"(
2527  label_replace(
2528    label_replace(
2529      up{job="api-server",service="a:c"},
2530      "foo",
2531      "$1",
2532      "service",
2533      "(.*):.*"
2534    ),
2535    "foo",
2536    "$1",
2537    "service",
2538    "(.*):.*"
2539  )
2540)"#,
2541            ),
2542            (
2543                r#"(label_replace(label_replace((up{job="api-server",service="a:c"}), "foo", "$1", "service", "(.*):.*"), "foo", "$1", "service", "(.*):.*"))"#,
2544                r#"(
2545  label_replace(
2546    label_replace(
2547      (
2548        up{job="api-server",service="a:c"}
2549      ),
2550      "foo",
2551      "$1",
2552      "service",
2553      "(.*):.*"
2554    ),
2555    "foo",
2556    "$1",
2557    "service",
2558    "(.*):.*"
2559  )
2560)"#,
2561            ),
2562        ];
2563
2564        for (input, expect) in cases {
2565            let expr = crate::parser::parse(input);
2566            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2567        }
2568    }
2569
2570    #[test]
2571    fn test_unary_expr_pretty() {
2572        let cases = vec![
2573            ("-1", "-1"),
2574            ("-vector_selector", "-vector_selector"),
2575            (
2576                "(-vector_selector)",
2577                "(
2578  -vector_selector
2579)",
2580            ),
2581            (
2582                "-histogram_quantile(0.9,rate(foo[1m]))",
2583                "-histogram_quantile(
2584  0.9,
2585  rate(
2586    foo[1m]
2587  )
2588)",
2589            ),
2590            (
2591                "-histogram_quantile(0.99, sum by (le) (rate(foo[1m])))",
2592                "-histogram_quantile(
2593  0.99,
2594  sum by (le) (
2595    rate(
2596      foo[1m]
2597    )
2598  )
2599)",
2600            ),
2601            (
2602                "-histogram_quantile(0.9, -rate(foo[1m] @ start()))",
2603                "-histogram_quantile(
2604  0.9,
2605  -rate(
2606    foo[1m] @ start()
2607  )
2608)",
2609            ),
2610            (
2611                "(-histogram_quantile(0.9, -rate(foo[1m] @ start())))",
2612                "(
2613  -histogram_quantile(
2614    0.9,
2615    -rate(
2616      foo[1m] @ start()
2617    )
2618  )
2619)",
2620            ),
2621        ];
2622
2623        for (input, expect) in cases {
2624            let expr = crate::parser::parse(input);
2625            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2626        }
2627    }
2628
2629    #[test]
2630    fn test_expr_pretty() {
2631        // Following queries have been taken from https://monitoring.mixins.dev/
2632        let cases = vec![
2633            (
2634                r#"(node_filesystem_avail_bytes{job="node",fstype!=""} / node_filesystem_size_bytes{job="node",fstype!=""} * 100 < 40 and predict_linear(node_filesystem_avail_bytes{job="node",fstype!=""}[6h], 24*60*60) < 0 and node_filesystem_readonly{job="node",fstype!=""} == 0)"#,
2635                r#"(
2636            node_filesystem_avail_bytes{fstype!="",job="node"}
2637          /
2638            node_filesystem_size_bytes{fstype!="",job="node"}
2639        *
2640          100
2641      <
2642        40
2643    and
2644        predict_linear(
2645          node_filesystem_avail_bytes{fstype!="",job="node"}[6h],
2646            24 * 60
2647          *
2648            60
2649        )
2650      <
2651        0
2652  and
2653      node_filesystem_readonly{fstype!="",job="node"}
2654    ==
2655      0
2656)"#,
2657            ),
2658            (
2659                r#"(node_filesystem_avail_bytes{job="node",fstype!=""} / node_filesystem_size_bytes{job="node",fstype!=""} * 100 < 20 and predict_linear(node_filesystem_avail_bytes{job="node",fstype!=""}[6h], 4*60*60) < 0 and node_filesystem_readonly{job="node",fstype!=""} == 0)"#,
2660                r#"(
2661            node_filesystem_avail_bytes{fstype!="",job="node"}
2662          /
2663            node_filesystem_size_bytes{fstype!="",job="node"}
2664        *
2665          100
2666      <
2667        20
2668    and
2669        predict_linear(
2670          node_filesystem_avail_bytes{fstype!="",job="node"}[6h],
2671            4 * 60
2672          *
2673            60
2674        )
2675      <
2676        0
2677  and
2678      node_filesystem_readonly{fstype!="",job="node"}
2679    ==
2680      0
2681)"#,
2682            ),
2683            (
2684                r#"(node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)"#,
2685                r#"  (
2686        node_timex_offset_seconds
2687      >
2688        0.05
2689    and
2690        deriv(
2691          node_timex_offset_seconds[5m]
2692        )
2693      >=
2694        0
2695  )
2696or
2697  (
2698        node_timex_offset_seconds
2699      <
2700        -0.05
2701    and
2702        deriv(
2703          node_timex_offset_seconds[5m]
2704        )
2705      <=
2706        0
2707  )"#,
2708            ),
2709            (
2710                r#"1 - ((node_memory_MemAvailable_bytes{job="node"} or (node_memory_Buffers_bytes{job="node"} + node_memory_Cached_bytes{job="node"} + node_memory_MemFree_bytes{job="node"} + node_memory_Slab_bytes{job="node"}) ) / node_memory_MemTotal_bytes{job="node"})"#,
2711                r#"  1
2712-
2713  (
2714      (
2715          node_memory_MemAvailable_bytes{job="node"}
2716        or
2717          (
2718                  node_memory_Buffers_bytes{job="node"}
2719                +
2720                  node_memory_Cached_bytes{job="node"}
2721              +
2722                node_memory_MemFree_bytes{job="node"}
2723            +
2724              node_memory_Slab_bytes{job="node"}
2725          )
2726      )
2727    /
2728      node_memory_MemTotal_bytes{job="node"}
2729  )"#,
2730            ),
2731            (
2732                r#"min by (job, integration) (rate(alertmanager_notifications_failed_total{job="alertmanager", integration=~".*"}[5m]) / rate(alertmanager_notifications_total{job="alertmanager", integration="~.*"}[5m])) > 0.01"#,
2733                r#"  min by (job, integration) (
2734      rate(
2735        alertmanager_notifications_failed_total{integration=~".*",job="alertmanager"}[5m]
2736      )
2737    /
2738      rate(
2739        alertmanager_notifications_total{integration="~.*",job="alertmanager"}[5m]
2740      )
2741  )
2742>
2743  0.01"#,
2744            ),
2745            (
2746                r#"(count by (job) (changes(process_start_time_seconds{job="alertmanager"}[10m]) > 4) / count by (job) (up{job="alertmanager"})) >= 0.5"#,
2747                r#"  (
2748      count by (job) (
2749          changes(
2750            process_start_time_seconds{job="alertmanager"}[10m]
2751          )
2752        >
2753          4
2754      )
2755    /
2756      count by (job) (
2757        up{job="alertmanager"}
2758      )
2759  )
2760>=
2761  0.5"#,
2762            ),
2763        ];
2764
2765        for (input, expect) in cases {
2766            let expr = crate::parser::parse(input);
2767            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2768        }
2769    }
2770
2771    #[test]
2772    fn test_step_invariant_pretty() {
2773        let cases = vec![
2774            ("a @ 1", "a @ 1.000"),
2775            ("a @ start()", "a @ start()"),
2776            ("vector_selector @ start()", "vector_selector @ start()"),
2777        ];
2778
2779        for (input, expect) in cases {
2780            let expr = crate::parser::parse(input);
2781            assert_eq!(expect, expr.unwrap().pretty(0, 10));
2782        }
2783    }
2784
2785    #[test]
2786    fn test_prettify() {
2787        let cases = vec![
2788            ("vector_selector", "vector_selector"),
2789            (
2790                r#"vector_selector{fooooooooooooooooo="barrrrrrrrrrrrrrrrrrr",barrrrrrrrrrrrrrrrrrr="fooooooooooooooooo",process_name="alertmanager"}"#,
2791                r#"vector_selector{barrrrrrrrrrrrrrrrrrr="fooooooooooooooooo",fooooooooooooooooo="barrrrrrrrrrrrrrrrrrr",process_name="alertmanager"}"#,
2792            ),
2793            (
2794                r#"matrix_selector{fooooooooooooooooo="barrrrrrrrrrrrrrrrrrr",barrrrrrrrrrrrrrrrrrr="fooooooooooooooooo",process_name="alertmanager"}[1y2w3d]"#,
2795                r#"matrix_selector{barrrrrrrrrrrrrrrrrrr="fooooooooooooooooo",fooooooooooooooooo="barrrrrrrrrrrrrrrrrrr",process_name="alertmanager"}[382d]"#,
2796            ),
2797        ];
2798
2799        for (input, expect) in cases {
2800            assert_eq!(expect, crate::parser::parse(input).unwrap().prettify());
2801        }
2802    }
2803
2804    #[test]
2805    fn test_eval_stmt_to_string() {
2806        let query = r#"http_requests_total{job="apiserver", handler="/api/comments"}[5m]"#;
2807        let start = "2024-10-08T07:15:00.022978+00:00";
2808        let end = "2024-10-08T07:15:30.012978+00:00";
2809        let expect = r#"[http_requests_total{handler="/api/comments",job="apiserver"}[5m]] @ [2024-10-08T07:15:00.022978+00:00, 2024-10-08T07:15:30.012978+00:00, 1m, 5m]"#;
2810
2811        let stmt = EvalStmt {
2812            expr: crate::parser::parse(query).unwrap(),
2813            start: DateTime::parse_from_rfc3339(start)
2814                .unwrap()
2815                .with_timezone(&Utc)
2816                .into(),
2817            end: DateTime::parse_from_rfc3339(end)
2818                .unwrap()
2819                .with_timezone(&Utc)
2820                .into(),
2821            interval: Duration::from_secs(60),
2822            lookback_delta: Duration::from_secs(300),
2823        };
2824
2825        assert_eq!(expect, stmt.to_string());
2826    }
2827
2828    fn make_call(func_name: &str, arg_count: usize) -> Call {
2829        use crate::parser::function::get_function;
2830        let func =
2831            get_function(func_name).unwrap_or_else(|| panic!("unknown function: {func_name}"));
2832        let args: Vec<Box<Expr>> = (0..arg_count)
2833            .map(|_| Box::new(Expr::VectorSelector(VectorSelector::from("foo"))))
2834            .collect();
2835        Call {
2836            func,
2837            args: FunctionArgs { args },
2838        }
2839    }
2840
2841    #[test]
2842    fn test_call_arity_variadic_zero() {
2843        // floor: arg_types=[Vector], variadic=0 → exact 1 arg required
2844        assert!(check_ast(Expr::Call(make_call("floor", 1))).is_ok());
2845
2846        let err = check_ast(Expr::Call(make_call("floor", 0))).unwrap_err();
2847        assert!(
2848            err.contains("expected 1 argument(s) in call to 'floor', got 0"),
2849            "{err}"
2850        );
2851
2852        let err = check_ast(Expr::Call(make_call("floor", 2))).unwrap_err();
2853        assert!(
2854            err.contains("expected 1 argument(s) in call to 'floor', got 2"),
2855            "{err}"
2856        );
2857    }
2858
2859    #[test]
2860    fn test_call_arity_bounded_variadic_single_arg_type() {
2861        // days_in_month: arg_types=[Vector], variadic=1 → min=0, max=1
2862        // 0 args is valid (default); only "too many" is enforced
2863        assert!(check_ast(Expr::Call(make_call("days_in_month", 1))).is_ok());
2864
2865        let err = check_ast(Expr::Call(make_call("days_in_month", 2))).unwrap_err();
2866        assert!(
2867            err.contains("expected at most 1 argument(s) in call to 'days_in_month', got 2"),
2868            "{err}"
2869        );
2870    }
2871
2872    #[test]
2873    fn test_call_arity_bounded_variadic_two_arg_types() {
2874        // round: arg_types=[Vector, Scalar], variadic=1 → min=1, max=2
2875        let err = check_ast(Expr::Call(make_call("round", 0))).unwrap_err();
2876        assert!(
2877            err.contains("expected at least 1 argument(s) in call to 'round', got 0"),
2878            "{err}"
2879        );
2880
2881        let err = check_ast(Expr::Call(make_call("round", 3))).unwrap_err();
2882        assert!(
2883            err.contains("expected at most 2 argument(s) in call to 'round', got 3"),
2884            "{err}"
2885        );
2886
2887        // info: arg_types=[Vector, Vector], variadic=1 → min=1, max=2
2888        let err = check_ast(Expr::Call(make_call("info", 0))).unwrap_err();
2889        assert!(
2890            err.contains("expected at least 1 argument(s) in call to 'info', got 0"),
2891            "{err}"
2892        );
2893
2894        let err = check_ast(Expr::Call(make_call("info", 3))).unwrap_err();
2895        assert!(
2896            err.contains("expected at most 2 argument(s) in call to 'info', got 3"),
2897            "{err}"
2898        );
2899    }
2900
2901    #[test]
2902    fn test_call_arity_bounded_variadic_large() {
2903        // histogram_quantiles: arg_types=[Vector, String, Scalar, Scalar], variadic=9 → min=3, max=12
2904        let err = check_ast(Expr::Call(make_call("histogram_quantiles", 2))).unwrap_err();
2905        assert!(
2906            err.contains("expected at least 3 argument(s) in call to 'histogram_quantiles', got 2"),
2907            "{err}"
2908        );
2909
2910        let err = check_ast(Expr::Call(make_call("histogram_quantiles", 13))).unwrap_err();
2911        assert!(
2912            err.contains(
2913                "expected at most 12 argument(s) in call to 'histogram_quantiles', got 13"
2914            ),
2915            "{err}"
2916        );
2917    }
2918
2919    #[test]
2920    fn test_call_arity_unbounded_variadic() {
2921        // label_join: arg_types=[Vector, String, String, String], variadic=-1 → min=3, no max
2922        let err = check_ast(Expr::Call(make_call("label_join", 2))).unwrap_err();
2923        assert!(
2924            err.contains("expected at least 3 argument(s) in call to 'label_join', got 2"),
2925            "{err}"
2926        );
2927
2928        // sort_by_label: arg_types=[Vector, String], variadic=-1 → min=1, no max
2929        let err = check_ast(Expr::Call(make_call("sort_by_label", 0))).unwrap_err();
2930        assert!(
2931            err.contains("expected at least 1 argument(s) in call to 'sort_by_label', got 0"),
2932            "{err}"
2933        );
2934    }
2935
2936    #[test]
2937    fn test_prettify_with_utf8_labels() {
2938        // Test that labels with special characters are properly quoted in display
2939        let cases = vec![
2940            // (input, expected_display)
2941            (r#"{"some.metric"}"#, r#"{__name__="some.metric"}"#),
2942            (
2943                r#"foo{"label.with.dots"="value"}"#,
2944                r#"foo{"label.with.dots"="value"}"#,
2945            ),
2946            (
2947                r#"bar{"label-with-dashes"="test"}"#,
2948                r#"bar{"label-with-dashes"="test"}"#,
2949            ),
2950            (
2951                r#"baz{"label:with:colons"="data"}"#,
2952                r#"baz{"label:with:colons"="data"}"#,
2953            ),
2954            (
2955                r#"sum by ("service.version", foo) ({"some.metric"})"#,
2956                r#"sum by ("service.version", foo) ({__name__="some.metric"})"#,
2957            ),
2958            (
2959                r#"sum by (`service.version`, foo) ({"some.metric"})"#,
2960                r#"sum by ("service.version", foo) ({__name__="some.metric"})"#,
2961            ),
2962            // Regular labels should not be quoted
2963            (r#"foo{job="web"}"#, r#"foo{job="web"}"#),
2964            (
2965                r#"bar{instance_id="server1"}"#,
2966                r#"bar{instance_id="server1"}"#,
2967            ),
2968        ];
2969
2970        for (input, expected) in cases {
2971            let parsed = crate::parser::parse(input).unwrap();
2972            let prettified = parsed.prettify();
2973            assert_eq!(prettified, expected);
2974        }
2975    }
2976
2977    #[test]
2978    fn test_prettify_escape_roundtrip() {
2979        // Queries with backslash escapes must survive parse → prettify → re-parse
2980        let cases = vec![
2981            // Escaped dot in regex matcher
2982            (
2983                r#"{__name__="up",service=~"flagd\\.evaluation\\.v1\\.Service"}"#,
2984                r#"{__name__="up",service=~"flagd\\.evaluation\\.v1\\.Service"}"#,
2985            ),
2986            // Escaped pipe
2987            (
2988                r#"{__name__="up",tag=~"a\\|b"}"#,
2989                r#"{__name__="up",tag=~"a\\|b"}"#,
2990            ),
2991            // Literal backslash in value
2992            (r#"{path="C:\\\\Windows"}"#, r#"{path="C:\\\\Windows"}"#),
2993            // Embedded double quote
2994            (r#"{msg="say \"hello\""}"#, r#"{msg="say \"hello\""}"#),
2995        ];
2996
2997        for (input, expected) in &cases {
2998            let parsed = crate::parser::parse(input).unwrap();
2999            let prettified = parsed.prettify();
3000            assert_eq!(
3001                &prettified, expected,
3002                "prettify mismatch for input: {input}"
3003            );
3004
3005            // Roundtrip: re-parsing the prettified output must succeed and produce the same result
3006            let reparsed = crate::parser::parse(&prettified).unwrap();
3007            assert_eq!(
3008                parsed.prettify(),
3009                reparsed.prettify(),
3010                "roundtrip failed for input: {input}"
3011            );
3012        }
3013    }
3014}