This commit is contained in:
2025-04-22 12:53:17 +04:00
parent cad285fd59
commit 1708e6dd06
116 changed files with 1919 additions and 81 deletions

View 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))
}
}
}

View 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::*;