Thanks to visit codestin.com
Credit goes to docs.rs

dataflow_rs/
lib.rs

1/*!
2# Dataflow-rs
3
4A lightweight, rule-driven workflow engine for building powerful data processing pipelines and nanoservices in Rust.
5
6## Overview
7
8Dataflow-rs provides a flexible and extensible framework for processing data through a series of tasks organized in workflows.
9The engine automatically routes messages through appropriate workflows based on configurable rules, and each workflow can
10contain multiple tasks that transform, validate, or enrich the data.
11
12## Key Components
13
14* **Engine**: The central component that processes messages through workflows
15* **Workflow**: A collection of tasks with conditions that determine when they should be applied
16* **Task**: An individual processing unit that performs a specific function on a message
17* **AsyncFunctionHandler**: A trait implemented by task handlers to define custom async processing logic
18* **Message**: The data structure that flows through the engine, containing payload, metadata, and processing results
19
20## Built-in Functions
21
22The engine comes with several pre-registered functions:
23
24* **map**: Maps and transforms data between different parts of a message
25* **validate**: Validates message data against rules using JSONLogic expressions
26
27## Usage Example
28
29```rust,no_run
30use dataflow_rs::{Engine, Workflow};
31use dataflow_rs::engine::message::Message;
32use serde_json::json;
33
34#[tokio::main]
35async fn main() -> Result<(), Box<dyn std::error::Error>> {
36    // Define a workflow in JSON
37    let workflow_json = r#"
38    {
39        "id": "data_processor",
40        "name": "Data Processor",
41        "priority": 0,
42        "tasks": [
43            {
44                "id": "transform_data",
45                "name": "Transform Data",
46                "function": {
47                    "name": "map",
48                    "input": {
49                        "mappings": [
50                            {
51                                "path": "data.result",
52                                "logic": { "var": "temp_data.value" }
53                            }
54                        ]
55                    }
56                }
57            }
58        ]
59    }
60    "#;
61
62    // Parse the workflow
63    let workflow = Workflow::from_json(workflow_json)?;
64
65    // Create the workflow engine with the workflow (built-in functions are auto-registered by default)
66    let engine = Engine::new(vec![workflow], None);
67
68    // Create a message to process
69    let mut message = Message::from_value(&json!({}));
70
71    // Process the message through the workflow
72    match engine.process_message(&mut message).await {
73        Ok(_) => {
74            println!("Processed result: {}", message.context["data"]["result"]);
75        }
76        Err(e) => {
77            println!("Error in workflow: {:?}", e);
78        }
79    }
80
81    Ok(())
82}
83```
84
85## Error Handling
86
87The library provides a comprehensive error handling system:
88
89```rust,no_run
90use dataflow_rs::{Engine, Result, DataflowError};
91use dataflow_rs::engine::message::Message;
92use serde_json::json;
93
94#[tokio::main]
95async fn main() -> Result<()> {
96    // ... setup workflows ...
97    let engine = Engine::new(vec![/* workflows */], None);
98
99    let mut message = Message::from_value(&json!({}));
100
101    // Process the message, errors will be collected but not halt execution
102    engine.process_message(&mut message).await?;
103
104    // Check if there were any errors during processing
105    if message.has_errors() {
106        for error in &message.errors {
107            println!("Error in workflow: {:?}, task: {:?}: {:?}",
108                     error.workflow_id, error.task_id, error.message);
109        }
110    }
111
112    Ok(())
113}
114```
115
116## Extending with Custom Functions
117
118You can extend the engine with your own custom function handlers:
119
120```rust,no_run
121use dataflow_rs::{Engine, AsyncFunctionHandler, Result, Workflow};
122use dataflow_rs::engine::{FunctionConfig, message::{Change, Message}, error::DataflowError};
123use datalogic_rs::DataLogic;
124use serde_json::{json, Value};
125use std::collections::HashMap;
126use std::sync::Arc;
127use async_trait::async_trait;
128
129struct CustomFunction;
130
131#[async_trait]
132impl AsyncFunctionHandler for CustomFunction {
133    async fn execute(
134        &self,
135        message: &mut Message,
136        config: &FunctionConfig,
137        datalogic: Arc<DataLogic>,
138    ) -> Result<(usize, Vec<Change>)> {
139        // Implement your custom logic here
140
141        // Extract the custom configuration from config
142        let input = match config {
143            FunctionConfig::Custom { input, .. } => input,
144            _ => return Err(DataflowError::Validation("Invalid configuration type".to_string())),
145        };
146
147        // Validate input
148        let required_field = input.get("field")
149            .ok_or_else(|| DataflowError::Validation("Missing required field".to_string()))?
150            .as_str()
151            .ok_or_else(|| DataflowError::Validation("Field must be a string".to_string()))?;
152
153        // Record changes for audit trail
154        let changes = vec![
155            Change {
156                path: Arc::from("data.custom_field"),
157                old_value: Arc::new(Value::Null),
158                new_value: Arc::new(json!("custom value")),
159            }
160        ];
161
162        // Return success code (200) and changes
163        Ok((200, changes))
164    }
165}
166
167#[tokio::main]
168async fn main() -> Result<()> {
169    // Create custom functions
170    let mut custom_functions = HashMap::new();
171    custom_functions.insert(
172        "custom".to_string(),
173        Box::new(CustomFunction) as Box<dyn AsyncFunctionHandler + Send + Sync>
174    );
175
176    // Create engine with workflows and custom functions
177    let engine = Engine::new(vec![/* workflows */], Some(custom_functions));
178
179    // Now it can be used in workflows...
180    Ok(())
181}
182```
183*/
184
185pub mod engine;
186
187// Re-export all public APIs for easier access
188pub use engine::error::{DataflowError, ErrorInfo, Result};
189pub use engine::functions::{
190    AsyncFunctionHandler, FunctionConfig, MapConfig, MapMapping, ValidationConfig, ValidationRule,
191};
192pub use engine::message::{AuditTrail, Change, Message};
193pub use engine::{Engine, Task, Workflow};