Skip to content

Commit cb9db55

Browse files
committed
Fix
1 parent bbba9d6 commit cb9db55

File tree

9 files changed

+85
-61
lines changed

9 files changed

+85
-61
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/router/src/pipeline/progressive_override.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
use std::collections::{BTreeMap, HashMap, HashSet};
22

3-
use hive_router_config::override_labels::{LabelOverrideValue, OverrideLabelsConfig};
3+
use hive_router_config::{
4+
override_labels::{LabelOverrideValue, OverrideLabelsConfig},
5+
primitives::expression::Expression,
6+
};
47
use hive_router_plan_executor::execution::client_request_details::ClientRequestDetails;
58
use hive_router_query_planner::{
69
graph::{PlannerOverrideContext, PERCENTAGE_SCALE_FACTOR},
710
state::supergraph_state::SupergraphState,
811
};
912
use rand::Rng;
1013
use vrl::{
11-
compiler::{compile as vrl_compile, Program as VrlProgram, TargetValue as VrlTargetValue},
14+
compiler::TargetValue as VrlTargetValue,
1215
core::Value as VrlValue,
1316
prelude::{
1417
state::RuntimeState as VrlState, Context as VrlContext, ExpressionError,
1518
TimeZone as VrlTimeZone,
1619
},
17-
stdlib::all as vrl_build_functions,
1820
value::Secrets as VrlSecrets,
1921
};
2022

