Skip to main content

promql_parser/parser/
function.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 std::collections::{HashMap, HashSet};
16use std::fmt;
17
18use lazy_static::lazy_static;
19
20use crate::parser::value::ValueType;
21use crate::parser::{Expr, Prettier};
22use crate::util::join_vector;
23
24/// called by func in Call
25#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "ser", derive(serde::Serialize))]
27pub struct FunctionArgs {
28    pub args: Vec<Box<Expr>>,
29}
30
31impl FunctionArgs {
32    pub fn empty_args() -> Self {
33        Self { args: vec![] }
34    }
35
36    pub fn new_args(expr: Expr) -> Self {
37        Self {
38            args: vec![Box::new(expr)],
39        }
40    }
41
42    pub fn append_args(mut self: FunctionArgs, expr: Expr) -> Self {
43        self.args.push(Box::new(expr));
44        self
45    }
46
47    pub fn is_empty(&self) -> bool {
48        self.args.is_empty()
49    }
50
51    pub fn len(&self) -> usize {
52        self.args.len()
53    }
54
55    pub fn first(&self) -> Option<Box<Expr>> {
56        self.args.first().cloned()
57    }
58
59    pub fn last(&self) -> Option<Box<Expr>> {
60        self.args.last().cloned()
61    }
62}
63
64impl fmt::Display for FunctionArgs {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        write!(f, "{}", join_vector(&self.args, ", ", false))
67    }
68}
69
70impl Prettier for FunctionArgs {
71    fn pretty(&self, level: usize, max: usize) -> String {
72        let mut v = vec![];
73        for ex in &self.args {
74            v.push(ex.pretty(level, max));
75        }
76        v.join(",\n")
77    }
78}
79
80/// Functions is a list of all functions supported by PromQL, including their types.
81#[derive(Debug, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "ser", derive(serde::Serialize))]
83#[cfg_attr(feature = "ser", serde(rename_all = "camelCase"))]
84pub struct Function {
85    pub name: &'static str,
86    pub arg_types: Vec<ValueType>,
87    /// Variadic cardinality follows Prometheus semantics:
88    /// 0 = exact args, >0 = bounded optional args, <0 = unbounded args.
89    pub variadic: i32,
90    pub return_type: ValueType,
91    pub experimental: bool,
92}
93
94impl Function {
95    pub fn new(
96        name: &'static str,
97        arg_types: Vec<ValueType>,
98        variadic: i32,
99        return_type: ValueType,
100        experimental: bool,
101    ) -> Self {
102        Self {
103            name,
104            arg_types,
105            variadic,
106            return_type,
107            experimental,
108        }
109    }
110}
111
112macro_rules! map {
113    // if variadic args, then the last is the variadic one
114    ($(($name:literal, $arg:expr, $ret:expr)),*) => (
115        {
116            let mut m: HashMap<&'static str, Function> = HashMap::new();
117            $(
118                let variadic = FUNCTION_VARIADIC_CARDINALITY
119                    .get($name)
120                    .copied()
121                    .unwrap_or_default();
122                let experimental = EXPERIMENTAL_FUNCTIONS.contains($name);
123                let func = Function::new($name, $arg, variadic, $ret, experimental);
124                m.insert($name, func);
125            )*
126            m
127        }
128    );
129}
130
131lazy_static! {
132    // Variadic cardinality follows Prometheus semantics:
133    // 0 = exact args, >0 = bounded optional args, <0 = unbounded args.
134    // Only non-zero entries are listed here; missing entries default to 0.
135    static ref FUNCTION_VARIADIC_CARDINALITY: HashMap<&'static str, i32> = HashMap::from([
136        ("days_in_month", 1),
137        ("day_of_year", 1),
138        ("day_of_month", 1),
139        ("day_of_week", 1),
140        ("year", 1),
141        ("month", 1),
142        ("hour", 1),
143        ("minute", 1),
144        ("label_join", -1),
145        ("sort_by_label", -1),
146        ("sort_by_label_desc", -1),
147        ("round", 1),
148    ]);
149    // Functions currently supported by this parser that are marked experimental in Prometheus.
150    // Keep this set in sync when adding new functions to FUNCTIONS.
151    static ref EXPERIMENTAL_FUNCTIONS: HashSet<&'static str> = HashSet::from([
152        "double_exponential_smoothing",
153        "sort_by_label",
154        "sort_by_label_desc",
155    ]);
156    static ref FUNCTIONS: HashMap<&'static str, Function> = map!(
157        ("abs", vec![ValueType::Vector], ValueType::Vector),
158        ("absent", vec![ValueType::Vector], ValueType::Vector),
159        (
160            "absent_over_time",
161            vec![ValueType::Matrix],
162            ValueType::Vector
163        ),
164        ("acos", vec![ValueType::Vector], ValueType::Vector),
165        ("acosh", vec![ValueType::Vector], ValueType::Vector),
166        ("asin", vec![ValueType::Vector], ValueType::Vector),
167        ("asinh", vec![ValueType::Vector], ValueType::Vector),
168        ("atan", vec![ValueType::Vector], ValueType::Vector),
169        ("atanh", vec![ValueType::Vector], ValueType::Vector),
170        ("avg_over_time", vec![ValueType::Matrix], ValueType::Vector),
171        ("ceil", vec![ValueType::Vector], ValueType::Vector),
172        ("changes", vec![ValueType::Matrix], ValueType::Vector),
173        (
174            "clamp",
175            vec![ValueType::Vector, ValueType::Scalar, ValueType::Scalar],
176            ValueType::Vector
177        ),
178        (
179            "clamp_max",
180            vec![ValueType::Vector, ValueType::Scalar],
181            ValueType::Vector
182        ),
183        (
184            "clamp_min",
185            vec![ValueType::Vector, ValueType::Scalar],
186            ValueType::Vector
187        ),
188        ("cos", vec![ValueType::Vector], ValueType::Vector),
189        ("cosh", vec![ValueType::Vector], ValueType::Vector),
190        (
191            "count_over_time",
192            vec![ValueType::Matrix],
193            ValueType::Vector
194        ),
195        ("days_in_month", vec![ValueType::Vector], ValueType::Vector),
196        ("day_of_month", vec![ValueType::Vector], ValueType::Vector),
197        ("day_of_week", vec![ValueType::Vector], ValueType::Vector),
198        ("day_of_year", vec![ValueType::Vector], ValueType::Vector),
199        ("deg", vec![ValueType::Vector], ValueType::Vector),
200        ("delta", vec![ValueType::Matrix], ValueType::Vector),
201        ("deriv", vec![ValueType::Matrix], ValueType::Vector),
202        ("exp", vec![ValueType::Vector], ValueType::Vector),
203        ("floor", vec![ValueType::Vector], ValueType::Vector),
204        (
205            "histogram_count",
206            vec![ValueType::Vector],
207            ValueType::Vector
208        ),
209        ("histogram_sum", vec![ValueType::Vector], ValueType::Vector),
210        ("histogram_avg", vec![ValueType::Vector], ValueType::Vector),
211        (
212            "histogram_fraction",
213            vec![ValueType::Scalar, ValueType::Scalar, ValueType::Vector],
214            ValueType::Vector
215        ),
216        (
217            "histogram_quantile",
218            vec![ValueType::Scalar, ValueType::Vector],
219            ValueType::Vector
220        ),
221        ("histogram_stddev", vec![ValueType::Vector], ValueType::Vector),
222        ("histogram_stdvar", vec![ValueType::Vector], ValueType::Vector),
223        (
224            "double_exponential_smoothing",
225            vec![ValueType::Matrix, ValueType::Scalar, ValueType::Scalar],
226            ValueType::Vector
227        ),
228        // Kept for backward compatibility; Prometheus 3.x renamed this function.
229        (
230            "holt_winters",
231            vec![ValueType::Matrix, ValueType::Scalar, ValueType::Scalar],
232            ValueType::Vector
233        ),
234        ("hour", vec![ValueType::Vector], ValueType::Vector),
235        ("idelta", vec![ValueType::Matrix], ValueType::Vector),
236        ("increase", vec![ValueType::Matrix], ValueType::Vector),
237        ("irate", vec![ValueType::Matrix], ValueType::Vector),
238        (
239            "label_replace",
240            vec![
241                ValueType::Vector,
242                ValueType::String,
243                ValueType::String,
244                ValueType::String,
245                ValueType::String,
246            ],
247            ValueType::Vector
248        ),
249        (
250            "label_join",
251            vec![
252                ValueType::Vector,
253                ValueType::String,
254                ValueType::String,
255                ValueType::String,
256            ],
257            ValueType::Vector
258        ),
259        ("last_over_time", vec![ValueType::Matrix], ValueType::Vector),
260        ("ln", vec![ValueType::Vector], ValueType::Vector),
261        ("log10", vec![ValueType::Vector], ValueType::Vector),
262        ("log2", vec![ValueType::Vector], ValueType::Vector),
263        ("max_over_time", vec![ValueType::Matrix], ValueType::Vector),
264        ("min_over_time", vec![ValueType::Matrix], ValueType::Vector),
265        ("minute", vec![ValueType::Vector], ValueType::Vector),
266        ("month", vec![ValueType::Vector], ValueType::Vector),
267        ("pi", vec![], ValueType::Scalar),
268        (
269            "predict_linear",
270            vec![ValueType::Matrix, ValueType::Scalar],
271            ValueType::Vector
272        ),
273        (
274            "present_over_time",
275            vec![ValueType::Matrix],
276            ValueType::Vector
277        ),
278        (
279            "quantile_over_time",
280            vec![ValueType::Scalar, ValueType::Matrix],
281            ValueType::Vector
282        ),
283        ("rad", vec![ValueType::Vector], ValueType::Vector),
284        ("rate", vec![ValueType::Matrix], ValueType::Vector),
285        ("resets", vec![ValueType::Matrix], ValueType::Vector),
286        (
287            "round",
288            vec![ValueType::Vector, ValueType::Scalar],
289            ValueType::Vector
290        ),
291        ("scalar", vec![ValueType::Vector], ValueType::Scalar),
292        ("sgn", vec![ValueType::Vector], ValueType::Vector),
293        ("sin", vec![ValueType::Vector], ValueType::Vector),
294        ("sinh", vec![ValueType::Vector], ValueType::Vector),
295        ("sort", vec![ValueType::Vector], ValueType::Vector),
296        ("sort_desc", vec![ValueType::Vector], ValueType::Vector),
297        (
298            "sort_by_label",
299            vec![ValueType::Vector, ValueType::String, ValueType::String],
300            ValueType::Vector
301        ),
302        (
303            "sort_by_label_desc",
304            vec![ValueType::Vector, ValueType::String, ValueType::String],
305            ValueType::Vector
306        ),
307        ("sqrt", vec![ValueType::Vector], ValueType::Vector),
308        (
309            "stddev_over_time",
310            vec![ValueType::Matrix],
311            ValueType::Vector
312        ),
313        (
314            "stdvar_over_time",
315            vec![ValueType::Matrix],
316            ValueType::Vector
317        ),
318        ("sum_over_time", vec![ValueType::Matrix], ValueType::Vector),
319        ("tan", vec![ValueType::Vector], ValueType::Vector),
320        ("tanh", vec![ValueType::Vector], ValueType::Vector),
321        ("time", vec![], ValueType::Scalar),
322        ("timestamp", vec![ValueType::Vector], ValueType::Vector),
323        ("vector", vec![ValueType::Scalar], ValueType::Vector),
324        ("year", vec![ValueType::Vector], ValueType::Vector)
325    );
326}
327
328/// get_function returns a predefined Function object for the given name.
329pub(crate) fn get_function(name: &str) -> Option<Function> {
330    FUNCTIONS.get(name).cloned()
331}
332
333#[cfg(test)]
334mod tests {
335    use super::*;
336    use crate::parser::*;
337
338    #[test]
339    fn test_function_equality() {
340        let func = "month";
341        assert!(get_function(func).is_some());
342        assert_eq!(get_function(func), get_function(func));
343    }
344
345    #[test]
346    fn test_function_args_equality() {
347        assert_eq!(FunctionArgs::empty_args(), FunctionArgs::empty_args());
348
349        let arg1 = Expr::NumberLiteral(NumberLiteral::new(1.0));
350        let arg2 = Expr::StringLiteral(StringLiteral {
351            val: "prometheus".into(),
352        });
353        let args1 = FunctionArgs::new_args(arg1).append_args(arg2);
354
355        let arg1 = Expr::NumberLiteral(NumberLiteral::new(0.5 + 0.5));
356        let arg2 = Expr::StringLiteral(StringLiteral {
357            val: String::from("prometheus"),
358        });
359        let args2 = FunctionArgs::new_args(arg1).append_args(arg2);
360
361        assert_eq!(args1, args2);
362    }
363
364    #[test]
365    fn test_args_display() {
366        let cases = vec![
367            (
368                FunctionArgs::new_args(Expr::from(VectorSelector::from("up"))),
369                "up",
370            ),
371            (
372                FunctionArgs::empty_args()
373                    .append_args(Expr::from("src1"))
374                    .append_args(Expr::from("src2"))
375                    .append_args(Expr::from("src3")),
376                r#""src1", "src2", "src3""#,
377            ),
378        ];
379
380        for (args, expect) in cases {
381            assert_eq!(expect, args.to_string())
382        }
383    }
384
385    #[test]
386    fn test_function_metadata() {
387        let round = get_function("round").unwrap();
388        assert_eq!(round.variadic, 1);
389        assert!(!round.experimental);
390
391        let label_join = get_function("label_join").unwrap();
392        assert_eq!(label_join.variadic, -1);
393        assert!(!label_join.experimental);
394
395        let sort_by_label = get_function("sort_by_label").unwrap();
396        assert_eq!(sort_by_label.variadic, -1);
397        assert!(sort_by_label.experimental);
398
399        let rate = get_function("rate").unwrap();
400        assert_eq!(rate.variadic, 0);
401        assert!(!rate.experimental);
402    }
403}