Skip to main content

a3s_flow/nodes/
noop.rs

1//! Built-in `"noop"` node — passes all upstream inputs through unchanged.
2//!
3//! Useful as a placeholder node, a fan-in join point, or for testing.
4
5use async_trait::async_trait;
6use serde_json::{json, Value};
7
8use crate::error::Result;
9use crate::node::{ExecContext, Node};
10
11/// A no-operation node that merges all upstream inputs into a single object
12/// and returns it as output.
13///
14/// If there are no inputs the output is an empty JSON object `{}`.
15pub struct NoopNode;
16
17#[async_trait]
18impl Node for NoopNode {
19    fn node_type(&self) -> &str {
20        "noop"
21    }
22
23    async fn execute(&self, ctx: ExecContext) -> Result<Value> {
24        // Merge all upstream inputs into one flat object.
25        let mut merged = json!({});
26        for (key, value) in &ctx.inputs {
27            merged[key] = value.clone();
28        }
29        Ok(merged)
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use std::collections::HashMap;
37
38    #[tokio::test]
39    async fn merges_inputs() {
40        let node = NoopNode;
41        let ctx = ExecContext {
42            data: Value::Null,
43            inputs: HashMap::from([("a".into(), json!({"x": 1})), ("b".into(), json!({"y": 2}))]),
44            variables: HashMap::new(),
45            ..Default::default()
46        };
47        let out = node.execute(ctx).await.unwrap();
48        assert_eq!(out["a"]["x"], 1);
49        assert_eq!(out["b"]["y"], 2);
50    }
51
52    #[tokio::test]
53    async fn empty_inputs_returns_empty_object() {
54        let node = NoopNode;
55        let ctx = ExecContext {
56            data: Value::Null,
57            inputs: HashMap::new(),
58            variables: HashMap::new(),
59            ..Default::default()
60        };
61        let out = node.execute(ctx).await.unwrap();
62        assert!(out.is_object());
63        assert!(out.as_object().unwrap().is_empty());
64    }
65}