1use std::collections::BTreeMap;
18
19use promql_parser::label::{METRIC_NAME, MatchOp, Matcher};
20use promql_parser::parser::{Expr, VectorSelector};
21use promql_parser::util::{ExprVisitor, walk_expr};
22use query::parser::QueryLanguageParser;
23use query::promql::label_values::signed_millis_since_epoch;
24use serde::{Deserialize, Serialize};
25use snafu::OptionExt;
26
27use crate::error::{InvalidQuerySnafu, Result};
28use crate::prom_store::{FIELD_NAME_LABEL, is_database_selection_label};
29use crate::prometheus_handler::resolve_schema_from_matchers;
30
31#[derive(Debug, Clone)]
32pub struct Selector {
33 pub schema: String,
34 pub matchers: Vec<Matcher>,
35}
36
37#[derive(Debug)]
38pub struct Query {
39 pub expression: String,
40 pub selectors: Vec<Selector>,
41 pub bounds: (i64, i64),
43}
44
45impl Query {
46 pub fn parse(expression: String, start: &str, end: &str, schema: &str) -> Result<Self> {
47 let parse = |input| {
48 let time = QueryLanguageParser::parse_promql_timestamp(input).map_err(|error| {
49 InvalidQuerySnafu {
50 reason: error.to_string(),
51 }
52 .build()
53 })?;
54 let millis = signed_millis_since_epoch(time).map_err(|error| {
55 InvalidQuerySnafu {
56 reason: error.to_string(),
57 }
58 .build()
59 })?;
60 millis.checked_mul(1_000_000).context(InvalidQuerySnafu {
61 reason: "timestamp exceeds signed nanosecond range",
62 })
63 };
64 let start = parse(start)?;
65 let end = parse(end)?;
66 if start > end {
67 return invalid("start must not exceed end");
68 }
69 let expr = promql_parser::parser::parse(&expression)
70 .map_err(|reason| InvalidQuerySnafu { reason }.build())?;
71 struct Collector<'a> {
72 schema: &'a str,
73 selectors: Vec<Selector>,
74 }
75 impl ExprVisitor for Collector<'_> {
76 type Error = crate::error::Error;
77 fn pre_visit(&mut self, expr: &Expr) -> Result<bool> {
78 let selector = match expr {
79 Expr::VectorSelector(vs) => vs,
80 Expr::MatrixSelector(ms) => &ms.vs,
81 Expr::Aggregate(aggregate) => {
82 if let Some(param) = &aggregate.param {
84 walk_expr(self, param)?;
85 }
86 return Ok(true);
87 }
88 _ => return Ok(true),
89 };
90 self.selectors.extend(resolve(selector, self.schema)?);
91 Ok(true)
92 }
93 }
94 let mut collector = Collector {
95 schema,
96 selectors: Vec::new(),
97 };
98 walk_expr(&mut collector, &expr)?;
99 Ok(Self {
100 expression,
101 selectors: collector.selectors,
102 bounds: (start, end.saturating_add(999_999)),
104 })
105 }
106}
107
108fn resolve(selector: &VectorSelector, default_schema: &str) -> Result<Vec<Selector>> {
109 let branches = if selector.matchers.or_matchers.is_empty() {
110 vec![&selector.matchers.matchers]
111 } else {
112 selector.matchers.or_matchers.iter().collect()
113 };
114 branches
115 .into_iter()
116 .map(|branch| {
117 if branch
118 .iter()
119 .any(|matcher| matcher.name == FIELD_NAME_LABEL)
120 {
121 return invalid("__field__ is not supported in exemplar queries");
122 }
123 let schema =
124 resolve_schema_from_matchers(branch)?.unwrap_or_else(|| default_schema.to_string());
125 let mut matchers = branch
126 .iter()
127 .filter(|matcher| !is_database_selection_label(&matcher.name))
128 .cloned()
129 .collect::<Vec<_>>();
130 if let Some(name) = &selector.name {
131 matchers.push(Matcher::new(MatchOp::Equal, METRIC_NAME, name));
132 }
133 Ok(Selector { schema, matchers })
134 })
135 .collect()
136}
137
138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
139pub struct Series {
140 #[serde(rename = "seriesLabels")]
141 pub series_labels: BTreeMap<String, String>,
142 pub exemplars: Vec<Observation>,
143}
144
145#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
146pub struct Observation {
147 pub labels: BTreeMap<String, String>,
148 pub value: String,
149 pub timestamp: f64,
151}
152
153fn invalid<T>(reason: &str) -> Result<T> {
154 InvalidQuerySnafu { reason }.fail()
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn query_bounds_use_prometheus_milliseconds() {
163 for (input, millis) in [
164 ("1.234567891", 1235),
165 ("1.234e0", 1234),
166 ("1720000000.123456789", 1720000000123),
167 ("-0.0006", -1),
168 ("-0.0004", 0),
169 ("-1.0005", -1000),
170 ("1970-01-01T00:00:00.0019Z", 1),
171 ("1969-12-31T23:59:59.999999999Z", -1),
172 ("1970-01-01T01:00:00.0019+01:00", 1),
173 ] {
174 assert_eq!(
175 Query::parse("up".into(), input, input, "public")
176 .unwrap()
177 .bounds,
178 (millis * 1_000_000, millis * 1_000_000 + 999_999),
179 "{input}",
180 );
181 }
182 assert_eq!(
183 Query::parse("up".into(), "0.0012", "0.0011", "public")
184 .unwrap()
185 .bounds,
186 (1_000_000, 1_999_999),
187 );
188 assert_eq!(
189 Query::parse(
190 "up".into(),
191 "2262-04-11T23:47:16.854Z",
192 "2262-04-11T23:47:16.854Z",
193 "public"
194 )
195 .unwrap()
196 .bounds,
197 (9_223_372_036_854_000_000, i64::MAX),
198 );
199 assert!(Query::parse("up".into(), "0.002", "0.001", "public").is_err());
200 for input in [
201 "NaN",
202 "inf",
203 "",
204 "1e100",
205 "9223372036.855",
206 "-9223372036.855",
207 ] {
208 assert!(
209 Query::parse("up".into(), input, input, "public").is_err(),
210 "{input}"
211 );
212 }
213 assert!(
214 Query::parse("1".into(), "0", "1", "public")
215 .unwrap()
216 .selectors
217 .is_empty()
218 );
219 }
220
221 #[test]
222 fn aggregation_parameter_selectors() {
223 for (expression, expected) in [
224 (
225 "topk(scalar(limit_metric), requests)",
226 vec!["limit_metric", "requests"],
227 ),
228 (
229 "bottomk(scalar(limit_metric), requests)",
230 vec!["limit_metric", "requests"],
231 ),
232 (
233 "quantile(scalar(limit_metric), requests)",
234 vec!["limit_metric", "requests"],
235 ),
236 (
237 "topk(scalar(topk(scalar(inner_limit), limit_metric)), requests)",
238 vec!["inner_limit", "limit_metric", "requests"],
239 ),
240 ("topk(2, requests)", vec!["requests"]),
241 ("count_values(\"kind\", requests)", vec!["requests"]),
242 (
243 "topk(scalar(requests), requests)",
244 vec!["requests", "requests"],
245 ),
246 ] {
247 let query = Query::parse(expression.into(), "0", "1", "public").unwrap();
248 let mut names = query
249 .selectors
250 .iter()
251 .flat_map(|selector| &selector.matchers)
252 .filter(|matcher| matcher.name == METRIC_NAME)
253 .map(|matcher| matcher.value.as_str())
254 .collect::<Vec<_>>();
255 names.sort_unstable();
256 assert_eq!(names, expected, "{expression}");
257 }
258 }
259
260 #[test]
261 fn range_vectors_and_routing_controls() {
262 let query = Query::parse(
263 "topk(scalar(sum(rate(requests{__schema__=\"a\"}[5m]))), errors{__database__=\"b\"})"
264 .into(),
265 "0",
266 "1",
267 "public",
268 )
269 .unwrap();
270 assert_eq!(
271 query
272 .selectors
273 .iter()
274 .map(|s| s.schema.as_str())
275 .collect::<Vec<_>>(),
276 ["a", "b"]
277 );
278 for query in [
279 "up{__schema__=\"\"}",
280 "up{__schema__!=\"a\"}",
281 "up{__field__=\"x\"}",
282 "topk(scalar(up{__schema__=\"\"}), requests)",
283 "topk(scalar(up{__schema__!=\"a\"}), requests)",
284 "topk(scalar(up{__field__=\"x\"}), requests)",
285 ] {
286 assert!(Query::parse(query.into(), "0", "1", "public").is_err());
287 }
288 }
289}