Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 52fbb40

Browse files
committed
feat(engine): dot notation resolution for state paths
1 parent a4efecf commit 52fbb40

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

crates/core/src/engine.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,8 @@ impl Engine {
18171817
.save_task(&current_task)
18181818
.await?;
18191819

1820-
debug!("Command output: {output}");
1820+
info!("Step output:");
1821+
info!("{output}");
18211822

18221823
let outputs = read_to_string(&state_outputs_path).await?;
18231824

crates/models/src/variable.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,44 @@ use std::collections::HashMap;
55
use crate::error::Error;
66
use crate::Result;
77

8+
/// Resolve a dot notation path in a HashMap<String, Value>
9+
/// For example: resolve_state_path(state, "x.y.0.z") gets state["x"]["y"][0]["z"]
10+
pub fn resolve_state_path<'a>(state: &'a HashMap<String, Value>, path: &str) -> Result<&'a Value> {
11+
let parts: Vec<&str> = path.split('.').collect();
12+
13+
if parts.is_empty() {
14+
return Err(Error::VariableResolution("Empty path".to_string()));
15+
}
16+
17+
let root_key = parts[0];
18+
let mut current_value = state
19+
.get(root_key)
20+
.ok_or_else(|| Error::VariableResolution(format!("State key not found: {root_key}")))?;
21+
22+
for part in &parts[1..] {
23+
current_value = match current_value {
24+
Value::Object(obj) => obj.get(*part).ok_or_else(|| {
25+
Error::VariableResolution(format!("Object key not found: {part}"))
26+
})?,
27+
Value::Array(arr) => {
28+
let index: usize = part.parse().map_err(|_| {
29+
Error::VariableResolution(format!("Invalid array index: {part}"))
30+
})?;
31+
arr.get(index).ok_or_else(|| {
32+
Error::VariableResolution(format!("Array index out of bounds: {index}"))
33+
})?
34+
}
35+
_ => {
36+
return Err(Error::VariableResolution(format!(
37+
"Cannot traverse path '{part}' - value is not an object or array"
38+
)));
39+
}
40+
};
41+
}
42+
43+
Ok(current_value)
44+
}
45+
846
/// Resolve variables in a string
947
pub fn resolve_variables(
1048
input: &str,
@@ -28,9 +66,7 @@ pub fn resolve_variables(
2866
Error::VariableResolution(format!("Parameter not found: {name}"))
2967
})?
3068
} else if let Some(name) = inner.strip_prefix("state.") {
31-
let value = state.get(name).ok_or_else(|| {
32-
Error::VariableResolution(format!("State value not found: {name}"))
33-
})?;
69+
let value = resolve_state_path(state, name)?;
3470
serde_json::to_string(value).unwrap()
3571
} else {
3672
return Err(Error::VariableResolution(format!(

crates/scheduler/src/lib.rs

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

3+
use butterflow_models::variable::resolve_state_path;
34
use log::{debug, warn};
45
#[cfg(feature = "wasm")]
56
use serde::Serialize;
@@ -202,7 +203,7 @@ impl Scheduler {
202203
if let Some(Strategy {
203204
r#type: StrategyType::Matrix,
204205
values,
205-
from_state: _, // Corrected variable name
206+
from_state: _,
206207
}) = &node.strategy
207208
{
208209
// Create a master task for the matrix
@@ -276,27 +277,30 @@ impl Scheduler {
276277
}
277278

278279
// Get the current value from the state
279-
let state_value = state.get(state_key);
280+
let state_value = resolve_state_path(state, state_key);
280281

281282
// --- Calculate Values for Current State Items ---
282283
let mut current_item_values = Vec::new();
283284

284285
match state_value {
285-
Some(serde_json::Value::Array(items)) => {
286+
Ok(serde_json::Value::Array(items)) => {
286287
for item in items {
287288
current_item_values.push(item.clone());
288289
}
289290
debug!("Found {} items in state array '{}'", items.len(), state_key);
290291
}
291-
Some(serde_json::Value::Object(_obj)) => {
292+
Ok(serde_json::Value::Object(_obj)) => {
292293
// Object mapping not fully supported yet
293294
warn!("Matrix from_state for object key '{state_key}' is not yet fully supported, skipping.");
294-
continue; // Skip this node
295+
continue;
295296
}
296-
_ => {
297+
Ok(_) => {
297298
// State key not found or not an array/object
298299
debug!("State key '{}' for matrix node '{}' is missing or not an array/object.", state_key, node.id);
299300
}
301+
Err(_) => {
302+
debug!("Could not resolve state path '{state_key}'");
303+
}
300304
}
301305

302306
// --- Compare with Existing Tasks ---

0 commit comments

Comments
 (0)