///|
pub fn evaluate(
expression : @ast.Expr,
context : EvalContext,
) -> @model.Value raise @model.PromqlError {
match expression {
@ast.Number(value) => @model.Scalar(value)
@ast.StringLiteral(value) => @model.StringValue(value)
@ast.Selector(selector) =>
match selector.range_ms {
Some(range_ms) => select_range(selector, range_ms, context)
None => select_instant(selector, context)
}
@ast.Unary(operator, value) => {
let evaluated = evaluate(value, context)
match operator {
@ast.UnaryOp::Pos => evaluated
@ast.UnaryOp::Neg =>
match evaluated {
@model.Scalar(value) => @model.Scalar(-value)
@model.Instant(points) => {
let output : Array[@model.Point] = []
for point in points {
output.push({ labels: point.labels, value: -point.value, })
}
@model.Instant(output)
}
_ => raise @model.EvalError("unary minus expects scalar or vector")
}
}
}
@ast.Call(name, args) => {
let values : Array[@model.Value] = []
for arg in args {
values.push(evaluate(arg, context))
}
@functions.call(name, values, context.eval_time_ms)
}
@ast.Aggregate(operator, args, without, names) =>
evaluate_aggregate(operator, args, without, names, context)
@ast.Binary(operator, left, right, bool_modifier, vector_match) => {
let left_value = evaluate(left, context)
let right_value = evaluate(right, context)
match (left_value, right_value) {
(@model.Scalar(a), @model.Scalar(b)) =>
if is_comparison(operator) {
let matched = comparison_operator(operator, a, b)
@model.Scalar(
if bool_modifier {
if matched {
1.0
} else {
0.0
}
} else if matched {
a
} else {
0.0 / 0.0
},
)
} else {
@model.Scalar(numeric_operator(operator, a, b))
}
(@model.Instant(points), @model.Scalar(scalar)) =>
@model.Instant(
map_instant_scalar(points, scalar, false, operator, bool_modifier),
)
(@model.Scalar(scalar), @model.Instant(points)) =>
@model.Instant(
map_instant_scalar(points, scalar, true, operator, bool_modifier),
)
(@model.Instant(left_points), @model.Instant(right_points)) =>
@model.Instant(
apply_vector_vector(
operator, left_points, right_points, bool_modifier, vector_match,
),
)
_ =>
raise @model.EvalError(
"binary operator requires compatible scalar or instant vector values",
)
}
}
}
}
///|
/// Parse and evaluate one PromQL query.
pub fn query(
input : StringView,
context : EvalContext,
) -> @model.Value raise @model.PromqlError {
evaluate(@parser.parse(input), context)
}