...
This commit is contained in:
377
herodb_old/src/rhaiengine/engine.rs
Normal file
377
herodb_old/src/rhaiengine/engine.rs
Normal file
@@ -0,0 +1,377 @@
|
||||
use rhai::{Engine, EvalAltResult, Dynamic, Map};
|
||||
use std::sync::Arc;
|
||||
use std::fs;
|
||||
use crate::core::{DB, SledDBResult};
|
||||
use crate::zaz::factory::create_zaz_db;
|
||||
use crate::zaz::models::{Company, User, Shareholder};
|
||||
|
||||
/// A wrapper around the Rhai Engine that provides additional functionality
|
||||
pub struct RhaiEngine {
|
||||
engine: Engine,
|
||||
}
|
||||
|
||||
impl RhaiEngine {
|
||||
/// Creates a new Rhai engine with all model functions registered
|
||||
pub fn new() -> Self {
|
||||
let mut engine = Engine::new();
|
||||
rhai_engine
|
||||
}
|
||||
|
||||
/// Get a reference to the underlying Rhai engine
|
||||
pub fn get_engine(&mut self) -> &mut Engine {
|
||||
&mut self.engine
|
||||
}
|
||||
|
||||
/// Register a named function with the engine
|
||||
///
|
||||
/// This allows adding wrapped functions to the engine in a generic way,
|
||||
/// so they can be called from Rhai scripts
|
||||
pub fn register_fn<F>(&mut self, name: &str, f: F) {
|
||||
|
||||
|
||||
//in script engine
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Run a Rhai script from a file
|
||||
///
|
||||
/// This method reads the specified script file and executes it
|
||||
/// using the current engine instance.
|
||||
pub fn run_script(&mut self, file_path: &str) -> Result<(), String> {
|
||||
// Read the script file content
|
||||
let script = match fs::read_to_string(file_path) {
|
||||
Ok(content) => content,
|
||||
Err(e) => return Err(format!("Failed to read script file: {}", e))
|
||||
};
|
||||
|
||||
// Execute the script
|
||||
match self.engine.eval::<()>(&script) {
|
||||
Ok(_) => {
|
||||
println!("Rhai script executed successfully: {}", file_path);
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => {
|
||||
Err(format!("Rhai script execution failed: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a Rhai script from a text string
|
||||
///
|
||||
/// This method executes the provided script text using the current engine instance.
|
||||
pub fn run(&mut self, script_text: &str) -> Result<(), String> {
|
||||
// Execute the script
|
||||
match self.engine.eval::<()>(script_text) {
|
||||
Ok(_) => {
|
||||
println!("Rhai script text executed successfully");
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => {
|
||||
Err(format!("Rhai script execution failed: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new Rhai engine with all model functions registered
|
||||
/// This function is maintained for backward compatibility
|
||||
pub fn new() -> Engine {
|
||||
let rhai_engine = RhaiEngine::new();
|
||||
rhai_engine.engine
|
||||
}
|
||||
|
||||
/// Register a named function with the engine
|
||||
/// This function is maintained for backward compatibility
|
||||
pub fn register_named_fn<F>(engine: &mut Engine, name: &str, f: F)
|
||||
where
|
||||
F: 'static + Fn(&mut Engine) -> Result<(), Box<EvalAltResult>>
|
||||
{
|
||||
match f(engine) {
|
||||
Ok(_) => println!("Function '{}' registered successfully", name),
|
||||
Err(e) => eprintln!("Failed to register function '{}': {}", name, e)
|
||||
}
|
||||
}
|
||||
|
||||
/// Run a Rhai script from a file
|
||||
/// This function is maintained for backward compatibility
|
||||
pub fn run_script(file_path: &str) -> Result<(), String> {
|
||||
let mut rhai_engine = RhaiEngine::new();
|
||||
rhai_engine.run_script(file_path)
|
||||
}
|
||||
|
||||
/// Run a Rhai script from a text string
|
||||
/// This function is maintained for backward compatibility
|
||||
pub fn run(script_text: &str) -> Result<(), String> {
|
||||
let mut rhai_engine = RhaiEngine::new();
|
||||
rhai_engine.run(script_text)
|
||||
}
|
||||
|
||||
/// Utility functions to safely convert between Rhai Dynamic types and Rust types
|
||||
impl RhaiEngine {
|
||||
/// Helper function to convert a value to a Rhai Dynamic type with proper error handling
|
||||
pub fn to_dynamic<T: Clone + Into<Dynamic>>(&self, value: T) -> Dynamic {
|
||||
value.into()
|
||||
}
|
||||
|
||||
/// Helper function to safely get a property from a map with proper error handling
|
||||
pub fn get_property<T: Clone + 'static>(&self, map: &Map, key: &str) -> Result<T, String>
|
||||
where Dynamic: TryInto<T> {
|
||||
match map.get(key) {
|
||||
Some(value) => {
|
||||
match value.clone().try_into() {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(format!("Property '{}' has wrong type", key))
|
||||
}
|
||||
},
|
||||
None => Err(format!("Property '{}' not found", key))
|
||||
}
|
||||
}
|
||||
|
||||
/// Register CRUD operations for Company
|
||||
pub fn register_company_crud(&mut self) {
|
||||
// Create company from a map of properties
|
||||
self.engine.register_result_fn("create_company_from_map",
|
||||
|map: Map| -> Result<Company, Box<EvalAltResult>> {
|
||||
// Extract required fields with proper error handling
|
||||
let name = match map.get("name") {
|
||||
Some(val) => match val.clone().try_into::<String>() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("'name' must be a string".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'name'".into())
|
||||
};
|
||||
|
||||
let reg_number = match map.get("registration_number") {
|
||||
Some(val) => match val.clone().try_into::<String>() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("'registration_number' must be a string".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'registration_number'".into())
|
||||
};
|
||||
|
||||
// Extract other fields (example with default values)
|
||||
let id = match map.get("id") {
|
||||
Some(val) => match val.clone().try_into::<i64>() {
|
||||
Ok(id) => id as u32,
|
||||
Err(_) => return Err("'id' must be an integer".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'id'".into())
|
||||
};
|
||||
|
||||
// Here you would call your actual company creation logic
|
||||
// This is just a stub that would be replaced with actual implementation
|
||||
Err("Not fully implemented: would connect to database here".into())
|
||||
}
|
||||
);
|
||||
|
||||
// Read company by ID
|
||||
self.engine.register_result_fn("get_company_by_id",
|
||||
|id: i64| -> Result<Company, Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid company ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Here you would query the database for the company
|
||||
// This is just a stub that would be replaced with actual implementation
|
||||
Err(format!("Company with ID {} not found", id).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Update company
|
||||
self.engine.register_result_fn("update_company",
|
||||
|company: Company| -> Result<(), Box<EvalAltResult>> {
|
||||
// Here you would update the company in the database
|
||||
// This is just a stub that would be replaced with actual implementation
|
||||
Err(format!("Failed to update company: {}", company.name).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Delete company
|
||||
self.engine.register_result_fn("delete_company",
|
||||
|id: i64| -> Result<(), Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid company ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Here you would delete the company from the database
|
||||
// This is just a stub that would be replaced with actual implementation
|
||||
Err(format!("Failed to delete company with ID {}", id).into())
|
||||
}
|
||||
);
|
||||
|
||||
// List companies with filtering capabilities
|
||||
self.engine.register_result_fn("list_companies",
|
||||
|filter: Map| -> Result<Vec<Company>, Box<EvalAltResult>> {
|
||||
// Here you would query the database with the filter
|
||||
// This is just a stub that would be replaced with actual implementation
|
||||
Err("No companies found matching filter".into())
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Register CRUD operations for User
|
||||
pub fn register_user_crud(&mut self) {
|
||||
// Create user from a map of properties
|
||||
self.engine.register_result_fn("create_user_from_map",
|
||||
|map: Map| -> Result<User, Box<EvalAltResult>> {
|
||||
// Extract required fields with proper error handling
|
||||
let name = match map.get("name") {
|
||||
Some(val) => match val.clone().try_into::<String>() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("'name' must be a string".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'name'".into())
|
||||
};
|
||||
|
||||
let email = match map.get("email") {
|
||||
Some(val) => match val.clone().try_into::<String>() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("'email' must be a string".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'email'".into())
|
||||
};
|
||||
|
||||
// Extract other fields
|
||||
let id = match map.get("id") {
|
||||
Some(val) => match val.clone().try_into::<i64>() {
|
||||
Ok(id) => id as u32,
|
||||
Err(_) => return Err("'id' must be an integer".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'id'".into())
|
||||
};
|
||||
|
||||
// This is a stub that would be replaced with actual implementation
|
||||
Err("Not fully implemented: would create user in database".into())
|
||||
}
|
||||
);
|
||||
|
||||
// Read user by ID
|
||||
self.engine.register_result_fn("get_user_by_id",
|
||||
|id: i64| -> Result<User, Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid user ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Implementation would query database
|
||||
Err(format!("User with ID {} not found", id).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Update user
|
||||
self.engine.register_result_fn("update_user",
|
||||
|user: User| -> Result<(), Box<EvalAltResult>> {
|
||||
// Implementation would update the user in the database
|
||||
Err(format!("Failed to update user: {}", user.name).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Delete user
|
||||
self.engine.register_result_fn("delete_user",
|
||||
|id: i64| -> Result<(), Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid user ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Implementation would delete from database
|
||||
Err(format!("Failed to delete user with ID {}", id).into())
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Register CRUD operations for Shareholder
|
||||
pub fn register_shareholder_crud(&mut self) {
|
||||
// Create shareholder from a map of properties
|
||||
self.engine.register_result_fn("create_shareholder_from_map",
|
||||
|map: Map| -> Result<Shareholder, Box<EvalAltResult>> {
|
||||
// Extract required fields with proper error handling
|
||||
let name = match map.get("name") {
|
||||
Some(val) => match val.clone().try_into::<String>() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("'name' must be a string".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'name'".into())
|
||||
};
|
||||
|
||||
let company_id = match map.get("company_id") {
|
||||
Some(val) => match val.clone().try_into::<i64>() {
|
||||
Ok(id) => id as u32,
|
||||
Err(_) => return Err("'company_id' must be an integer".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'company_id'".into())
|
||||
};
|
||||
|
||||
let shares = match map.get("shares") {
|
||||
Some(val) => match val.clone().try_into::<i64>() {
|
||||
Ok(num) => num,
|
||||
Err(_) => return Err("'shares' must be an integer".into())
|
||||
},
|
||||
None => return Err("Missing required field: 'shares'".into())
|
||||
};
|
||||
|
||||
// This is a stub that would be replaced with actual implementation
|
||||
Err("Not fully implemented: would create shareholder in database".into())
|
||||
}
|
||||
);
|
||||
|
||||
// Read shareholder by ID
|
||||
self.engine.register_result_fn("get_shareholder_by_id",
|
||||
|id: i64| -> Result<Shareholder, Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid shareholder ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Implementation would query database
|
||||
Err(format!("Shareholder with ID {} not found", id).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Update shareholder
|
||||
self.engine.register_result_fn("update_shareholder",
|
||||
|shareholder: Shareholder| -> Result<(), Box<EvalAltResult>> {
|
||||
// Implementation would update the shareholder in the database
|
||||
Err(format!("Failed to update shareholder ID: {}", shareholder.id).into())
|
||||
}
|
||||
);
|
||||
|
||||
// Delete shareholder
|
||||
self.engine.register_result_fn("delete_shareholder",
|
||||
|id: i64| -> Result<(), Box<EvalAltResult>> {
|
||||
if id <= 0 {
|
||||
return Err(format!("Invalid shareholder ID: {}", id).into());
|
||||
}
|
||||
|
||||
// Implementation would delete from database
|
||||
Err(format!("Failed to delete shareholder with ID {}", id).into())
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper function to safely convert a map to a strongly-typed object
|
||||
pub fn map_to_object<T>(&self, map: &Map, converter: fn(&Map) -> Result<T, String>) -> Result<T, String> {
|
||||
converter(map)
|
||||
}
|
||||
|
||||
/// Helper function to handle Dynamic types safely
|
||||
pub fn get_dynamic_value(&self, dynamic: &Dynamic, key: &str) -> Result<Dynamic, String> {
|
||||
if let Some(map) = dynamic.try_cast::<Map>() {
|
||||
match map.get(key) {
|
||||
Some(value) => Ok(value.clone()),
|
||||
None => Err(format!("Key '{}' not found in map", key))
|
||||
}
|
||||
} else {
|
||||
Err("Dynamic value is not a map".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to extract a value of a specific type from a Dynamic value
|
||||
pub fn extract_value<T: Clone + 'static>(&self, dynamic: &Dynamic, key: &str) -> Result<T, String>
|
||||
where Dynamic: TryInto<T> {
|
||||
let value = self.get_dynamic_value(dynamic, key)?;
|
||||
match value.clone().try_into() {
|
||||
Ok(result) => Ok(result),
|
||||
Err(_) => Err(format!("Value for key '{}' has wrong type", key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
7
herodb_old/src/rhaiengine/mod.rs
Normal file
7
herodb_old/src/rhaiengine/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Rhai Engine module for scripting support
|
||||
//!
|
||||
//! This module provides integration with the Rhai scripting language.
|
||||
|
||||
// Re-export the engine module
|
||||
pub mod engine;
|
||||
pub use engine::*;
|
Reference in New Issue
Block a user