@@ -117,7 +119,7 @@ impl StableOverrideContext {
117119
/// It's intended to be used as a shared state in the router.
118120
pub struct OverrideLabelsEvaluator {
119121
static_enabled_labels: HashSet<String>,
120-
expressions: HashMap<String, VrlProgram>,
122+
expressions: HashMap<String, Expression>,
121123
}
122124

123125
impl OverrideLabelsEvaluator {
@@ -126,27 +128,14 @@ impl OverrideLabelsEvaluator {
126128
) -> Result<Self, OverrideLabelsCompileError> {
127129
let mut static_enabled_labels = HashSet::new();
128130
let mut expressions = HashMap::new();
129-
let vrl_functions = vrl_build_functions();
130131

131132
for (label, value) in override_labels_config.iter() {
132133
match value {
133134
LabelOverrideValue::Boolean(true) => {
134135
static_enabled_labels.insert(label.clone());
135136
}
136-
LabelOverrideValue::Expression { expression } => {
137-
let compilation_result =
138-
vrl_compile(expression, &vrl_functions).map_err(|diagnostics| {
139-
OverrideLabelsCompileError {
140-
label: label.clone(),
141-
error: diagnostics
142-
.errors()
143-
.into_iter()
144-
.map(|d| d.code.to_string() + ": " + &d.message)
145-
.collect::<Vec<_>>()
146-
.join(", "),
147-
}
148-
})?;
149-
expressions.insert(label.clone(), compilation_result.program);
137+
LabelOverrideValue::Expression(expression) => {
138+
expressions.insert(label.clone(), expression.clone());
150139
}
151140
_ => {} // Skip false booleans
152141
}
@@ -179,7 +168,7 @@ impl OverrideLabelsEvaluator {
179168
let mut ctx = VrlContext::new(&mut target, &mut state, &timezone);
180169

181170
for (label, expression) in &self.expressions {
182-
match expression.resolve(&mut ctx) {
171+
match expression.execute_with_context(&mut ctx) {
183172
Ok(evaluated_value) => match evaluated_value {
184173
VrlValue::Boolean(true) => {
185174
active_flags.insert(label.clone());

lib/executor/src/executors/error.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use vrl::{diagnostic::DiagnosticList, prelude::ExpressionError};
1+
use vrl::prelude::ExpressionError;
22

33
use crate::response::graphql_error::{GraphQLError, GraphQLErrorExtensions};
44

@@ -34,21 +34,6 @@ impl From<SubgraphExecutorError> for GraphQLError {
3434
}
3535

3636
impl SubgraphExecutorError {
37-
pub fn new_endpoint_expression_build(
38-
subgraph_name: String,
39-
diagnostics: DiagnosticList,
40-
) -> Self {
41-
SubgraphExecutorError::EndpointExpressionBuild(
42-
subgraph_name,
43-
diagnostics
44-
.errors()
45-
.into_iter()
46-
.map(|d| d.code.to_string() + ": " + &d.message)
47-
.collect::<Vec<_>>()
48-
.join(", "),
49-
)
50-
}
51-
5237
pub fn new_endpoint_expression_resolution_failure(
5338
subgraph_name: String,
5439
error: ExpressionError,

lib/executor/src/executors/map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl SubgraphExecutorMap {
190190
]));
191191

192192
// Resolve the expression to get an endpoint URL.
193-
let endpoint_result = expression.execute(value).map_err(|err| {
193+
let endpoint_result = expression.execute_with_value(value).map_err(|err| {
194194
SubgraphExecutorError::new_endpoint_expression_resolution_failure(
195195
subgraph_name.to_string(),
196196
err,

lib/executor/src/headers/request.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,15 @@ impl ApplyRequestHeader for RequestInsertExpression {
166166
if is_denied_header(&self.name) {
167167
return Ok(());
168168
}
169-
let value = self.expression.execute(ctx.into()).map_err(|err| {
170-
HeaderRuleRuntimeError::new_expression_evaluation(self.name.to_string(), Box::new(err))
171-
})?;
169+
let value = self
170+
.expression
171+
.execute_with_value(ctx.into())
172+
.map_err(|err| {
173+
HeaderRuleRuntimeError::new_expression_evaluation(
174+
self.name.to_string(),
175+
Box::new(err),
176+
)
177+
})?;
172178

173179
if let Some(header_value) = vrl_value_to_header_value(value) {
174180
if is_never_join_header(&self.name) {

lib/executor/src/headers/response.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,12 @@ impl ApplyResponseHeader for ResponseInsertExpression {
188188
if is_denied_header(&self.name) {
189189
return Ok(());
190190
}
191-
let value = self.expression.execute(ctx.into()).map_err(|err| {
192-
HeaderRuleRuntimeError::ExpressionEvaluation(self.name.to_string(), Box::new(err))
193-
})?;
191+
let value = self
192+
.expression
193+
.execute_with_value(ctx.into())
194+
.map_err(|err| {
195+
HeaderRuleRuntimeError::ExpressionEvaluation(self.name.to_string(), Box::new(err))
196+
})?;
194197

195198
if let Some(header_value) = vrl_value_to_header_value(value) {
196199
let strategy = if is_never_join_header(&self.name) {

lib/router-config/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ retry-policies = { workspace = true}
2525
tracing = { workspace = true }
2626
vrl = { workspace = true }
2727

28+
once_cell = "1.21.3"
2829
schemars = "1.0.4"
2930
humantime-serde = "1.1.1"
3031
config = { version = "0.15.14", features = ["yaml", "json", "json5"] }

lib/router-config/src/override_labels.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use schemars::JsonSchema;
22
use serde::{Deserialize, Serialize};
33
use std::collections::HashMap;
44

5+
use crate::primitives::expression::Expression;
6+
57
/// A map of label names to their override configuration.
68
pub type OverrideLabelsConfig = HashMap<String, LabelOverrideValue>;
79

@@ -15,10 +17,7 @@ pub enum LabelOverrideValue {
1517
/// A static boolean value to enable or disable the label.
1618
Boolean(bool),
1719
/// A dynamic value computed by an expression.
18-
Expression {
19-
/// An expression that must evaluate to a boolean. If true, the label will be applied.
20-
expression: String,
21-
},
20+
Expression(Expression),
2221
}
2322

2423
impl LabelOverrideValue {

lib/router-config/src/primitives/expression.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use std::{borrow::Cow, collections::BTreeMap};
2-
1+
use once_cell::sync::Lazy;
32
use schemars::{JsonSchema, Schema, SchemaGenerator};
43
use serde::{Deserialize, Serialize};
4+
use std::{borrow::Cow, collections::BTreeMap};
55
use vrl::{
66
compiler::{compile as vrl_compile, Program as VrlProgram, TargetValue as VrlTargetValue},
77
core::Value as VrlValue,
88
prelude::{
9-
state::RuntimeState as VrlState, Context as VrlContext, ExpressionError,
9+
state::RuntimeState as VrlState, Context as VrlContext, ExpressionError, Function,
1010
TimeZone as VrlTimeZone,
1111
},
1212
stdlib::all as vrl_build_functions,
@@ -19,16 +19,17 @@ pub struct Expression {
1919
program: Box<VrlProgram>,
2020
}
2121

22+
static VRL_FUNCTIONS: Lazy<Vec<Box<dyn Function>>> = Lazy::new(vrl_build_functions);
23+
static VRL_TIMEZONE: Lazy<VrlTimeZone> = Lazy::new(VrlTimeZone::default);
24+
2225
impl Expression {
2326
pub fn try_new(expression: String) -> Result<Self, String> {
24-
let vrl_functions = vrl_build_functions();
25-
2627
let compilation_result =
27-
vrl_compile(&expression, &vrl_functions).map_err(|diagnostics| {
28+
vrl_compile(&expression, &VRL_FUNCTIONS).map_err(|diagnostics| {
2829
diagnostics
2930
.errors()
30-
.into_iter()
31-
.map(|d| d.code.to_string() + ": " + &d.message)
31+
.iter()
32+
.map(|d| format!("{}: {}", d.code, d.message))
3233
.collect::<Vec<_>>()
3334
.join(", ")
3435
})?;
@@ -39,18 +40,21 @@ impl Expression {
3940
})
4041
}
4142

42-
pub fn execute(&self, value: VrlValue) -> Result<VrlValue, ExpressionError> {
43+
pub fn execute_with_value(&self, value: VrlValue) -> Result<VrlValue, ExpressionError> {
4344
let mut target = VrlTargetValue {
4445
value,
4546
metadata: VrlValue::Object(BTreeMap::new()),
4647
secrets: VrlSecrets::default(),
4748
};
4849

4950
let mut state = VrlState::default();
50-
let timezone = VrlTimeZone::default();
51-
let mut ctx = VrlContext::new(&mut target, &mut state, &timezone);
51+
let mut ctx = VrlContext::new(&mut target, &mut state, &VRL_TIMEZONE);
52+
53+
self.execute_with_context(&mut ctx)
54+
}
5255

53-
self.program.resolve(&mut ctx)
56+
pub fn execute_with_context(&self, ctx: &mut VrlContext) -> Result<VrlValue, ExpressionError> {
57+
self.program.resolve(ctx)
5458
}
5559
}
5660

@@ -59,8 +63,44 @@ impl<'de> Deserialize<'de> for Expression {
5963
where
6064
D: serde::Deserializer<'de>,
6165
{
62-
let expression = String::deserialize(deserializer)?;
63-
Expression::try_new(expression).map_err(serde::de::Error::custom)
66+
struct ExpressionVisitor;
67+
impl<'de> serde::de::Visitor<'de> for ExpressionVisitor {
68+
type Value = Expression;
69+
70+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
71+
formatter.write_str("a map for Expression")
72+
}
73+
74+
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
75+
where
76+
A: serde::de::MapAccess<'de>,
77+
{
78+
let mut expression_str: Option<String> = None;
79+
80+
while let Some(key) = map.next_key::<String>()? {
81+
match key.as_str() {
82+
"expression" => {
83+
if expression_str.is_some() {
84+
return Err(serde::de::Error::duplicate_field("expression"));
85+
}
86+
expression_str = Some(map.next_value()?);
87+
}
88+
other_key => {
89+
return Err(serde::de::Error::unknown_field(
90+
other_key,
91+
&["expression"],
92+
));
93+
}
94+
}
95+
}
96+
97+
let expression_str =
98+
expression_str.ok_or_else(|| serde::de::Error::missing_field("expression"))?;
99+
100+
Expression::try_new(expression_str).map_err(serde::de::Error::custom)
101+
}
102+
}
103+
deserializer.deserialize_map(ExpressionVisitor)
64104
}
65105
}
66106

0 commit comments

Comments
 (0)