use rust_rule_engine::engine::engine::RustRuleEngine;
use rust_rule_engine::engine::plugin::{PluginHealth, PluginMetadata, PluginState, RulePlugin};
use rust_rule_engine::errors::Result;
use rust_rule_engine::types::Value;
#[allow(dead_code)]
pub struct DatabasePlugin {
metadata: PluginMetadata,
}
impl DatabasePlugin {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
metadata: PluginMetadata {
name: "database".to_string(),
version: "1.0.0".to_string(),
description: "Database operations for SQL and NoSQL databases".to_string(),
author: "Rust Rule Engine Team".to_string(),
state: PluginState::Loaded,
health: PluginHealth::Healthy,
actions: vec![
"ExecuteSQL".to_string(),
"InsertRecord".to_string(),
"UpdateRecord".to_string(),
"DeleteRecord".to_string(),
"CreateIndex".to_string(),
"BackupDatabase".to_string(),
"MongoFind".to_string(),
"RedisSet".to_string(),
"RedisGet".to_string(),
],
functions: vec![
"sqlQuery".to_string(),
"countRows".to_string(),
"getLastInsertId".to_string(),
"formatQuery".to_string(),
"sanitizeInput".to_string(),
"buildWhereClause".to_string(),
"aggregateData".to_string(),
],
dependencies: vec![
"sqlx".to_string(),
"mongodb".to_string(),
"redis".to_string(),
"serde_json".to_string(),
],
},
}
}
}
impl RulePlugin for DatabasePlugin {
fn get_metadata(&self) -> &PluginMetadata {
&self.metadata
}
fn register_actions(&self, engine: &mut RustRuleEngine) -> Result<()> {
engine.register_action_handler("ExecuteSQL", |params, facts| {
let query = params.get("0").map(|v| v.to_string()).unwrap_or_default();
let result_key = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("sql_result".to_string());
println!("💾 EXECUTING SQL:");
println!(" Query: {}", query);
if query.to_lowercase().contains("select") {
println!(" ✅ Query executed - 3 rows returned");
facts.add_value(&result_key, Value::String("3 rows".to_string()))?;
facts.add_value("rows_affected", Value::Number(3.0))?;
} else if query.to_lowercase().contains("insert") {
println!(" ✅ Insert successful - 1 row inserted");
facts.add_value(&result_key, Value::String("insert_success".to_string()))?;
facts.add_value("last_insert_id", Value::Number(456.0))?;
} else if query.to_lowercase().contains("update") {
println!(" ✅ Update successful - 2 rows modified");
facts.add_value(&result_key, Value::String("update_success".to_string()))?;
facts.add_value("rows_affected", Value::Number(2.0))?;
} else {
println!(" ✅ Query executed successfully");
facts.add_value(&result_key, Value::String("success".to_string()))?;
}
Ok(())
});
engine.register_action_handler("InsertRecord", |params, facts| {
let table = params
.get("0")
.map(|v| v.to_string())
.unwrap_or("table".to_string());
let data = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("{}".to_string());
println!("📝 INSERT RECORD:");
println!(" Table: {}", table);
println!(" Data: {}", data);
println!(" ✅ Record inserted with ID: 789");
facts.add_value("last_insert_id", Value::Number(789.0))?;
facts.add_value("insert_success", Value::Boolean(true))?;
Ok(())
});
engine.register_action_handler("MongoFind", |params, facts| {
let collection = params
.get("0")
.map(|v| v.to_string())
.unwrap_or("users".to_string());
let filter = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("{}".to_string());
println!("🍃 MONGODB FIND:");
println!(" Collection: {}", collection);
println!(" Filter: {}", filter);
println!(" ✅ Found 5 documents");
facts.add_value(
"mongo_results",
Value::String("[{\"_id\": 1, \"name\": \"John\"}]".to_string()),
)?;
facts.add_value("documents_found", Value::Number(5.0))?;
Ok(())
});
engine.register_action_handler("RedisSet", |params, _facts| {
let key = params
.get("0")
.map(|v| v.to_string())
.unwrap_or("key".to_string());
let value = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("value".to_string());
let ttl = params
.get("2")
.map(|v| v.to_string())
.unwrap_or("3600".to_string());
println!("🔴 REDIS SET:");
println!(" Key: {}", key);
println!(" Value: {}", value);
println!(" TTL: {} seconds", ttl);
println!(" ✅ Key cached successfully");
Ok(())
});
engine.register_action_handler("RedisGet", |params, facts| {
let key = params
.get("0")
.map(|v| v.to_string())
.unwrap_or("key".to_string());
let result_key = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("redis_value".to_string());
println!("🔴 REDIS GET:");
println!(" Key: {}", key);
if key.contains("user") {
println!(" ✅ Cache HIT - User data found");
facts.add_value(
&result_key,
Value::String("{\"id\": 123, \"name\": \"Cached User\"}".to_string()),
)?;
facts.add_value("cache_hit", Value::Boolean(true))?;
} else {
println!(" ❌ Cache MISS - Key not found");
facts.add_value("cache_hit", Value::Boolean(false))?;
}
Ok(())
});
engine.register_action_handler("BackupDatabase", |params, facts| {
let database = params
.get("0")
.map(|v| v.to_string())
.unwrap_or("main_db".to_string());
let backup_path = params
.get("1")
.map(|v| v.to_string())
.unwrap_or("/backups/".to_string());
println!("💿 DATABASE BACKUP:");
println!(" Database: {}", database);
println!(" Backup Path: {}", backup_path);
println!(" 📊 Backing up 150,000 records...");
println!(" ✅ Backup completed - backup_20241016_143022.sql");
facts.add_value(
"backup_file",
Value::String("backup_20241016_143022.sql".to_string()),
)?;
facts.add_value("backup_success", Value::Boolean(true))?;
Ok(())
});
Ok(())
}
fn register_functions(&self, engine: &mut RustRuleEngine) -> Result<()> {
engine.register_function("sqlQuery", |args, _facts| {
let table = args
.first()
.map(|v| v.to_string())
.unwrap_or("users".to_string());
let columns = args
.get(1)
.map(|v| v.to_string())
.unwrap_or("*".to_string());
let condition = args
.get(2)
.map(|v| v.to_string())
.unwrap_or("1=1".to_string());
let query = format!("SELECT {} FROM {} WHERE {}", columns, table, condition);
println!("🔧 Generated SQL: {}", query);
Ok(Value::String(query))
});
engine.register_function("countRows", |args, _facts| {
let table = args
.first()
.map(|v| v.to_string())
.unwrap_or("users".to_string());
println!("🔢 Counting rows in table: {}", table);
let count = match table.as_str() {
"users" => 1250.0,
"orders" => 8943.0,
"products" => 567.0,
_ => 100.0,
};
Ok(Value::Number(count))
});
engine.register_function("sanitizeInput", |args, _facts| {
let input = args.first().map(|v| v.to_string()).unwrap_or_default();
let sanitized = input.replace("'", "''").replace("--", "").replace(";", "");
println!("🛡️ Sanitized input: {} -> {}", input, sanitized);
Ok(Value::String(sanitized))
});
engine.register_function("buildWhereClause", |args, _facts| {
let field = args
.first()
.map(|v| v.to_string())
.unwrap_or("id".to_string());
let operator = args
.get(1)
.map(|v| v.to_string())
.unwrap_or("=".to_string());
let value = args
.get(2)
.map(|v| v.to_string())
.unwrap_or("1".to_string());
let clause = if value.parse::<f64>().is_ok() {
format!("{} {} {}", field, operator, value)
} else {
format!("{} {} '{}'", field, operator, value)
};
println!("🔧 Built WHERE clause: {}", clause);
Ok(Value::String(clause))
});
engine.register_function("aggregateData", |args, _facts| {
let function = args
.first()
.map(|v| v.to_string())
.unwrap_or("COUNT".to_string());
let column = args
.get(1)
.map(|v| v.to_string())
.unwrap_or("*".to_string());
let table = args
.get(2)
.map(|v| v.to_string())
.unwrap_or("data".to_string());
println!("📊 Aggregating: {} {} from {}", function, column, table);
let result = match function.to_uppercase().as_str() {
"COUNT" => 1547.0,
"SUM" => 98765.43,
"AVG" => 423.21,
"MAX" => 999.99,
"MIN" => 1.0,
_ => 0.0,
};
Ok(Value::Number(result))
});
Ok(())
}
fn unload(&mut self) -> Result<()> {
self.metadata.state = PluginState::Unloaded;
println!("💾 Database Plugin unloaded");
Ok(())
}
fn health_check(&mut self) -> PluginHealth {
println!("🏥 Database health check: All connections healthy");
PluginHealth::Healthy
}
}
#[cfg(test)]
mod tests {
use super::*;
use rust_rule_engine::engine::knowledge_base::KnowledgeBase;
use rust_rule_engine::Facts;
#[test]
fn test_database_plugin() {
let kb = KnowledgeBase::new("DatabaseTest");
let mut engine = RustRuleEngine::new(kb);
let facts = Facts::new();
let plugin = DatabasePlugin::new();
assert!(plugin.register_actions(&mut engine).is_ok());
assert!(plugin.register_functions(&mut engine).is_ok());
assert!(engine.has_function("sqlQuery"));
assert!(engine.has_function("countRows"));
assert!(engine.has_function("aggregateData"));
assert!(engine.has_action_handler("ExecuteSQL"));
assert!(engine.has_action_handler("MongoFind"));
assert!(engine.has_action_handler("RedisSet"));
}
}