rust_logic_graph/node/
mod.rs1
2use async_trait::async_trait;
3use serde::{Serialize, Deserialize};
4use serde_json::Value;
5use tracing::{info, debug};
6
7use crate::core::Context;
8use crate::rule::RuleResult;
9
10#[derive(Debug, Serialize, Deserialize, Clone)]
11pub enum NodeType {
12 RuleNode,
13 DBNode,
14 AINode,
15}
16
17#[async_trait]
18pub trait Node: Send + Sync {
19 fn id(&self) -> &str;
20 fn node_type(&self) -> NodeType;
21 async fn run(&self, ctx: &mut Context) -> RuleResult;
22}
23
24#[derive(Debug, Clone)]
29pub struct RuleNode {
30 pub id: String,
31 pub condition: String,
32}
33
34impl RuleNode {
35 pub fn new(id: impl Into<String>, condition: impl Into<String>) -> Self {
36 Self {
37 id: id.into(),
38 condition: condition.into(),
39 }
40 }
41}
42
43#[async_trait]
44impl Node for RuleNode {
45 fn id(&self) -> &str {
46 &self.id
47 }
48
49 fn node_type(&self) -> NodeType {
50 NodeType::RuleNode
51 }
52
53 async fn run(&self, ctx: &mut Context) -> RuleResult {
54 info!("RuleNode[{}]: Evaluating condition '{}'", self.id, self.condition);
55
56 let result = if self.condition == "true" {
58 Value::Bool(true)
59 } else if self.condition == "false" {
60 Value::Bool(false)
61 } else {
62 ctx.data.get(&self.condition).cloned().unwrap_or(Value::Bool(true))
64 };
65
66 debug!("RuleNode[{}]: Result = {:?}", self.id, result);
67 ctx.data.insert(format!("{}_result", self.id), result.clone());
68
69 Ok(result)
70 }
71}
72
73#[derive(Debug, Clone)]
78pub struct DBNode {
79 pub id: String,
80 pub query: String,
81}
82
83impl DBNode {
84 pub fn new(id: impl Into<String>, query: impl Into<String>) -> Self {
85 Self {
86 id: id.into(),
87 query: query.into(),
88 }
89 }
90}
91
92#[async_trait]
93impl Node for DBNode {
94 fn id(&self) -> &str {
95 &self.id
96 }
97
98 fn node_type(&self) -> NodeType {
99 NodeType::DBNode
100 }
101
102 async fn run(&self, ctx: &mut Context) -> RuleResult {
103 info!("DBNode[{}]: Executing query '{}'", self.id, self.query);
104
105 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
107
108 let mock_result = serde_json::json!({
110 "query": self.query,
111 "rows": [
112 {"id": 1, "name": "Alice", "active": true},
113 {"id": 2, "name": "Bob", "active": false}
114 ],
115 "count": 2
116 });
117
118 debug!("DBNode[{}]: Query result = {:?}", self.id, mock_result);
119 ctx.data.insert(format!("{}_result", self.id), mock_result.clone());
120
121 Ok(mock_result)
122 }
123}
124
125#[derive(Debug, Clone)]
130pub struct AINode {
131 pub id: String,
132 pub prompt: String,
133}
134
135impl AINode {
136 pub fn new(id: impl Into<String>, prompt: impl Into<String>) -> Self {
137 Self {
138 id: id.into(),
139 prompt: prompt.into(),
140 }
141 }
142}
143
144#[async_trait]
145impl Node for AINode {
146 fn id(&self) -> &str {
147 &self.id
148 }
149
150 fn node_type(&self) -> NodeType {
151 NodeType::AINode
152 }
153
154 async fn run(&self, ctx: &mut Context) -> RuleResult {
155 info!("AINode[{}]: Processing prompt '{}'", self.id, self.prompt);
156
157 tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
159
160 let context_summary: Vec<String> = ctx.data.keys().cloned().collect();
162 let mock_response = serde_json::json!({
163 "prompt": self.prompt,
164 "response": format!("AI processed: {} with context keys: {:?}", self.prompt, context_summary),
165 "confidence": 0.95,
166 "model": "mock-gpt-4"
167 });
168
169 debug!("AINode[{}]: AI response = {:?}", self.id, mock_response);
170 ctx.data.insert(format!("{}_result", self.id), mock_response.clone());
171
172 Ok(mock_response)
173 }
174}